Index: 3rdParty_sources/undertow/io/undertow/UndertowOptions.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/Attic/UndertowOptions.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/UndertowOptions.java 25 Nov 2014 10:47:01 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/UndertowOptions.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -32,7 +32,7 @@ /** * The default size we allow for the HTTP header. */ - public static final int DEFAULT_MAX_HEADER_SIZE = 50 * 1024; + public static final int DEFAULT_MAX_HEADER_SIZE = 1024 * 1024; /** * The default maximum size of the HTTP entity body. @@ -173,6 +173,20 @@ */ public static final Option ENABLE_SPDY = Option.simple(UndertowOptions.class, "ENABLE_SPDY", Boolean.class); + /** + * If unknown protocols should be allowed. The known protocols are: + * + * HTTP/0.9 + * HTTP/1.0 + * HTTP/1.1 + * HTTP/2.0 + * + * If this is false then requests that specify any other protocol will be rejected with a 400 + * + * Defaults to false + */ + public static final Option ALLOW_UNKNOWN_PROTOCOLS = Option.simple(UndertowOptions.class, "ALLOW_UNKNOWN_PROTOCOLS", Boolean.class); + private UndertowOptions() { } Index: 3rdParty_sources/undertow/io/undertow/channels/DetachableStreamSinkChannel.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/channels/Attic/DetachableStreamSinkChannel.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/channels/DetachableStreamSinkChannel.java 25 Nov 2014 10:47:01 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/channels/DetachableStreamSinkChannel.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -18,6 +18,7 @@ package io.undertow.channels; +import io.undertow.UndertowLogger; import io.undertow.UndertowMessages; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; @@ -140,9 +141,9 @@ writeSetter = new ChannelListener.SimpleSetter<>(); if (!isFinished()) { if(delegate instanceof ConduitStreamSinkChannel) { - ((ConduitStreamSinkChannel) delegate).setWriteListener(ChannelListeners.delegatingChannelListener(this, writeSetter)); + ((ConduitStreamSinkChannel) delegate).setWriteListener(new SetterDelegatingListener((ChannelListener.SimpleSetter)writeSetter, this)); } else { - delegate.getWriteSetter().set(ChannelListeners.delegatingChannelListener(this, writeSetter)); + delegate.getWriteSetter().set(new SetterDelegatingListener((ChannelListener.SimpleSetter)writeSetter, this)); } } } @@ -267,4 +268,30 @@ delegate.suspendWrites(); } } + + private static class SetterDelegatingListener implements ChannelListener { + + private final SimpleSetter setter; + private final StreamSinkChannel channel; + + public SetterDelegatingListener(final SimpleSetter setter, final StreamSinkChannel channel) { + this.setter = setter; + this.channel = channel; + } + + public void handleEvent(final StreamSinkChannel channel) { + ChannelListener channelListener = setter.get(); + if(channelListener != null) { + ChannelListeners.invokeChannelListener(this.channel, channelListener); + } else { + UndertowLogger.REQUEST_LOGGER.debugf("suspending writes on %s to prevent listener runaway", channel); + channel.suspendWrites(); + } + } + + public String toString() { + return "Setter delegating channel listener -> " + setter; + } + } + } Index: 3rdParty_sources/undertow/io/undertow/channels/DetachableStreamSourceChannel.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/channels/Attic/DetachableStreamSourceChannel.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/channels/DetachableStreamSourceChannel.java 25 Nov 2014 10:47:01 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/channels/DetachableStreamSourceChannel.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -22,6 +22,8 @@ import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; + +import io.undertow.UndertowLogger; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.Option; @@ -124,9 +126,9 @@ readSetter = new ChannelListener.SimpleSetter<>(); if (!isFinished()) { if(delegate instanceof ConduitStreamSourceChannel) { - ((ConduitStreamSourceChannel)delegate).setReadListener(ChannelListeners.delegatingChannelListener(this, readSetter)); + ((ConduitStreamSourceChannel)delegate).setReadListener(new SetterDelegatingListener((ChannelListener.SimpleSetter)readSetter, this)); } else { - delegate.getReadSetter().set(ChannelListeners.delegatingChannelListener(this, readSetter)); + delegate.getReadSetter().set(new SetterDelegatingListener((ChannelListener.SimpleSetter)readSetter, this)); } } } @@ -211,4 +213,30 @@ public XnioIoThread getIoThread() { return delegate.getIoThread(); } + + + private static class SetterDelegatingListener implements ChannelListener { + + private final SimpleSetter setter; + private final StreamSourceChannel channel; + + public SetterDelegatingListener(final SimpleSetter setter, final StreamSourceChannel channel) { + this.setter = setter; + this.channel = channel; + } + + public void handleEvent(final StreamSourceChannel channel) { + ChannelListener channelListener = setter.get(); + if(channelListener != null) { + ChannelListeners.invokeChannelListener(this.channel, channelListener); + } else { + UndertowLogger.REQUEST_LOGGER.debugf("suspending reads on %s to prevent listener runaway", channel); + channel.suspendReads(); + } + } + + public String toString() { + return "Setter delegating channel listener -> " + setter; + } + } } Index: 3rdParty_sources/undertow/io/undertow/channels/ReadTimeoutStreamSourceChannel.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/channels/Attic/ReadTimeoutStreamSourceChannel.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/channels/ReadTimeoutStreamSourceChannel.java 25 Nov 2014 10:47:01 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/channels/ReadTimeoutStreamSourceChannel.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -59,7 +59,6 @@ /** * @param delegate The underlying channel - * @param readTimeout The read timeout, in milliseconds */ public ReadTimeoutStreamSourceChannel(final StreamSourceChannel delegate) { super(delegate); @@ -76,9 +75,14 @@ } private void handleReadTimeout(final long ret) { - if (readTimeout > 0) { + if(ret == -1) { + if(handle != null) { + handle.remove(); + handle = null; + } + } else if (readTimeout > 0) { if (ret == 0 && handle == null) { - handle = delegate.getReadThread().executeAfter(timeoutCommand, readTimeout, TimeUnit.MILLISECONDS); + handle = delegate.getIoThread().executeAfter(timeoutCommand, readTimeout, TimeUnit.MILLISECONDS); } else if (ret > 0 && handle != null) { handle.remove(); } @@ -134,4 +138,22 @@ } return ret; } + + @Override + public void shutdownReads() throws IOException { + super.shutdownReads(); + if(handle != null) { + handle.remove(); + handle = null; + } + } + + @Override + public void close() throws IOException { + super.close(); + if(handle != null) { + handle.remove(); + handle = null; + } + } } Index: 3rdParty_sources/undertow/io/undertow/channels/WriteTimeoutStreamSinkChannel.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/channels/Attic/WriteTimeoutStreamSinkChannel.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/channels/WriteTimeoutStreamSinkChannel.java 25 Nov 2014 10:47:01 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/channels/WriteTimeoutStreamSinkChannel.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -24,6 +24,7 @@ import java.util.concurrent.TimeUnit; import io.undertow.UndertowLogger; +import org.xnio.Buffers; import org.xnio.ChannelListeners; import org.xnio.IoUtils; import org.xnio.Option; @@ -103,20 +104,38 @@ public int writeFinal(ByteBuffer src) throws IOException { int ret = delegate.writeFinal(src); handleWriteTimeout(ret); + if(!src.hasRemaining()) { + if(handle != null) { + handle.remove(); + handle = null; + } + } return ret; } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { long ret = delegate.writeFinal(srcs, offset, length); handleWriteTimeout(ret); + if(!Buffers.hasRemaining(srcs, offset, length)) { + if(handle != null) { + handle.remove(); + handle = null; + } + } return ret; } @Override public long writeFinal(ByteBuffer[] srcs) throws IOException { long ret = delegate.writeFinal(srcs); handleWriteTimeout(ret); + if(!Buffers.hasRemaining(srcs)) { + if(handle != null) { + handle.remove(); + handle = null; + } + } return ret; } @@ -148,4 +167,22 @@ } return ret; } + + @Override + public void shutdownWrites() throws IOException { + super.shutdownWrites(); + if(handle != null) { + handle.remove(); + handle = null; + } + } + + @Override + public void close() throws IOException { + super.close(); + if(handle != null) { + handle.remove(); + handle = null; + } + } } Index: 3rdParty_sources/undertow/io/undertow/client/http/HttpClientConnection.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/client/http/Attic/HttpClientConnection.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/client/http/HttpClientConnection.java 25 Nov 2014 10:46:55 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/client/http/HttpClientConnection.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -34,6 +34,7 @@ import io.undertow.util.HttpString; import io.undertow.util.Methods; import io.undertow.util.Protocols; +import io.undertow.util.StatusCodes; import org.xnio.ChannelExceptionHandler; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; @@ -434,7 +435,7 @@ } } - if (builder.getStatusCode() == 100) { + if (builder.getStatusCode() == StatusCodes.CONTINUE) { pendingResponse = new HttpResponseBuilder(); currentRequest.setContinueResponse(response); } else { Index: 3rdParty_sources/undertow/io/undertow/conduits/AbstractFixedLengthStreamSinkConduit.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/conduits/Attic/AbstractFixedLengthStreamSinkConduit.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/conduits/AbstractFixedLengthStreamSinkConduit.java 25 Nov 2014 10:46:51 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/conduits/AbstractFixedLengthStreamSinkConduit.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -18,9 +18,9 @@ package io.undertow.conduits; +import io.undertow.UndertowLogger; import org.xnio.Buffers; import org.xnio.channels.FixedLengthOverflowException; -import org.xnio.channels.FixedLengthUnderflowException; import org.xnio.channels.StreamSourceChannel; import org.xnio.conduits.AbstractStreamSinkConduit; import org.xnio.conduits.Conduits; @@ -251,17 +251,26 @@ public void terminateWrites() throws IOException { final long val = enterShutdown(); if (anyAreSet(val, MASK_COUNT) && !broken) { - try { - throw new FixedLengthUnderflowException((val & MASK_COUNT) + " bytes remaining"); - } finally { - next.truncateWrites(); - } + UndertowLogger.REQUEST_IO_LOGGER.debugf("Fixed length stream closed with with %s bytes remaining", val & MASK_COUNT); + next.truncateWrites(); } else if (allAreSet(config, CONF_FLAG_PASS_CLOSE)) { next.terminateWrites(); } } + @Override + public void truncateWrites() throws IOException { + try { + if (!anyAreSet(state, FLAG_FINISHED_CALLED)) { + state |= FLAG_FINISHED_CALLED; + channelFinished(); + } + } finally { + super.truncateWrites(); + } + } + public void awaitWritable() throws IOException { next.awaitWritable(); } Index: 3rdParty_sources/undertow/io/undertow/conduits/ChunkedStreamSinkConduit.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/conduits/Attic/ChunkedStreamSinkConduit.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/conduits/ChunkedStreamSinkConduit.java 25 Nov 2014 10:46:51 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/conduits/ChunkedStreamSinkConduit.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -25,7 +25,7 @@ import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; -import io.undertow.UndertowMessages; +import io.undertow.UndertowLogger; import io.undertow.server.protocol.http.HttpAttachments; import io.undertow.util.Attachable; import io.undertow.util.AttachmentKey; @@ -196,10 +196,16 @@ @Override public void truncateWrites() throws IOException { - if(lastChunkBuffer != null) { - lastChunkBuffer.free(); + try { + if (lastChunkBuffer != null) { + lastChunkBuffer.free(); + } + if (allAreClear(state, FLAG_FINISHED)) { + invokeFinishListener(); + } + } finally { + super.truncateWrites(); } - super.truncateWrites(); } @Override @@ -291,7 +297,8 @@ return; } if (this.chunkleft != 0) { - throw UndertowMessages.MESSAGES.chunkedChannelClosedMidChunk(); + UndertowLogger.REQUEST_IO_LOGGER.debugf("Channel closed mid-chunk"); + next.truncateWrites(); } if (!anyAreSet(state, FLAG_FIRST_DATA_WRITTEN)) { //if no data was actually sent we just remove the transfer encoding header, and set content length 0 Index: 3rdParty_sources/undertow/io/undertow/conduits/ChunkedStreamSourceConduit.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/conduits/Attic/ChunkedStreamSourceConduit.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/conduits/ChunkedStreamSourceConduit.java 25 Nov 2014 10:46:51 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/conduits/ChunkedStreamSourceConduit.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -100,7 +100,12 @@ } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { - return target.transferFrom(new ConduitReadableByteChannel(this), position, count); + try { + return target.transferFrom(new ConduitReadableByteChannel(this), position, count); + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; + } } private void updateRemainingAllowed(final int written) throws IOException { @@ -127,7 +132,12 @@ } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { - return IoUtils.transfer(new ConduitReadableByteChannel(this), count, throughBuffer, target); + try { + return IoUtils.transfer(new ConduitReadableByteChannel(this), count, throughBuffer, target); + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; + } } public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { @@ -142,115 +152,126 @@ @Override public void terminateReads() throws IOException { if (!isFinished()) { + exchange.setPersistent(false); super.terminateReads(); throw UndertowMessages.MESSAGES.chunkedChannelClosedMidChunk(); } } public int read(final ByteBuffer dst) throws IOException { - long chunkRemaining = chunkReader.getChunkRemaining(); - //we have read the last chunk, we just return EOF - if (chunkRemaining == -1) { - return -1; - } - if (closed) { - throw new ClosedChannelException(); - } - Pooled pooled = bufferWrapper.allocate(); - ByteBuffer buf = pooled.getResource(); try { - int r = next.read(buf); - buf.flip(); - if (r == -1) { - //Channel is broken, not sure how best to report it + long chunkRemaining = chunkReader.getChunkRemaining(); + //we have read the last chunk, we just return EOF + if (chunkRemaining == -1) { + return -1; + } + if (closed) { throw new ClosedChannelException(); - } else if (r == 0) { - return 0; } - if (chunkRemaining == 0) { - chunkRemaining = chunkReader.readChunk(buf); - if (chunkRemaining <= 0) { - return (int) chunkRemaining; + Pooled pooled = bufferWrapper.allocate(); + ByteBuffer buf = pooled.getResource(); + boolean free = true; + try { + //we need to do our initial read into a + int r = next.read(buf); + buf.flip(); + if (r == -1) { + //Channel is broken, not sure how best to report it + throw new ClosedChannelException(); + } else if (r == 0) { + return 0; } - } + if (chunkRemaining == 0) { + chunkRemaining = chunkReader.readChunk(buf); + if (chunkRemaining <= 0) { + return (int) chunkRemaining; + } + } - final int originalLimit = dst.limit(); - try { - //now we may have some stuff in the raw buffer - //or the raw buffer may be exhausted, and we should read directly into the destination buffer - //from the next + final int originalLimit = dst.limit(); + try { + //now we may have some stuff in the raw buffer + //or the raw buffer may be exhausted, and we should read directly into the destination buffer + //from the next - int read = 0; - long chunkInBuffer = Math.min(buf.remaining(), chunkRemaining); - int remaining = dst.remaining(); - if (chunkInBuffer > remaining) { - //it won't fit - int orig = buf.limit(); - buf.limit(buf.position() + remaining); - dst.put(buf); - buf.limit(orig); - chunkRemaining -= remaining; - updateRemainingAllowed(remaining); - return remaining; - } else if (buf.hasRemaining()) { - int old = buf.limit(); - buf.limit((int) Math.min(old, buf.position() + chunkInBuffer)); - try { + int read = 0; + long chunkInBuffer = Math.min(buf.remaining(), chunkRemaining); + int remaining = dst.remaining(); + if (chunkInBuffer > remaining) { + //it won't fit + int orig = buf.limit(); + buf.limit(buf.position() + remaining); dst.put(buf); - } finally { - buf.limit(old); - } - read += chunkInBuffer; - chunkRemaining -= chunkInBuffer; - } - //there is still more to read - //we attempt to just read it directly into the destination buffer - //adjusting the limit as necessary to make sure we do not read too much - if (chunkRemaining > 0) { - int old = dst.limit(); - try { - if (chunkRemaining < dst.remaining()) { - dst.limit((int) (dst.position() + chunkRemaining)); + buf.limit(orig); + chunkRemaining -= remaining; + updateRemainingAllowed(remaining); + free = false; + return remaining; + } else if (buf.hasRemaining()) { + int old = buf.limit(); + buf.limit((int) Math.min(old, buf.position() + chunkInBuffer)); + try { + dst.put(buf); + } finally { + buf.limit(old); } - int c = 0; - do { - c = next.read(dst); - if (c > 0) { - read += c; - chunkRemaining -= c; + read += chunkInBuffer; + chunkRemaining -= chunkInBuffer; + } + //there is still more to read + //we attempt to just read it directly into the destination buffer + //adjusting the limit as necessary to make sure we do not read too much + if (chunkRemaining > 0) { + int old = dst.limit(); + try { + if (chunkRemaining < dst.remaining()) { + dst.limit((int) (dst.position() + chunkRemaining)); } - } while (c > 0 && chunkRemaining > 0); - if (c == -1) { - throw new ClosedChannelException(); + int c = 0; + do { + c = next.read(dst); + if (c > 0) { + read += c; + chunkRemaining -= c; + } + } while (c > 0 && chunkRemaining > 0); + if (c == -1) { + throw new ClosedChannelException(); + } + } finally { + dst.limit(old); } - } finally { - dst.limit(old); + } else { + free = false; } + updateRemainingAllowed(read); + return read; + + } finally { + //buffer will be freed if not needed in exitRead + dst.limit(originalLimit); } - updateRemainingAllowed(read); - return read; } finally { - //buffer will be freed if not needed in exitRead - dst.limit(originalLimit); + if (chunkRemaining >= 0) { + chunkReader.setChunkRemaining(chunkRemaining); + } + if (!free && buf.hasRemaining()) { + bufferWrapper.pushBack(pooled); + } else { + pooled.free(); + } } - - } finally { - if(chunkRemaining >= 0) { - chunkReader.setChunkRemaining(chunkRemaining); - } - if (buf.hasRemaining()) { - bufferWrapper.pushBack(pooled); - } else { - pooled.free(); - } + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; } } public boolean isFinished() { - return chunkReader.getChunkRemaining() == -1; + return closed || chunkReader.getChunkRemaining() == -1; } interface BufferWrapper { Index: 3rdParty_sources/undertow/io/undertow/conduits/DeflatingStreamSinkConduit.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/conduits/Attic/DeflatingStreamSinkConduit.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/conduits/DeflatingStreamSinkConduit.java 25 Nov 2014 10:46:51 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/conduits/DeflatingStreamSinkConduit.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -310,11 +310,7 @@ state |= WRITTEN_TRAILER; byte[] data = getTrailer(); if (data != null) { - if (data.length <= buffer.remaining()) { - buffer.put(data); - } else if (additionalBuffer == null) { - additionalBuffer = ByteBuffer.wrap(data); - } else { + if(additionalBuffer != null) { byte[] newData = new byte[additionalBuffer.remaining() + data.length]; int pos = 0; while (additionalBuffer.hasRemaining()) { @@ -324,6 +320,14 @@ newData[pos++] = aData; } this.additionalBuffer = ByteBuffer.wrap(newData); + } else if(anyAreSet(state, FLUSHING_BUFFER) && buffer.capacity() - buffer.remaining() >= data.length) { + buffer.compact(); + buffer.put(data); + buffer.flip(); + } else if (data.length <= buffer.remaining() && !anyAreSet(state, FLUSHING_BUFFER)) { + buffer.put(data); + } else { + additionalBuffer = ByteBuffer.wrap(data); } } } Index: 3rdParty_sources/undertow/io/undertow/conduits/FixedLengthStreamSourceConduit.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/conduits/Attic/FixedLengthStreamSourceConduit.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/conduits/FixedLengthStreamSourceConduit.java 25 Nov 2014 10:46:51 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/conduits/FixedLengthStreamSourceConduit.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -21,6 +21,7 @@ import io.undertow.UndertowMessages; import io.undertow.server.Connectors; import io.undertow.server.HttpServerExchange; +import org.xnio.IoUtils; import org.xnio.channels.StreamSinkChannel; import org.xnio.conduits.AbstractStreamSourceConduit; import org.xnio.conduits.StreamSourceConduit; @@ -122,6 +123,9 @@ long res = 0L; try { return res = next.transferTo(position, min(count, val & MASK_COUNT), target); + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; } finally { exitRead(res); } @@ -142,6 +146,9 @@ long res = 0L; try { return res = next.transferTo(min(count, val & MASK_COUNT), throughBuffer, target); + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; } finally { exitRead(res == -1L ? val & MASK_COUNT : res + throughBuffer.remaining()); } @@ -205,6 +212,9 @@ } // the total buffer space is less than the remaining count. return res = next.read(dsts, offset, length); + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; } finally { exitRead(res == -1L ? val & MASK_COUNT : res); } @@ -238,7 +248,10 @@ } else { return res = next.read(dst); } - } finally { + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; + } finally { exitRead(res == -1 ? remaining : (long) res); } } @@ -277,7 +290,12 @@ if (allAreSet(val, FLAG_CLOSED) || val == 0L) { return; } - next.awaitReadable(time, timeUnit); + try { + next.awaitReadable(time, timeUnit); + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; + } } /** Index: 3rdParty_sources/undertow/io/undertow/conduits/IdleTimeoutConduit.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/conduits/Attic/IdleTimeoutConduit.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/conduits/IdleTimeoutConduit.java 25 Nov 2014 10:46:51 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/conduits/IdleTimeoutConduit.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -18,6 +18,7 @@ package io.undertow.conduits; import io.undertow.UndertowLogger; +import org.xnio.Buffers; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; @@ -134,41 +135,77 @@ public int writeFinal(ByteBuffer src) throws IOException { handleIdleTimeout(); int w = sink.writeFinal(src); + if(source.isReadShutdown() && !src.hasRemaining()) { + if(handle != null) { + handle.remove(); + handle = null; + } + } return w; } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { handleIdleTimeout(); long w = sink.writeFinal(srcs, offset, length); + if(source.isReadShutdown() && !Buffers.hasRemaining(srcs, offset, length)) { + if(handle != null) { + handle.remove(); + handle = null; + } + } return w; } @Override public long transferTo(long position, long count, FileChannel target) throws IOException { handleIdleTimeout(); long w = source.transferTo(position, count, target); + if(sink.isWriteShutdown() && w == -1) { + if(handle != null) { + handle.remove(); + handle = null; + } + } return w; } @Override public long transferTo(long count, ByteBuffer throughBuffer, StreamSinkChannel target) throws IOException { handleIdleTimeout(); long w = source.transferTo(count, throughBuffer, target); + if(sink.isWriteShutdown() && w == -1) { + if(handle != null) { + handle.remove(); + handle = null; + } + } return w; } @Override public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { handleIdleTimeout(); long r = source.read(dsts, offset, length); + if(sink.isWriteShutdown() && r == -1) { + if(handle != null) { + handle.remove(); + handle = null; + } + } return r; } @Override public int read(ByteBuffer dst) throws IOException { handleIdleTimeout(); int r = source.read(dst); + if(sink.isWriteShutdown() && r == -1) { + if(handle != null) { + handle.remove(); + handle = null; + } + } return r; } @@ -183,6 +220,7 @@ public long transferFrom(StreamSourceChannel source, long count, ByteBuffer throughBuffer) throws IOException { handleIdleTimeout(); long r = sink.transferFrom(source, count, throughBuffer); + return r; } @@ -194,6 +232,12 @@ @Override public void terminateReads() throws IOException { source.terminateReads(); + if(sink.isWriteShutdown()) { + if(handle != null) { + handle.remove(); + handle = null; + } + } } @Override @@ -253,6 +297,12 @@ @Override public void terminateWrites() throws IOException { sink.terminateWrites(); + if(source.isReadShutdown()) { + if(handle != null) { + handle.remove(); + handle = null; + } + } } @Override @@ -304,8 +354,15 @@ @Override public void truncateWrites() throws IOException { sink.truncateWrites(); + if(source.isReadShutdown()) { + if(handle != null) { + handle.remove(); + handle = null; + } + } } + @Override public boolean flush() throws IOException { return sink.flush(); Index: 3rdParty_sources/undertow/io/undertow/conduits/RateLimitingStreamSinkConduit.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/conduits/Attic/RateLimitingStreamSinkConduit.java,v diff -u -r1.1.2.1 -r1.1.2.2 --- 3rdParty_sources/undertow/io/undertow/conduits/RateLimitingStreamSinkConduit.java 25 Nov 2014 10:46:51 -0000 1.1.2.1 +++ 3rdParty_sources/undertow/io/undertow/conduits/RateLimitingStreamSinkConduit.java 27 Aug 2015 06:12:25 -0000 1.1.2.2 @@ -44,7 +44,7 @@ private final int bytes; private boolean writesResumed = false; - private long byteCount = 0; + private int byteCount = 0; private long startTime = 0; private long nextSendTime = 0; @@ -68,6 +68,7 @@ if (!canSend()) { return 0; } + int bytes = this.bytes - this.byteCount; int old = src.limit(); if (src.remaining() > bytes) { src.limit(src.position() + bytes); @@ -86,6 +87,7 @@ if (!canSend()) { return 0; } + int bytes = this.bytes - this.byteCount; long written = super.transferFrom(src, position, Math.min(count, bytes)); handleWritten(written); return written; @@ -96,6 +98,7 @@ if (!canSend()) { return 0; } + int bytes = this.bytes - this.byteCount; long written = super.transferFrom(source, Math.min(count, bytes), throughBuffer); handleWritten(written); return written; @@ -141,6 +144,7 @@ if (!canSend()) { return 0; } + int bytes = this.bytes - this.byteCount; int old = src.limit(); if (src.remaining() > bytes) { src.limit(src.position() + bytes); @@ -273,11 +277,10 @@ } } else { //we have gone over, we need to wait till we are allowed to send again - long units = ((byteCount - 1) / bytes) + 1; if (startTime == 0) { startTime = System.currentTimeMillis(); } - nextSendTime = startTime + (units * time); + nextSendTime = startTime + time; if (writesResumed) { handleWritesResumedWhenBlocked(); } Index: 3rdParty_sources/undertow/io/undertow/conduits/ReadTimeoutStreamSourceConduit.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/conduits/Attic/ReadTimeoutStreamSourceConduit.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/conduits/ReadTimeoutStreamSourceConduit.java 25 Nov 2014 10:46:51 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/conduits/ReadTimeoutStreamSourceConduit.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -29,6 +29,7 @@ import org.xnio.XnioExecutor; import org.xnio.channels.StreamSinkChannel; import org.xnio.conduits.AbstractStreamSourceConduit; +import org.xnio.conduits.ReadReadyHandler; import org.xnio.conduits.StreamSourceConduit; import java.io.IOException; @@ -80,12 +81,36 @@ super(delegate); this.connection = connection; this.openListener = openListener; + final ReadReadyHandler handler = new ReadReadyHandler.ChannelListenerHandler<>(connection.getSourceChannel()); + delegate.setReadReadyHandler(new ReadReadyHandler() { + @Override + public void readReady() { + handler.readReady(); + } + + @Override + public void forceTermination() { + cleanup(); + handler.forceTermination(); + } + + @Override + public void terminated() { + cleanup(); + handler.terminated(); + } + }); } private void handleReadTimeout(final long ret) throws IOException { if (!connection.isOpen()) { + cleanup(); return; } + if(ret == -1) { + cleanup(); + return; + } if (ret == 0 && handle != null) { return; } @@ -165,4 +190,17 @@ } return timeout; } + + @Override + public void terminateReads() throws IOException { + super.terminateReads(); + cleanup(); + } + + private void cleanup() { + if(handle != null) { + handle.remove(); + handle = null; + } + } } Index: 3rdParty_sources/undertow/io/undertow/conduits/WriteTimeoutStreamSinkConduit.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/conduits/Attic/WriteTimeoutStreamSinkConduit.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/conduits/WriteTimeoutStreamSinkConduit.java 25 Nov 2014 10:46:51 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/conduits/WriteTimeoutStreamSinkConduit.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -22,6 +22,7 @@ import io.undertow.UndertowOptions; import io.undertow.server.OpenListener; +import org.xnio.Buffers; import org.xnio.ChannelListeners; import org.xnio.IoUtils; import org.xnio.Options; @@ -124,13 +125,25 @@ public int writeFinal(ByteBuffer src) throws IOException { int ret = super.writeFinal(src); handleWriteTimeout(ret); + if(!src.hasRemaining()) { + if(handle != null) { + handle.remove(); + handle = null; + } + } return ret; } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { long ret = super.writeFinal(srcs, offset, length); handleWriteTimeout(ret); + if(!Buffers.hasRemaining(srcs)) { + if(handle != null) { + handle.remove(); + handle = null; + } + } return ret; } @@ -179,4 +192,22 @@ } return timeout; } + + @Override + public void terminateWrites() throws IOException { + super.terminateWrites(); + if(handle != null) { + handle.remove(); + handle = null; + } + } + + @Override + public void truncateWrites() throws IOException { + super.truncateWrites(); + if(handle != null) { + handle.remove(); + handle = null; + } + } } Index: 3rdParty_sources/undertow/io/undertow/io/AsyncSenderImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/io/Attic/AsyncSenderImpl.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/io/AsyncSenderImpl.java 25 Nov 2014 10:47:00 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/io/AsyncSenderImpl.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -25,6 +25,7 @@ import io.undertow.UndertowMessages; import io.undertow.server.HttpServerExchange; +import io.undertow.util.Headers; import org.xnio.Buffers; import org.xnio.ChannelExceptionHandler; import org.xnio.ChannelListener; @@ -48,27 +49,7 @@ private IoCallback callback; private boolean inCallback; - private final ChannelListener writeListener = new ChannelListener() { - @Override - public void handleEvent(final StreamSinkChannel streamSinkChannel) { - try { - long toWrite = Buffers.remaining(buffer); - long written = 0; - while (written < toWrite) { - long res = streamSinkChannel.write(buffer, 0, buffer.length); - written += res; - if (res == 0) { - return; - } - } - streamSinkChannel.suspendWrites(); - invokeOnComplete(); - } catch (IOException e) { - streamSinkChannel.suspendWrites(); - invokeOnException(callback, e); - } - } - }; + private ChannelListener writeListener; public class TransferTask implements Runnable, ChannelListener { public boolean run(boolean complete) { @@ -80,7 +61,7 @@ StreamSinkChannel dest = channel; if (dest == null) { if (callback == IoCallback.END_EXCHANGE) { - if (exchange.getResponseContentLength() == -1) { + if (exchange.getResponseContentLength() == -1 && !exchange.getResponseHeaders().contains(Headers.TRANSFER_ENCODING)) { exchange.setResponseContentLength(size); } } @@ -124,7 +105,7 @@ } } - private final TransferTask transferTask = new TransferTask(); + private TransferTask transferTask; public AsyncSenderImpl(final HttpServerExchange exchange) { @@ -143,7 +124,7 @@ StreamSinkChannel channel = this.channel; if (channel == null) { if (callback == IoCallback.END_EXCHANGE) { - if (exchange.getResponseContentLength() == -1) { + if (exchange.getResponseContentLength() == -1 && !exchange.getResponseHeaders().contains(Headers.TRANSFER_ENCODING)) { exchange.setResponseContentLength(buffer.remaining()); } } @@ -167,6 +148,10 @@ if (res == 0) { this.buffer = new ByteBuffer[]{buffer}; this.callback = callback; + + if(writeListener == null) { + initWriteListener(); + } channel.getWriteSetter().set(writeListener); channel.resumeWrites(); return; @@ -199,7 +184,7 @@ StreamSinkChannel channel = this.channel; if (channel == null) { if (callback == IoCallback.END_EXCHANGE) { - if (exchange.getResponseContentLength() == -1) { + if (exchange.getResponseContentLength() == -1 && !exchange.getResponseHeaders().contains(Headers.TRANSFER_ENCODING)) { exchange.setResponseContentLength(totalToWrite); } } @@ -219,6 +204,10 @@ if (res == 0) { this.buffer = buffer; this.callback = callback; + + if(writeListener == null) { + initWriteListener(); + } channel.getWriteSetter().set(writeListener); channel.resumeWrites(); return; @@ -246,7 +235,9 @@ if (inCallback) { return; } - + if(transferTask == null) { + transferTask = new TransferTask(); + } if (exchange.isInIoThread()) { exchange.dispatch(transferTask); return; @@ -310,7 +301,7 @@ try { StreamSinkChannel channel = this.channel; if (channel == null) { - if (exchange.getResponseContentLength() == -1) { + if (exchange.getResponseContentLength() == -1 && !exchange.getResponseHeaders().contains(Headers.TRANSFER_ENCODING)) { exchange.setResponseContentLength(0); } this.channel = channel = exchange.getResponseChannel(); @@ -393,6 +384,9 @@ long res = channel.write(buffer); written += res; if (res == 0) { + if(writeListener == null) { + initWriteListener(); + } channel.getWriteSetter().set(writeListener); channel.resumeWrites(); return; @@ -403,6 +397,9 @@ invokeOnException(callback, e); } } else if (this.fileChannel != null) { + if(transferTask == null) { + transferTask = new TransferTask(); + } if (!transferTask.run(false)) { return; } @@ -424,4 +421,28 @@ } callback.onException(exchange, this, e); } + + private void initWriteListener() { + writeListener = new ChannelListener() { + @Override + public void handleEvent(final StreamSinkChannel streamSinkChannel) { + try { + long toWrite = Buffers.remaining(buffer); + long written = 0; + while (written < toWrite) { + long res = streamSinkChannel.write(buffer, 0, buffer.length); + written += res; + if (res == 0) { + return; + } + } + streamSinkChannel.suspendWrites(); + invokeOnComplete(); + } catch (IOException e) { + streamSinkChannel.suspendWrites(); + invokeOnException(callback, e); + } + } + }; + } } Index: 3rdParty_sources/undertow/io/undertow/io/DefaultIoCallback.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/io/Attic/DefaultIoCallback.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/io/DefaultIoCallback.java 25 Nov 2014 10:47:00 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/io/DefaultIoCallback.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -32,24 +32,26 @@ */ public class DefaultIoCallback implements IoCallback { + private static final IoCallback CALLBACK = new IoCallback() { + @Override + public void onComplete(final HttpServerExchange exchange, final Sender sender) { + exchange.endExchange(); + } + + @Override + public void onException(final HttpServerExchange exchange, final Sender sender, final IOException exception) { + UndertowLogger.REQUEST_IO_LOGGER.ioException(exception); + exchange.endExchange(); + } + }; + protected DefaultIoCallback() { } @Override public void onComplete(final HttpServerExchange exchange, final Sender sender) { - sender.close(new IoCallback() { - @Override - public void onComplete(final HttpServerExchange exchange, final Sender sender) { - exchange.endExchange(); - } - - @Override - public void onException(final HttpServerExchange exchange, final Sender sender, final IOException exception) { - UndertowLogger.REQUEST_IO_LOGGER.ioException(exception); - exchange.endExchange(); - } - }); + sender.close(CALLBACK); } @Override Index: 3rdParty_sources/undertow/io/undertow/io/UndertowInputStream.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/io/Attic/UndertowInputStream.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/io/UndertowInputStream.java 25 Nov 2014 10:47:00 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/io/UndertowInputStream.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -151,18 +151,22 @@ if (anyAreSet(state, FLAG_CLOSED)) { return; } - while (allAreClear(state, FLAG_FINISHED)) { - readIntoBuffer(); + state |= FLAG_CLOSED; + try { + while (allAreClear(state, FLAG_FINISHED)) { + readIntoBuffer(); + if (pooled != null) { + pooled.free(); + pooled = null; + } + } + } finally { if (pooled != null) { pooled.free(); pooled = null; } + channel.shutdownReads(); + state |= FLAG_FINISHED; } - if (pooled != null) { - pooled.free(); - pooled = null; - } - channel.shutdownReads(); - state |= FLAG_FINISHED | FLAG_CLOSED; } } Index: 3rdParty_sources/undertow/io/undertow/predicate/PathPrefixPredicate.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/predicate/Attic/PathPrefixPredicate.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/predicate/PathPrefixPredicate.java 25 Nov 2014 10:46:53 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/predicate/PathPrefixPredicate.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -52,7 +52,9 @@ boolean matches = result.getValue() == Boolean.TRUE; if(matches) { Map context = value.getAttachment(PREDICATE_CONTEXT); - context.put("remaining", result.getRemaining()); + if(context != null) { + context.put("remaining", result.getRemaining()); + } } return matches; } Index: 3rdParty_sources/undertow/io/undertow/predicate/PathTemplatePredicate.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/predicate/Attic/PathTemplatePredicate.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/predicate/PathTemplatePredicate.java 25 Nov 2014 10:46:53 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/predicate/PathTemplatePredicate.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -44,7 +44,11 @@ @Override public boolean resolve(final HttpServerExchange exchange) { final Map params = new HashMap<>(); - boolean result = this.value.matches(attribute.readAttribute(exchange), params); + String path = attribute.readAttribute(exchange); + if(path == null) { + return false; + } + boolean result = this.value.matches(path, params); if (result) { Map context = exchange.getAttachment(PREDICATE_CONTEXT); if (context != null) { Index: 3rdParty_sources/undertow/io/undertow/predicate/RegularExpressionPredicate.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/predicate/Attic/RegularExpressionPredicate.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/predicate/RegularExpressionPredicate.java 25 Nov 2014 10:46:54 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/predicate/RegularExpressionPredicate.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -56,7 +56,11 @@ @Override public boolean resolve(final HttpServerExchange value) { - Matcher matcher = pattern.matcher(matchAttribute.readAttribute(value)); + String input = matchAttribute.readAttribute(value); + if(input == null) { + return false; + } + Matcher matcher = pattern.matcher(input); final boolean matches; if (requireFullMatch) { matches = matcher.matches(); Index: 3rdParty_sources/undertow/io/undertow/protocols/ajp/AjpClientChannel.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/protocols/ajp/Attic/AjpClientChannel.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/protocols/ajp/AjpClientChannel.java 25 Nov 2014 10:46:52 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/protocols/ajp/AjpClientChannel.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -85,7 +85,7 @@ return null; } else { frameData.free(); - throw new RuntimeException("TODO: unkown frame"); + throw new RuntimeException("TODO: unknown frame"); } } Index: 3rdParty_sources/undertow/io/undertow/security/handlers/AbstractConfidentialityHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/security/handlers/Attic/AbstractConfidentialityHandler.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/security/handlers/AbstractConfidentialityHandler.java 25 Nov 2014 10:46:49 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/security/handlers/AbstractConfidentialityHandler.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -24,6 +24,7 @@ import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; import io.undertow.util.Headers; +import io.undertow.util.StatusCodes; /** * Handler responsible for checking of confidentiality is required for the requested resource and if so rejecting the request @@ -47,11 +48,11 @@ try { URI redirectUri = getRedirectURI(exchange); - exchange.setResponseCode(302); + exchange.setResponseCode(StatusCodes.FOUND); exchange.getResponseHeaders().put(Headers.LOCATION, redirectUri.toString()); } catch (Exception e) { UndertowLogger.REQUEST_LOGGER.exceptionProcessingRequest(e); - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); } exchange.endExchange(); } Index: 3rdParty_sources/undertow/io/undertow/security/impl/FormAuthenticationMechanism.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/security/impl/Attic/FormAuthenticationMechanism.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/security/impl/FormAuthenticationMechanism.java 25 Nov 2014 10:46:52 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/security/impl/FormAuthenticationMechanism.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -33,12 +33,11 @@ import io.undertow.util.Methods; import io.undertow.util.RedirectBuilder; import io.undertow.util.Sessions; +import io.undertow.util.StatusCodes; import java.io.IOException; import static io.undertow.UndertowMessages.MESSAGES; -import static io.undertow.util.StatusCodes.FOUND; -import static io.undertow.util.StatusCodes.TEMPORARY_REDIRECT; /** * @author Stuart Douglas @@ -135,7 +134,7 @@ @Override public boolean handleDefaultResponse(final HttpServerExchange exchange) { FormAuthenticationMechanism.sendRedirect(exchange, location); - exchange.setResponseCode(FOUND); + exchange.setResponseCode(StatusCodes.FOUND); exchange.endExchange(); return true; } @@ -167,7 +166,7 @@ protected Integer servePage(final HttpServerExchange exchange, final String location) { sendRedirect(exchange, location); - return TEMPORARY_REDIRECT; + return StatusCodes.TEMPORARY_REDIRECT; } Index: 3rdParty_sources/undertow/io/undertow/security/impl/SecurityContextImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/security/impl/Attic/SecurityContextImpl.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/security/impl/SecurityContextImpl.java 25 Nov 2014 10:46:52 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/security/impl/SecurityContextImpl.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -35,10 +35,9 @@ import io.undertow.security.idm.IdentityManager; import io.undertow.security.idm.PasswordCredential; import io.undertow.server.HttpServerExchange; +import io.undertow.util.StatusCodes; import static io.undertow.UndertowMessages.MESSAGES; -import static io.undertow.util.StatusCodes.FORBIDDEN; -import static io.undertow.util.StatusCodes.OK; /** * The internal SecurityContext used to hold the state of security for the current exchange. @@ -94,8 +93,11 @@ */ public boolean authenticate() { - // TODO - I don't see a need to force single threaded - if this request is from the servlet APIs then the request will - // have already been dispatched. + if(authenticationState == AuthenticationState.ATTEMPTED) { + //we are re-attempted, so we just reset the state + //see UNDERTOW-263 + authenticationState = AuthenticationState.NOT_ATTEMPTED; + } return !authTransition(); } @@ -335,7 +337,7 @@ if (chosenStatusCode == null) { chosenStatusCode = desiredCode; } else if (desiredCode != null) { - if (chosenStatusCode.equals(OK)) { + if (chosenStatusCode.equals(StatusCodes.OK)) { // Allows a more specific code to be chosen. // TODO - Still need a more complex code resolution strategy if many different codes are // returned (Although those mechanisms may just never work together.) @@ -349,16 +351,17 @@ return transition(); } else { - // Iterated all mechanisms, now need to select a suitable status code. - if (atLeastOneChallenge) { - if (chosenStatusCode != null) { - exchange.setResponseCode(chosenStatusCode); + if(!exchange.isResponseStarted()) { + // Iterated all mechanisms, now need to select a suitable status code. + if (atLeastOneChallenge) { + if (chosenStatusCode != null) { + exchange.setResponseCode(chosenStatusCode); + } + } else { + // No mechanism generated a challenge so send a 403 as our challenge - i.e. just rejecting the request. + exchange.setResponseCode(StatusCodes.FORBIDDEN); } - } else { - // No mechanism generated a challenge so send a 403 as our challenge - i.e. just rejecting the request. - exchange.setResponseCode(FORBIDDEN); } - return AuthenticationState.CHALLENGE_SENT; } Index: 3rdParty_sources/undertow/io/undertow/server/AbstractServerConnection.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/Attic/AbstractServerConnection.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/AbstractServerConnection.java 25 Nov 2014 10:46:48 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/AbstractServerConnection.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -181,6 +181,11 @@ } public Pooled getExtraBytes() { + if(extraBytes != null && !extraBytes.getResource().hasRemaining()) { + extraBytes.free(); + extraBytes = null; + return null; + } return extraBytes; } @@ -287,17 +292,24 @@ @Override public void handleEvent(StreamConnection channel) { - for (CloseListener l : closeListeners) { - try { - l.closed(AbstractServerConnection.this); - } catch (Throwable e) { - UndertowLogger.REQUEST_LOGGER.exceptionInvokingCloseListener(l, e); + try { + for (CloseListener l : closeListeners) { + try { + l.closed(AbstractServerConnection.this); + } catch (Throwable e) { + UndertowLogger.REQUEST_LOGGER.exceptionInvokingCloseListener(l, e); + } } + if (current != null) { + current.endExchange(); + } + ChannelListeners.invokeChannelListener(AbstractServerConnection.this, listener); + } finally { + if(extraBytes != null) { + extraBytes.free(); + extraBytes = null; + } } - if(current != null) { - current.endExchange(); - } - ChannelListeners.invokeChannelListener(AbstractServerConnection.this, listener); } } } Index: 3rdParty_sources/undertow/io/undertow/server/Connectors.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/Attic/Connectors.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/Connectors.java 25 Nov 2014 10:46:48 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/Connectors.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -22,6 +22,8 @@ import io.undertow.server.handlers.Cookie; import io.undertow.util.DateUtils; import io.undertow.util.Headers; +import io.undertow.util.StatusCodes; +import io.undertow.util.URLUtils; import org.xnio.Pooled; import org.xnio.channels.StreamSourceChannel; @@ -215,19 +217,98 @@ } catch (Throwable t) { exchange.setInCall(false); if (!exchange.isResponseStarted()) { - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); } UndertowLogger.REQUEST_LOGGER.errorf(t, "Undertow request failed %s", exchange); exchange.endExchange(); } } + /** + * Sets the request path and query parameters, decoding to the requested charset. + * + * @param exchange The exchange + * @param encodedPath The encoded path + * @param charset The charset + */ + public static void setExchangeRequestPath(final HttpServerExchange exchange, final String encodedPath, final String charset, boolean decode, final boolean allowEncodedSlash, StringBuilder decodeBuffer) { + boolean requiresDecode = false; + for (int i = 0; i < encodedPath.length(); ++i) { + char c = encodedPath.charAt(i); + if (c == '?') { + String part; + String encodedPart = encodedPath.substring(0, i); + if (requiresDecode) { + part = URLUtils.decode(encodedPart, charset, allowEncodedSlash, decodeBuffer); + } else { + part = encodedPart; + } + exchange.setRequestPath(part); + exchange.setRelativePath(part); + exchange.setRequestURI(encodedPart); + final String qs = encodedPath.substring(i + 1); + exchange.setQueryString(qs); + URLUtils.parseQueryString(qs, exchange, charset, decode); + return; + } else if(c == ';') { + String part; + String encodedPart = encodedPath.substring(0, i); + if (requiresDecode) { + part = URLUtils.decode(encodedPart, charset, allowEncodedSlash, decodeBuffer); + } else { + part = encodedPart; + } + exchange.setRequestPath(part); + exchange.setRelativePath(part); + for(int j = i; j < encodedPath.length(); ++j) { + if (encodedPath.charAt(j) == '?') { + exchange.setRequestURI(encodedPath.substring(0, j)); + String pathParams = encodedPath.substring(i + 1, j); + URLUtils.parsePathParms(pathParams, exchange, charset, decode); + String qs = encodedPath.substring(j + 1); + exchange.setQueryString(qs); + URLUtils.parseQueryString(qs, exchange, charset, decode); + return; + } + } + exchange.setRequestURI(encodedPath); + URLUtils.parsePathParms(encodedPath.substring(i + 1), exchange, charset, decode); + return; + } else if(c == '%' || c == '+') { + requiresDecode = true; + } + } + + String part; + if (requiresDecode) { + part = URLUtils.decode(encodedPath, charset, allowEncodedSlash, decodeBuffer); + } else { + part = encodedPath; + } + exchange.setRequestPath(part); + exchange.setRelativePath(part); + exchange.setRequestURI(encodedPath); + } + + + /** * Returns the existing request channel, if it exists. Otherwise returns null * * @param exchange The http server exchange */ public static StreamSourceChannel getExistingRequestChannel(final HttpServerExchange exchange) { return exchange.requestChannel; } + + public static boolean isEntityBodyAllowed(HttpServerExchange exchange){ + int code = exchange.getResponseCode(); + if(code >= 100 && code < 200) { + return false; + } + if(code == 204 || code == 304) { + return false; + } + return true; + } } Index: 3rdParty_sources/undertow/io/undertow/server/HttpServerExchange.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/Attic/HttpServerExchange.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/HttpServerExchange.java 25 Nov 2014 10:46:48 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/HttpServerExchange.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -38,8 +38,10 @@ import io.undertow.util.HeaderMap; import io.undertow.util.Headers; import io.undertow.util.HttpString; +import io.undertow.util.Methods; import io.undertow.util.NetworkUtils; import io.undertow.util.Protocols; +import io.undertow.util.StatusCodes; import org.jboss.logging.Logger; import org.xnio.Buffers; import org.xnio.ChannelExceptionHandler; @@ -276,7 +278,6 @@ private static final int FLAG_IN_CALL = 1 << 17; private static final int FLAG_SHOULD_RESUME_READS = 1 << 18; private static final int FLAG_SHOLD_RESUME_WRITES = 1 << 19; - /** * The source address for the request. If this is null then the actual source address from the channel is used */ @@ -577,7 +578,7 @@ public String getHostName() { String host = requestHeaders.getFirst(Headers.HOST); if (host == null) { - host = getDestinationAddress().getAddress().getHostAddress(); + host = getDestinationAddress().getHostString(); } else { if (host.startsWith("[")) { host = host.substring(1, host.indexOf(']')); @@ -600,10 +601,11 @@ public String getHostAndPort() { String host = requestHeaders.getFirst(Headers.HOST); if (host == null) { - host = NetworkUtils.formatPossibleIpv6Address(getDestinationAddress().getAddress().getHostAddress()); - int port = getDestinationAddress().getPort(); + InetSocketAddress address = getDestinationAddress(); + host = NetworkUtils.formatPossibleIpv6Address(address.getHostString()); + int port = address.getPort(); if (!((getRequestScheme().equals("http") && port == 80) - || (getRequestScheme().equals("https") && port == 8080))) { + || (getRequestScheme().equals("https") && port == 443))) { host = host + ":" + port; } } @@ -665,7 +667,7 @@ * @return True if this exchange represents an upgrade response */ public boolean isUpgrade() { - return getResponseCode() == 101; + return getResponseCode() == StatusCodes.SWITCHING_PROTOCOLS; } /** @@ -820,7 +822,7 @@ throw UndertowMessages.MESSAGES.upgradeNotSupported(); } connection.setUpgradeListener(listener); - setResponseCode(101); + setResponseCode(StatusCodes.SWITCHING_PROTOCOLS); getResponseHeaders().put(Headers.CONNECTION, Headers.UPGRADE_STRING); return this; } @@ -839,7 +841,7 @@ throw UndertowMessages.MESSAGES.upgradeNotSupported(); } connection.setUpgradeListener(listener); - setResponseCode(101); + setResponseCode(StatusCodes.SWITCHING_PROTOCOLS); final HeaderMap headers = getResponseHeaders(); headers.put(Headers.UPGRADE, productName); headers.put(Headers.CONNECTION, Headers.UPGRADE_STRING); @@ -1468,7 +1470,7 @@ //so we attempt to drain, and if we have not drained anything then we //assume the server has not sent any data - if (getResponseCode() != 417 || totalRead > 0) { + if (getResponseCode() != StatusCodes.EXPECTATION_FAILED || totalRead > 0) { requestChannel.getReadSetter().set(ChannelListeners.drainListener(Long.MAX_VALUE, new ChannelListener() { @Override @@ -1499,8 +1501,9 @@ } } catch (IOException e) { UndertowLogger.REQUEST_IO_LOGGER.ioException(e); + invokeExchangeCompleteListeners(); IoUtils.safeClose(connection); - break; + return this; } } @@ -1521,7 +1524,10 @@ } try { if (isResponseChannelAvailable()) { - getResponseHeaders().put(Headers.CONTENT_LENGTH, "0"); + if(!getRequestMethod().equals(Methods.CONNECT) && !(getRequestMethod().equals(Methods.HEAD) && getResponseHeaders().contains(Headers.CONTENT_LENGTH)) && Connectors.isEntityBodyAllowed(this)) { + //according to + getResponseHeaders().put(Headers.CONTENT_LENGTH, "0"); + } getResponseChannel(); } responseChannel.shutdownWrites(); @@ -1548,6 +1554,7 @@ } } catch (IOException e) { UndertowLogger.REQUEST_IO_LOGGER.ioException(e); + invokeExchangeCompleteListeners(); IoUtils.safeClose(connection); } Index: 3rdParty_sources/undertow/io/undertow/server/handlers/HttpContinueReadHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/Attic/HttpContinueReadHandler.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/HttpContinueReadHandler.java 25 Nov 2014 10:46:48 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/HttpContinueReadHandler.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -28,6 +28,7 @@ import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; import io.undertow.util.ConduitFactory; +import io.undertow.util.StatusCodes; import org.xnio.channels.StreamSinkChannel; import org.xnio.conduits.AbstractStreamSourceConduit; import org.xnio.conduits.StreamSourceConduit; @@ -78,7 +79,7 @@ @Override public long transferTo(final long position, final long count, final FileChannel target) throws IOException { - if (exchange.getResponseCode() == 417) { + if (exchange.getResponseCode() == StatusCodes.EXPECTATION_FAILED) { //rejected return -1; } @@ -97,7 +98,7 @@ @Override public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { - if (exchange.getResponseCode() == 417) { + if (exchange.getResponseCode() == StatusCodes.EXPECTATION_FAILED) { //rejected return -1; } @@ -116,7 +117,7 @@ @Override public int read(final ByteBuffer dst) throws IOException { - if (exchange.getResponseCode() == 417) { + if (exchange.getResponseCode() == StatusCodes.EXPECTATION_FAILED) { //rejected return -1; } @@ -135,7 +136,7 @@ @Override public long read(final ByteBuffer[] dsts, final int offs, final int len) throws IOException { - if (exchange.getResponseCode() == 417) { + if (exchange.getResponseCode() == StatusCodes.EXPECTATION_FAILED) { //rejected return -1; } @@ -154,7 +155,7 @@ @Override public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { - if (exchange.getResponseCode() == 417) { + if (exchange.getResponseCode() == StatusCodes.EXPECTATION_FAILED) { //rejected return; } @@ -180,7 +181,7 @@ @Override public void awaitReadable() throws IOException { - if (exchange.getResponseCode() == 417) { + if (exchange.getResponseCode() == StatusCodes.EXPECTATION_FAILED) { //rejected return; } Index: 3rdParty_sources/undertow/io/undertow/server/handlers/PredicateContextHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/Attic/PredicateContextHandler.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/PredicateContextHandler.java 25 Nov 2014 10:46:48 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/PredicateContextHandler.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -22,7 +22,7 @@ import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; -import java.util.HashMap; +import java.util.TreeMap; /** * Handler that sets up the predicate context @@ -39,7 +39,7 @@ @Override public void handleRequest(HttpServerExchange exchange) throws Exception { - exchange.putAttachment(Predicate.PREDICATE_CONTEXT, new HashMap()); + exchange.putAttachment(Predicate.PREDICATE_CONTEXT, new TreeMap()); next.handleRequest(exchange); } } Index: 3rdParty_sources/undertow/io/undertow/server/handlers/RedirectHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/Attic/RedirectHandler.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/RedirectHandler.java 25 Nov 2014 10:46:48 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/RedirectHandler.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -31,6 +31,7 @@ import io.undertow.server.HttpServerExchange; import io.undertow.server.handlers.builder.HandlerBuilder; import io.undertow.util.Headers; +import io.undertow.util.StatusCodes; /** * A redirect handler that redirects to the specified location via a 302 redirect. @@ -60,7 +61,7 @@ @Override public void handleRequest(final HttpServerExchange exchange) throws Exception { - exchange.setResponseCode(302); + exchange.setResponseCode(StatusCodes.FOUND); exchange.getResponseHeaders().put(Headers.LOCATION, attribute.readAttribute(exchange)); exchange.endExchange(); } Index: 3rdParty_sources/undertow/io/undertow/server/handlers/RequestLimit.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/Attic/RequestLimit.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/RequestLimit.java 25 Nov 2014 10:46:48 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/RequestLimit.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -68,6 +68,7 @@ try { final SuspendedRequest task = queue.poll(); if (task != null) { + task.exchange.addExchangeCompleteListener(COMPLETION_LISTENER); task.exchange.dispatch(task.next); } else { decrementRequests(); @@ -99,7 +100,6 @@ } public void handleRequest(final HttpServerExchange exchange, final HttpHandler next) throws Exception { - exchange.addExchangeCompleteListener(COMPLETION_LISTENER); long oldVal, newVal; do { oldVal = state; @@ -118,6 +118,7 @@ } newVal = oldVal + 1; } while (!stateUpdater.compareAndSet(this, oldVal, newVal)); + exchange.addExchangeCompleteListener(COMPLETION_LISTENER); next.handleRequest(exchange); } Index: 3rdParty_sources/undertow/io/undertow/server/handlers/accesslog/DefaultAccessLogReceiver.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/accesslog/Attic/DefaultAccessLogReceiver.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/accesslog/DefaultAccessLogReceiver.java 25 Nov 2014 10:46:59 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/accesslog/DefaultAccessLogReceiver.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -74,6 +74,7 @@ private Writer writer = null; private volatile boolean closed = false; + private boolean initialRun = true; public DefaultAccessLogReceiver(final Executor logWriteExecutor, final File outputDirectory, final String logBaseName) { this(logWriteExecutor, outputDirectory, logBaseName, null); @@ -121,7 +122,17 @@ } if (forceLogRotation) { doRotate(); + } else if(initialRun && defaultLogFile.exists()) { + //if there is an existing log file check if it should be rotated + long lm = defaultLogFile.lastModified(); + Calendar c = Calendar.getInstance(); + c.setTimeInMillis(changeOverPoint); + c.add(Calendar.DATE, -1); + if(lm <= c.getTimeInMillis()) { + doRotate(); + } } + initialRun = false; List messages = new ArrayList<>(); String msg = null; //only grab at most 1000 messages at a time @@ -197,6 +208,9 @@ writer.close(); writer = null; } + if(!defaultLogFile.exists()) { + return; + } File newFile = new File(outputDirectory, logBaseName + "_" + currentDateString + logNameSuffix); int count = 0; while (newFile.exists()) { Index: 3rdParty_sources/undertow/io/undertow/server/handlers/builder/ResponseCodeHandlerBuilder.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/builder/Attic/ResponseCodeHandlerBuilder.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/builder/ResponseCodeHandlerBuilder.java 25 Nov 2014 10:46:54 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/builder/ResponseCodeHandlerBuilder.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -52,7 +52,7 @@ @Override public String defaultParameter() { - return "200"; + return "value"; } @Override Index: 3rdParty_sources/undertow/io/undertow/server/handlers/cache/ResponseCache.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/cache/Attic/ResponseCache.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/cache/ResponseCache.java 25 Nov 2014 10:46:59 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/cache/ResponseCache.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -31,6 +31,7 @@ import io.undertow.util.ETagUtils; import io.undertow.util.Headers; import io.undertow.util.HttpString; +import io.undertow.util.StatusCodes; import static io.undertow.util.Methods.GET; import static io.undertow.util.Methods.HEAD; @@ -129,7 +130,7 @@ } //we do send a 304 if the if-none-match header matches if (!ETagUtils.handleIfNoneMatch(exchange, etag, true)) { - exchange.setResponseCode(304); + exchange.setResponseCode(StatusCodes.NOT_MODIFIED); exchange.endExchange(); return true; } @@ -138,7 +139,7 @@ return false; } if (!DateUtils.handleIfModifiedSince(exchange, existingKey.getLastModified())) { - exchange.setResponseCode(304); + exchange.setResponseCode(StatusCodes.NOT_MODIFIED); exchange.endExchange(); return true; } Index: 3rdParty_sources/undertow/io/undertow/server/handlers/encoding/AllowedContentEncodings.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/encoding/Attic/AllowedContentEncodings.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/encoding/AllowedContentEncodings.java 25 Nov 2014 10:46:59 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/encoding/AllowedContentEncodings.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -26,6 +26,7 @@ import io.undertow.util.ConduitFactory; import io.undertow.util.Headers; import io.undertow.util.Methods; +import io.undertow.util.StatusCodes; import org.xnio.conduits.StreamSinkConduit; /** @@ -87,8 +88,8 @@ } //if this is a zero length response we don't want to encode if (exchange.getResponseContentLength() != 0 - && exchange.getResponseCode() != 204 - && exchange.getResponseCode() != 304) { + && exchange.getResponseCode() != StatusCodes.NO_CONTENT + && exchange.getResponseCode() != StatusCodes.NOT_MODIFIED) { EncodingMapping encoding = getEncoding(); if (encoding != null) { exchange.getResponseHeaders().put(Headers.CONTENT_ENCODING, encoding.getName()); Index: 3rdParty_sources/undertow/io/undertow/server/handlers/error/FileErrorPageHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/error/Attic/FileErrorPageHandler.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/error/FileErrorPageHandler.java 25 Nov 2014 10:46:58 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/error/FileErrorPageHandler.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -70,6 +70,11 @@ this.responseCodes = new HashSet<>(Arrays.asList(responseCodes)); } + public FileErrorPageHandler(HttpHandler next, final File file, final Integer... responseCodes) { + this.next = next; + this.file = file; + this.responseCodes = new HashSet<>(Arrays.asList(responseCodes)); + } @Override public void handleRequest(final HttpServerExchange exchange) throws Exception { exchange.addDefaultResponseListener(new DefaultResponseListener() { @@ -217,7 +222,7 @@ @Override public HttpHandler wrap(HttpHandler handler) { - return new FileErrorPageHandler(new File(file), responseCodes); + return new FileErrorPageHandler(handler, new File(file), responseCodes); } } } Index: 3rdParty_sources/undertow/io/undertow/server/handlers/error/SimpleErrorPageHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/error/Attic/SimpleErrorPageHandler.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/error/SimpleErrorPageHandler.java 25 Nov 2014 10:46:58 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/error/SimpleErrorPageHandler.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -62,7 +62,7 @@ return false; } Set codes = responseCodes; - if (codes == null ? exchange.getResponseCode() >= 400 : codes.contains(Integer.valueOf(exchange.getResponseCode()))) { + if (codes == null ? exchange.getResponseCode() >= StatusCodes.BAD_REQUEST : codes.contains(Integer.valueOf(exchange.getResponseCode()))) { final String errorPage = "Error" + exchange.getResponseCode() + " - " + StatusCodes.getReason(exchange.getResponseCode()) + ""; exchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, "" + errorPage.length()); exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/html"); Index: 3rdParty_sources/undertow/io/undertow/server/handlers/form/MultiPartParserDefinition.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/form/Attic/MultiPartParserDefinition.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/form/MultiPartParserDefinition.java 25 Nov 2014 10:47:01 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/form/MultiPartParserDefinition.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -29,6 +29,7 @@ import io.undertow.util.MalformedMessageException; import io.undertow.util.MultipartParser; import io.undertow.util.SameThreadExecutor; +import io.undertow.util.StatusCodes; import org.xnio.ChannelListener; import org.xnio.FileAccess; import org.xnio.IoUtils; @@ -347,7 +348,7 @@ exchange.dispatch(SameThreadExecutor.INSTANCE, handler); } else { UndertowLogger.REQUEST_IO_LOGGER.ioException(UndertowMessages.MESSAGES.connectionTerminatedReadingMultiPartData()); - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); exchange.endExchange(); } return; @@ -359,15 +360,15 @@ } } catch (MalformedMessageException e) { UndertowLogger.REQUEST_IO_LOGGER.ioException(e); - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); exchange.endExchange(); } finally { pooled.free(); } } catch (Throwable e) { UndertowLogger.REQUEST_IO_LOGGER.debug("Exception parsing data", e); - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); exchange.endExchange(); } } Index: 3rdParty_sources/undertow/io/undertow/server/handlers/proxy/ProxyHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/proxy/Attic/ProxyHandler.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/proxy/ProxyHandler.java 25 Nov 2014 10:46:52 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/proxy/ProxyHandler.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -68,6 +68,7 @@ import io.undertow.util.Headers; import io.undertow.util.HttpString; import io.undertow.util.SameThreadExecutor; +import io.undertow.util.StatusCodes; import org.jboss.logging.Logger; import org.xnio.ChannelExceptionHandler; import org.xnio.ChannelListener; @@ -291,7 +292,7 @@ if (exchange.isResponseStarted()) { IoUtils.safeClose(exchange.getConnection()); } else { - exchange.setResponseCode(503); + exchange.setResponseCode(StatusCodes.SERVICE_UNAVAILABLE); exchange.endExchange(); } } @@ -308,7 +309,7 @@ if (exchange.isResponseStarted()) { IoUtils.safeClose(exchange.getConnection()); } else { - exchange.setResponseCode(503); + exchange.setResponseCode(StatusCodes.SERVICE_UNAVAILABLE); exchange.endExchange(); } } @@ -372,7 +373,7 @@ } } catch (UnsupportedEncodingException e) { //impossible - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); exchange.endExchange(); return; } @@ -419,19 +420,46 @@ } // Set the protocol header and attachment - final String proto = exchange.getRequestScheme().equals("https") ? "https" : "http"; - request.getRequestHeaders().put(Headers.X_FORWARDED_PROTO, proto); - request.putAttachment(ProxiedRequestAttachments.IS_SSL, proto.equals("https")); + if(reuseXForwarded && exchange.getRequestHeaders().contains(Headers.X_FORWARDED_PROTO)) { + final String proto = exchange.getRequestHeaders().getFirst(Headers.X_FORWARDED_PROTO); + request.putAttachment(ProxiedRequestAttachments.IS_SSL, proto.equals("https")); + } else { + final String proto = exchange.getRequestScheme().equals("https") ? "https" : "http"; + request.getRequestHeaders().put(Headers.X_FORWARDED_PROTO, proto); + request.putAttachment(ProxiedRequestAttachments.IS_SSL, proto.equals("https")); + } // Set the server name - final String hostName = exchange.getHostName(); - request.getRequestHeaders().put(Headers.X_FORWARDED_HOST, hostName); - request.putAttachment(ProxiedRequestAttachments.SERVER_NAME, hostName); + if(reuseXForwarded && exchange.getRequestHeaders().contains(Headers.X_FORWARDED_SERVER)) { + final String hostName = exchange.getRequestHeaders().getFirst(Headers.X_FORWARDED_SERVER); + request.putAttachment(ProxiedRequestAttachments.SERVER_NAME, hostName); + } else { + final String hostName = exchange.getHostName(); + request.getRequestHeaders().put(Headers.X_FORWARDED_SERVER, hostName); + request.putAttachment(ProxiedRequestAttachments.SERVER_NAME, hostName); + } + if(!exchange.getRequestHeaders().contains(Headers.X_FORWARDED_HOST)) { + final String hostName = exchange.getHostName(); + if(hostName != null) { + request.getRequestHeaders().put(Headers.X_FORWARDED_HOST, hostName); + } + } // Set the port - int port = exchange.getConnection().getLocalAddress(InetSocketAddress.class).getPort(); - request.getRequestHeaders().put(Headers.X_FORWARDED_PORT, port); - request.putAttachment(ProxiedRequestAttachments.SERVER_PORT, port); + if(reuseXForwarded && exchange.getRequestHeaders().contains(Headers.X_FORWARDED_PORT)) { + try { + int port = Integer.parseInt(exchange.getRequestHeaders().getFirst(Headers.X_FORWARDED_PORT)); + request.putAttachment(ProxiedRequestAttachments.SERVER_PORT, port); + } catch (NumberFormatException e) { + int port = exchange.getConnection().getLocalAddress(InetSocketAddress.class).getPort(); + request.getRequestHeaders().put(Headers.X_FORWARDED_PORT, port); + request.putAttachment(ProxiedRequestAttachments.SERVER_PORT, port); + } + } else { + int port = exchange.getConnection().getLocalAddress(InetSocketAddress.class).getPort(); + request.getRequestHeaders().put(Headers.X_FORWARDED_PORT, port); + request.putAttachment(ProxiedRequestAttachments.SERVER_PORT, port); + } SSLSessionInfo sslSessionInfo = exchange.getConnection().getSslSessionInfo(); if (sslSessionInfo != null) { @@ -512,7 +540,7 @@ public void failed(IOException e) { UndertowLogger.PROXY_REQUEST_LOGGER.proxyRequestFailed(exchange.getRequestURI(), e); if (!exchange.isResponseStarted()) { - exchange.setResponseCode(503); + exchange.setResponseCode(StatusCodes.SERVICE_UNAVAILABLE); exchange.endExchange(); } else { IoUtils.safeClose(exchange.getConnection()); @@ -567,7 +595,7 @@ public void failed(IOException e) { UndertowLogger.PROXY_REQUEST_LOGGER.proxyRequestFailed(exchange.getRequestURI(), e); if (!exchange.isResponseStarted()) { - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); exchange.endExchange(); } else { IoUtils.safeClose(exchange.getConnection()); @@ -631,13 +659,13 @@ IoUtils.safeClose(clientConnection); UndertowLogger.REQUEST_IO_LOGGER.debug("Exception reading from target server", exception); if (!exchange.isResponseStarted()) { - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); exchange.endExchange(); } else { IoUtils.safeClose(exchange.getConnection()); } } else { - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); exchange.endExchange(); } } Index: 3rdParty_sources/undertow/io/undertow/server/handlers/resource/DirectoryUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/resource/Attic/DirectoryUtils.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/resource/DirectoryUtils.java 25 Nov 2014 10:46:54 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/resource/DirectoryUtils.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -28,6 +28,7 @@ import io.undertow.util.Headers; import io.undertow.util.Methods; import io.undertow.util.RedirectBuilder; +import io.undertow.util.StatusCodes; import org.xnio.channels.Channels; /** @@ -130,7 +131,7 @@ public static void renderDirectoryListing(HttpServerExchange exchange, Resource resource) { String requestPath = exchange.getRequestPath(); if (! requestPath.endsWith("/")) { - exchange.setResponseCode(302); + exchange.setResponseCode(StatusCodes.FOUND); exchange.getResponseHeaders().put(Headers.LOCATION, RedirectBuilder.redirect(exchange, exchange.getRelativePath() + "/", true)); exchange.endExchange(); return; @@ -148,7 +149,7 @@ throw new IllegalStateException(e); } catch (IOException e) { UndertowLogger.REQUEST_IO_LOGGER.ioException(e); - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); } exchange.endExchange(); Index: 3rdParty_sources/undertow/io/undertow/server/handlers/resource/FileResource.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/resource/Attic/FileResource.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/resource/FileResource.java 25 Nov 2014 10:46:55 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/resource/FileResource.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -36,6 +36,7 @@ import io.undertow.util.DateUtils; import io.undertow.util.ETag; import io.undertow.util.MimeMappings; +import io.undertow.util.StatusCodes; import org.xnio.FileAccess; import org.xnio.IoUtils; import org.xnio.Pooled; @@ -119,11 +120,11 @@ try { fileChannel = exchange.getConnection().getWorker().getXnio().openFile(file, FileAccess.READ_ONLY); } catch (FileNotFoundException e) { - exchange.setResponseCode(404); + exchange.setResponseCode(StatusCodes.NOT_FOUND); callback.onException(exchange, sender, e); return false; } catch (IOException e) { - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); callback.onException(exchange, sender, e); return false; } @@ -182,7 +183,7 @@ } IoUtils.safeClose(fileChannel); if (!exchange.isResponseStarted()) { - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); } callback.onException(exchange, sender, exception); } Index: 3rdParty_sources/undertow/io/undertow/server/handlers/resource/FileResourceManager.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/resource/Attic/FileResourceManager.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/resource/FileResourceManager.java 25 Nov 2014 10:46:54 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/resource/FileResourceManager.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -64,7 +64,8 @@ private final boolean followLinks; /** - * Used if followLinks == true. Set of paths valid to follow symbolic links + * Used if followLinks == true. Set of paths valid to follow symbolic links. If this is empty and followLinks + * it true then all links will be followed */ private final TreeSet safePaths = new TreeSet(); @@ -132,8 +133,12 @@ try { File file = new File(base, path); if (file.exists()) { - boolean isSymlinkPath = isSymlinkPath(base, file); - if (isSymlinkPath) { + if(path.endsWith("/") && ! file.isDirectory()) { + //UNDERTOW-432 don't return non directories if the path ends with a / + return null; + } + boolean followAll = this.followLinks && safePaths.isEmpty(); + if (!followAll && isSymlinkPath(base, file)) { if (this.followLinks && isSymlinkSafe(file)) { return getFileResource(file, path); } Index: 3rdParty_sources/undertow/io/undertow/server/handlers/resource/ResourceHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/resource/Attic/ResourceHandler.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/resource/ResourceHandler.java 25 Nov 2014 10:46:55 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/resource/ResourceHandler.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -115,7 +115,7 @@ } else if (exchange.getRequestMethod().equals(Methods.HEAD)) { serveResource(exchange, false); } else { - exchange.setResponseCode(405); + exchange.setResponseCode(StatusCodes.METHOD_NOT_ALLOWED); exchange.endExchange(); } } @@ -127,7 +127,7 @@ } if (!allowed.resolve(exchange)) { - exchange.setResponseCode(403); + exchange.setResponseCode(StatusCodes.FORBIDDEN); exchange.endExchange(); return; } @@ -167,12 +167,12 @@ } } catch (IOException e) { UndertowLogger.REQUEST_IO_LOGGER.ioException(e); - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); exchange.endExchange(); return; } if (resource == null) { - exchange.setResponseCode(404); + exchange.setResponseCode(StatusCodes.NOT_FOUND); exchange.endExchange(); return; } @@ -183,7 +183,7 @@ indexResource = getIndexFiles(resourceManager, resource.getPath(), welcomeFiles); } catch (IOException e) { UndertowLogger.REQUEST_IO_LOGGER.ioException(e); - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); exchange.endExchange(); return; } @@ -197,29 +197,33 @@ return; } } else if (!exchange.getRequestPath().endsWith("/")) { - exchange.setResponseCode(302); + exchange.setResponseCode(StatusCodes.FOUND); exchange.getResponseHeaders().put(Headers.LOCATION, RedirectBuilder.redirect(exchange, exchange.getRelativePath() + "/", true)); exchange.endExchange(); return; } resource = indexResource; + } else if(exchange.getRelativePath().endsWith("/")) { + //UNDERTOW-432 + exchange.setResponseCode(StatusCodes.NOT_FOUND); + exchange.endExchange(); + return; } final ETag etag = resource.getETag(); final Date lastModified = resource.getLastModified(); if (!ETagUtils.handleIfMatch(exchange, etag, false) || !DateUtils.handleIfUnmodifiedSince(exchange, lastModified)) { - exchange.setResponseCode(412); + exchange.setResponseCode(StatusCodes.PRECONDITION_FAILED); exchange.endExchange(); return; } if (!ETagUtils.handleIfNoneMatch(exchange, etag, true) || !DateUtils.handleIfModifiedSince(exchange, lastModified)) { - exchange.setResponseCode(304); + exchange.setResponseCode(StatusCodes.NOT_MODIFIED); exchange.endExchange(); return; } - //todo: handle range requests //we are going to proceed. Set the appropriate headers final String contentType = resource.getContentType(mimeMappings); @@ -237,7 +241,7 @@ exchange.getResponseHeaders().put(Headers.ETAG, etag.toString()); } Long contentLength = resource.getContentLength(); - if (contentLength != null) { + if (contentLength != null && !exchange.getResponseHeaders().contains(Headers.TRANSFER_ENCODING)) { exchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, contentLength.toString()); } @@ -255,7 +259,7 @@ } catch (IOException e) { //TODO: should this be fatal UndertowLogger.REQUEST_IO_LOGGER.ioException(e); - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); exchange.endExchange(); return; } Index: 3rdParty_sources/undertow/io/undertow/server/handlers/resource/URLResource.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/handlers/resource/Attic/URLResource.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/handlers/resource/URLResource.java 25 Nov 2014 10:46:55 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/handlers/resource/URLResource.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -37,6 +37,7 @@ import io.undertow.util.DateUtils; import io.undertow.util.ETag; import io.undertow.util.MimeMappings; +import io.undertow.util.StatusCodes; import org.xnio.IoUtils; /** @@ -138,7 +139,7 @@ try { inputStream = url.openStream(); } catch (IOException e) { - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); return; } buffer = new byte[1024];//TODO: we should be pooling these @@ -172,7 +173,7 @@ UndertowLogger.REQUEST_IO_LOGGER.ioException(exception); IoUtils.safeClose(inputStream); if (!exchange.isResponseStarted()) { - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); } completionCallback.onException(exchange, sender, exception); } Index: 3rdParty_sources/undertow/io/undertow/server/protocol/ajp/AjpReadListener.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/protocol/ajp/Attic/AjpReadListener.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/protocol/ajp/AjpReadListener.java 25 Nov 2014 10:47:00 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/protocol/ajp/AjpReadListener.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -94,6 +94,7 @@ if(parseTimeoutUpdater != null) { parseTimeoutUpdater.connectionIdle(); } + connection.setCurrentExchange(null); } public void handleEvent(final StreamSourceChannel channel) { @@ -117,7 +118,7 @@ res = channel.read(buffer); } catch (IOException e) { UndertowLogger.REQUEST_IO_LOGGER.ioException(e); - safeClose(channel); + safeClose(connection); return; } } else { @@ -227,12 +228,11 @@ } catch (Throwable t) { //TODO: we should attempt to return a 500 status code in this situation UndertowLogger.REQUEST_LOGGER.exceptionProcessingRequest(t); - safeClose(channel); safeClose(connection); } } catch (Exception e) { UndertowLogger.REQUEST_LOGGER.exceptionProcessingRequest(e); - safeClose(connection.getChannel()); + safeClose(connection); } finally { if (free) pooled.free(); } Index: 3rdParty_sources/undertow/io/undertow/server/protocol/ajp/AjpRequestParser.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/protocol/ajp/Attic/AjpRequestParser.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/protocol/ajp/AjpRequestParser.java 25 Nov 2014 10:47:00 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/protocol/ajp/AjpRequestParser.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -243,7 +243,7 @@ } else { final String url = result.value.substring(0, colon); String res = decode(url, result.containsUrlCharacters); - exchange.setRequestURI(url); + exchange.setRequestURI(result.value); exchange.setRequestPath(res); exchange.setRelativePath(res); URLUtils.parsePathParms(result.value.substring(colon + 1), exchange, encoding, doDecode && result.containsUrlCharacters); Index: 3rdParty_sources/undertow/io/undertow/server/protocol/ajp/AjpServerRequestConduit.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/protocol/ajp/Attic/AjpServerRequestConduit.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/protocol/ajp/AjpServerRequestConduit.java 25 Nov 2014 10:47:00 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/protocol/ajp/AjpServerRequestConduit.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -125,12 +125,22 @@ @Override public long transferTo(long position, long count, FileChannel target) throws IOException { - return target.transferFrom(new ConduitReadableByteChannel(this), position, count); + try { + return target.transferFrom(new ConduitReadableByteChannel(this), position, count); + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; + } } @Override public long transferTo(long count, ByteBuffer throughBuffer, StreamSinkChannel target) throws IOException { - return IoUtils.transfer(new ConduitReadableByteChannel(this), count, throughBuffer, target); + try { + return IoUtils.transfer(new ConduitReadableByteChannel(this), count, throughBuffer, target); + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; + } } @Override @@ -144,46 +154,56 @@ @Override public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { - long total = 0; - for (int i = offset; i < length; ++i) { - while (dsts[i].hasRemaining()) { - int r = read(dsts[i]); - if (r <= 0 && total > 0) { - return total; - } else if (r <= 0) { - return r; - } else { - total += r; + try { + long total = 0; + for (int i = offset; i < length; ++i) { + while (dsts[i].hasRemaining()) { + int r = read(dsts[i]); + if (r <= 0 && total > 0) { + return total; + } else if (r <= 0) { + return r; + } else { + total += r; + } } } + return total; + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; } - return total; } @Override public int read(ByteBuffer dst) throws IOException { - long state = this.state; - if (anyAreSet(state, STATE_FINISHED)) { - return -1; - } else if (anyAreSet(state, STATE_SEND_REQUIRED)) { - state = this.state = (state & STATE_MASK) | STATE_READING; - if(ajpResponseConduit.isWriteShutdown()) { - this.state = STATE_FINISHED; - if (finishListener != null) { - finishListener.handleEvent(this); - } + try { + long state = this.state; + if (anyAreSet(state, STATE_FINISHED)) { return -1; + } else if (anyAreSet(state, STATE_SEND_REQUIRED)) { + state = this.state = (state & STATE_MASK) | STATE_READING; + if (ajpResponseConduit.isWriteShutdown()) { + this.state = STATE_FINISHED; + if (finishListener != null) { + finishListener.handleEvent(this); + } + return -1; + } + if (!ajpResponseConduit.doGetRequestBodyChunk(READ_BODY_CHUNK.duplicate(), this)) { + return 0; + } } - if (!ajpResponseConduit.doGetRequestBodyChunk(READ_BODY_CHUNK.duplicate(), this)) { - return 0; + //we might have gone into state_reading above + if (anyAreSet(state, STATE_READING)) { + return doRead(dst, state); } + assert STATE_FINISHED == state; + return -1; + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; } - //we might have gone into state_reading above - if (anyAreSet(state, STATE_READING)) { - return doRead(dst, state); - } - assert STATE_FINISHED == state; - return -1; } private int doRead(final ByteBuffer dst, long state) throws IOException { @@ -274,15 +294,25 @@ @Override public void awaitReadable() throws IOException { - if (anyAreSet(state, STATE_READING)) { - next.awaitReadable(); + try { + if (anyAreSet(state, STATE_READING)) { + next.awaitReadable(); + } + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; } } @Override public void awaitReadable(long time, TimeUnit timeUnit) throws IOException { - if (anyAreSet(state, STATE_READING)) { - next.awaitReadable(time, timeUnit); + try { + if (anyAreSet(state, STATE_READING)) { + next.awaitReadable(time, timeUnit); + } + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; } } @@ -291,6 +321,9 @@ * @param e */ void setReadBodyChunkError(IOException e) { - //TODO: + IoUtils.safeClose(exchange.getConnection()); + if(isReadResumed()) { + wakeupReads(); + } } } Index: 3rdParty_sources/undertow/io/undertow/server/protocol/ajp/AjpServerResponseConduit.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/protocol/ajp/Attic/AjpServerResponseConduit.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/protocol/ajp/AjpServerResponseConduit.java 25 Nov 2014 10:47:00 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/protocol/ajp/AjpServerResponseConduit.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -288,6 +288,9 @@ } } while (toWrite > 0); return originalPayloadSize; + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; } finally { src.limit(limit); } @@ -379,10 +382,15 @@ @Override protected void doTerminateWrites() throws IOException { - if (!exchange.isPersistent()) { - next.terminateWrites(); + try { + if (!exchange.isPersistent()) { + next.terminateWrites(); + } + state |= FLAG_WRITE_SHUTDOWN; + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; } - state |= FLAG_WRITE_SHUTDOWN; } @Override Index: 3rdParty_sources/undertow/io/undertow/server/protocol/framed/AbstractFramedChannel.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/protocol/framed/Attic/AbstractFramedChannel.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/protocol/framed/AbstractFramedChannel.java 25 Nov 2014 10:46:48 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/protocol/framed/AbstractFramedChannel.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -321,6 +321,11 @@ } receiver = null; } + //if we read data into a frame we just return immediately, even if there is more remaining + //see https://issues.jboss.org/browse/UNDERTOW-410 + //basically if we don't do this we loose some message ordering semantics + //as the second message may be processed before the first one + return null; } FrameHeaderData data = parseFrame(pooled.getResource()); if (data != null) { Index: 3rdParty_sources/undertow/io/undertow/server/protocol/framed/AbstractFramedStreamSinkChannel.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/protocol/framed/Attic/AbstractFramedStreamSinkChannel.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/protocol/framed/AbstractFramedStreamSinkChannel.java 25 Nov 2014 10:46:48 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/protocol/framed/AbstractFramedStreamSinkChannel.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -593,6 +593,7 @@ } if(buffer != null) { buffer.free(); + buffer = null; } } } Index: 3rdParty_sources/undertow/io/undertow/server/protocol/http/HttpContinue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/protocol/http/Attic/HttpContinue.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/protocol/http/HttpContinue.java 25 Nov 2014 10:47:00 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/protocol/http/HttpContinue.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -22,7 +22,9 @@ import io.undertow.io.IoCallback; import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; +import io.undertow.util.AttachmentKey; import io.undertow.util.Headers; +import io.undertow.util.StatusCodes; import org.xnio.ChannelExceptionHandler; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; @@ -45,14 +47,16 @@ public static final String CONTINUE = "100-continue"; + private static final AttachmentKey ALREADY_SENT = AttachmentKey.create(Boolean.class); + /** * Returns true if this exchange requires the server to send a 100 (Continue) response. * * @param exchange The exchange * @return true if the server needs to send a continue response */ public static boolean requiresContinueResponse(final HttpServerExchange exchange) { - if (!exchange.isHttp11() || exchange.isResponseStarted()) { + if (!exchange.isHttp11() || exchange.isResponseStarted() || exchange.getAttachment(ALREADY_SENT) != null) { return false; } if (exchange.getConnection() instanceof HttpServerConnection) { @@ -97,9 +101,29 @@ if (!exchange.isResponseChannelAvailable()) { throw UndertowMessages.MESSAGES.cannotSendContinueResponse(); } + if(exchange.getAttachment(ALREADY_SENT) != null) { + return new ContinueResponseSender() { + @Override + public boolean send() throws IOException { + return true; + } + + @Override + public void awaitWritable() throws IOException { + + } + + @Override + public void awaitWritable(long time, TimeUnit timeUnit) throws IOException { + + } + }; + } + HttpServerExchange newExchange = exchange.getConnection().sendOutOfBandResponse(exchange); - newExchange.setResponseCode(100); + exchange.putAttachment(ALREADY_SENT, true); + newExchange.setResponseCode(StatusCodes.CONTINUE); newExchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, 0); final StreamSinkChannel responseChannel = newExchange.getResponseChannel(); return new ContinueResponseSender() { @@ -135,8 +159,12 @@ if (!exchange.isResponseChannelAvailable()) { throw UndertowMessages.MESSAGES.cannotSendContinueResponse(); } + if(exchange.getAttachment(ALREADY_SENT) != null) { + return; + } HttpServerExchange newExchange = exchange.getConnection().sendOutOfBandResponse(exchange); - newExchange.setResponseCode(100); + exchange.putAttachment(ALREADY_SENT, true); + newExchange.setResponseCode(StatusCodes.CONTINUE); newExchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, 0); newExchange.startBlocking(); newExchange.getOutputStream().close(); @@ -149,15 +177,20 @@ * @param exchange The exchange to reject */ public static void rejectExchange(final HttpServerExchange exchange) { - exchange.setResponseCode(417); + exchange.setResponseCode(StatusCodes.EXPECTATION_FAILED); exchange.setPersistent(false); exchange.endExchange(); } private static void internalSendContinueResponse(final HttpServerExchange exchange, final IoCallback callback) { + if(exchange.getAttachment(ALREADY_SENT) != null) { + callback.onComplete(exchange, null); + return; + } HttpServerExchange newExchange = exchange.getConnection().sendOutOfBandResponse(exchange); - newExchange.setResponseCode(100); + exchange.putAttachment(ALREADY_SENT, true); + newExchange.setResponseCode(StatusCodes.CONTINUE); newExchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, 0); final StreamSinkChannel responseChannel = newExchange.getResponseChannel(); try { Index: 3rdParty_sources/undertow/io/undertow/server/protocol/http/HttpReadListener.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/protocol/http/Attic/HttpReadListener.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/protocol/http/HttpReadListener.java 25 Nov 2014 10:47:00 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/protocol/http/HttpReadListener.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -25,14 +25,15 @@ import io.undertow.server.HttpServerExchange; import io.undertow.server.protocol.ParseTimeoutUpdater; import io.undertow.util.ClosingChannelExceptionHandler; +import io.undertow.util.HttpString; +import io.undertow.util.Protocols; import io.undertow.util.StringWriteChannelListener; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.IoUtils; import org.xnio.Pooled; import org.xnio.StreamConnection; import org.xnio.channels.StreamSinkChannel; -import org.xnio.channels.StreamSourceChannel; import org.xnio.conduits.ConduitStreamSinkChannel; import org.xnio.conduits.ConduitStreamSourceChannel; @@ -60,6 +61,7 @@ private final int maxRequestSize; private final long maxEntitySize; private final boolean recordRequestStartTime; + private final boolean allowUnknownProtocols; //0 = new request ok, reads resumed //1 = request running, new request not ok @@ -76,6 +78,7 @@ this.maxRequestSize = connection.getUndertowOptions().get(UndertowOptions.MAX_HEADER_SIZE, UndertowOptions.DEFAULT_MAX_HEADER_SIZE); this.maxEntitySize = connection.getUndertowOptions().get(UndertowOptions.MAX_ENTITY_SIZE, UndertowOptions.DEFAULT_MAX_ENTITY_SIZE); this.recordRequestStartTime = connection.getUndertowOptions().get(UndertowOptions.RECORD_REQUEST_START_TIME, false); + this.allowUnknownProtocols = connection.getUndertowOptions().get(UndertowOptions.ALLOW_UNKNOWN_PROTOCOLS, false); int requestParseTimeout = connection.getUndertowOptions().get(UndertowOptions.REQUEST_PARSE_TIMEOUT, -1); int requestIdleTimeout = connection.getUndertowOptions().get(UndertowOptions.NO_REQUEST_TIMEOUT, -1); if(requestIdleTimeout < 0 && requestParseTimeout < 0) { @@ -93,6 +96,7 @@ if(parseTimeoutUpdater != null) { parseTimeoutUpdater.connectionIdle(); } + connection.setCurrentExchange(null); } public void handleEvent(final ConduitStreamSourceChannel channel) { @@ -152,12 +156,13 @@ } else { buffer.flip(); } + int begin = buffer.remaining(); parser.handle(buffer, state, httpServerExchange); if (buffer.hasRemaining()) { free = false; connection.setExtraBytes(pooled); } - int total = read + res; + int total = read + (begin - buffer.remaining()); read = total; if (read > maxRequestSize) { UndertowLogger.REQUEST_LOGGER.requestHeaderWasTooLarge(connection.getPeerAddress(), maxRequestSize); @@ -173,6 +178,15 @@ httpServerExchange.setRequestScheme(connection.getSslSession() != null ? "https" : "http"); this.httpServerExchange = null; requestStateUpdater.set(this, 1); + + if(!allowUnknownProtocols) { + HttpString protocol = httpServerExchange.getProtocol(); + if(protocol != Protocols.HTTP_1_1 && protocol != Protocols.HTTP_1_0 && protocol != Protocols.HTTP_0_9) { + UndertowLogger.REQUEST_IO_LOGGER.debugf("Closing connection from %s due to unknown protocol %s", connection.getChannel().getPeerAddress(), protocol); + sendBadRequestAndClose(connection.getChannel(), new IOException()); + return; + } + } HttpTransferEncoding.setupRequest(httpServerExchange); if (recordRequestStartTime) { Connectors.setRequestStartTime(httpServerExchange); @@ -192,21 +206,7 @@ channel.setReadListener(this); channel.resumeReads(); } else if (res == -1) { - handleConnectionClose(channel); - } - } - - private void handleConnectionClose(StreamSourceChannel channel) { - try { - channel.suspendReads(); - channel.shutdownReads(); - final StreamSinkChannel responseChannel = this.connection.getChannel().getSinkChannel(); - responseChannel.shutdownWrites(); IoUtils.safeClose(connection); - } catch (IOException e) { - UndertowLogger.REQUEST_IO_LOGGER.debug("Error reading request", e); - // fuck it, it's all ruined - IoUtils.safeClose(connection); } } Index: 3rdParty_sources/undertow/io/undertow/server/protocol/http/HttpResponseConduit.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/protocol/http/Attic/HttpResponseConduit.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/protocol/http/HttpResponseConduit.java 25 Nov 2014 10:47:00 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/protocol/http/HttpResponseConduit.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -25,7 +25,6 @@ import io.undertow.server.Connectors; import io.undertow.server.HttpServerExchange; -import io.undertow.server.TruncatedResponseException; import io.undertow.util.HeaderMap; import io.undertow.util.HeaderValues; import io.undertow.util.HttpString; @@ -118,137 +117,146 @@ if(done) { throw new ClosedChannelException(); } - assert state != STATE_BODY; - if (state == STATE_BUF_FLUSH) { - final ByteBuffer byteBuffer = pooledBuffer.getResource(); + try { + assert state != STATE_BODY; + if (state == STATE_BUF_FLUSH) { + final ByteBuffer byteBuffer = pooledBuffer.getResource(); + do { + long res = 0; + ByteBuffer[] data; + if (userData == null || length == 0) { + res = next.write(byteBuffer); + } else if (userData instanceof ByteBuffer) { + data = writevBuffer; + if (data == null) { + data = writevBuffer = new ByteBuffer[2]; + } + data[0] = byteBuffer; + data[1] = (ByteBuffer) userData; + res = next.write(data, 0, 2); + } else { + data = writevBuffer; + if (data == null || data.length < length + 1) { + data = writevBuffer = new ByteBuffer[length + 1]; + } + data[0] = byteBuffer; + System.arraycopy(userData, pos, data, 1, length); + res = next.write(data, 0, data.length); + } + if (res == 0) { + return STATE_BUF_FLUSH; + } + } while (byteBuffer.hasRemaining()); + bufferDone(); + return STATE_BODY; + } else if (state != STATE_START) { + return processStatefulWrite(state, userData, pos, length); + } + + //merge the cookies into the header map + Connectors.flattenCookies(exchange); + + if (pooledBuffer == null) { + pooledBuffer = pool.allocate(); + } + ByteBuffer buffer = pooledBuffer.getResource(); + + + assert buffer.remaining() >= 0x100; + exchange.getProtocol().appendTo(buffer); + buffer.put((byte) ' '); + int code = exchange.getResponseCode(); + assert 999 >= code && code >= 100; + buffer.put((byte) (code / 100 + '0')); + buffer.put((byte) (code / 10 % 10 + '0')); + buffer.put((byte) (code % 10 + '0')); + buffer.put((byte) ' '); + String string = StatusCodes.getReason(code); + writeString(buffer, string); + buffer.put((byte) '\r').put((byte) '\n'); + + int remaining = buffer.remaining(); + + + HeaderMap headers = exchange.getResponseHeaders(); + long fiCookie = headers.fastIterateNonEmpty(); + while (fiCookie != -1) { + HeaderValues headerValues = headers.fiCurrent(fiCookie); + + HttpString header = headerValues.getHeaderName(); + int headerSize = header.length(); + int valueIdx = 0; + while (valueIdx < headerValues.size()) { + remaining -= (headerSize + 2); + + if (remaining < 0) { + this.fiCookie = fiCookie; + this.string = string; + this.headerValues = headerValues; + this.valueIdx = valueIdx; + this.charIndex = 0; + this.state = STATE_HDR_NAME; + buffer.flip(); + return processStatefulWrite(STATE_HDR_NAME, userData, pos, length); + } + header.appendTo(buffer); + buffer.put((byte) ':').put((byte) ' '); + string = headerValues.get(valueIdx++); + + remaining -= (string.length() + 2); + if (remaining < 2) {//we use 2 here, to make sure we always have room for the final \r\n + this.fiCookie = fiCookie; + this.string = string; + this.headerValues = headerValues; + this.valueIdx = valueIdx; + this.charIndex = 0; + this.state = STATE_HDR_VAL; + buffer.flip(); + return processStatefulWrite(STATE_HDR_VAL, userData, pos, length); + } + writeString(buffer, string); + buffer.put((byte) '\r').put((byte) '\n'); + } + fiCookie = headers.fiNextNonEmpty(fiCookie); + } + buffer.put((byte) '\r').put((byte) '\n'); + buffer.flip(); do { long res = 0; ByteBuffer[] data; - if (userData == null || length == 0) { - res = next.write(byteBuffer); - } else if (userData instanceof ByteBuffer){ + if (userData == null) { + res = next.write(buffer); + } else if (userData instanceof ByteBuffer) { data = writevBuffer; - if(data == null) { + if (data == null) { data = writevBuffer = new ByteBuffer[2]; } - data[0] = byteBuffer; + data[0] = buffer; data[1] = (ByteBuffer) userData; res = next.write(data, 0, 2); } else { data = writevBuffer; - if(data == null || data.length < length + 1) { + if (data == null || data.length < length + 1) { data = writevBuffer = new ByteBuffer[length + 1]; } - data[0] = byteBuffer; + data[0] = buffer; System.arraycopy(userData, pos, data, 1, length); - res = next.write(data, 0, data.length); + res = next.write(data, 0, length + 1); } if (res == 0) { return STATE_BUF_FLUSH; } - } while (byteBuffer.hasRemaining()); + } while (buffer.hasRemaining()); bufferDone(); return STATE_BODY; - } else if (state != STATE_START) { - return processStatefulWrite(state, userData, pos, length); - } - - //merge the cookies into the header map - Connectors.flattenCookies(exchange); - - if(pooledBuffer == null) { - pooledBuffer = pool.allocate(); - } - ByteBuffer buffer = pooledBuffer.getResource(); - - - assert buffer.remaining() >= 0x100; - exchange.getProtocol().appendTo(buffer); - buffer.put((byte) ' '); - int code = exchange.getResponseCode(); - assert 999 >= code && code >= 100; - buffer.put((byte) (code / 100 + '0')); - buffer.put((byte) (code / 10 % 10 + '0')); - buffer.put((byte) (code % 10 + '0')); - buffer.put((byte) ' '); - String string = StatusCodes.getReason(code); - writeString(buffer, string); - buffer.put((byte) '\r').put((byte) '\n'); - - int remaining = buffer.remaining(); - - - HeaderMap headers = exchange.getResponseHeaders(); - long fiCookie = headers.fastIterateNonEmpty(); - while (fiCookie != -1) { - HeaderValues headerValues = headers.fiCurrent(fiCookie); - - HttpString header = headerValues.getHeaderName(); - int headerSize = header.length(); - int valueIdx = 0; - while (valueIdx < headerValues.size()) { - remaining -= (headerSize + 2); - - if (remaining < 0) { - this.fiCookie = fiCookie; - this.string = string; - this.headerValues = headerValues; - this.valueIdx = valueIdx; - this.charIndex = 0; - this.state = STATE_HDR_NAME; - buffer.flip(); - return processStatefulWrite(STATE_HDR_NAME, userData, pos, length); - } - header.appendTo(buffer); - buffer.put((byte) ':').put((byte) ' '); - string = headerValues.get(valueIdx++); - - remaining -= (string.length() + 2); - if (remaining < 2) {//we use 2 here, to make sure we always have room for the final \r\n - this.fiCookie = fiCookie; - this.string = string; - this.headerValues = headerValues; - this.valueIdx = valueIdx; - this.charIndex = 0; - this.state = STATE_HDR_VAL; - buffer.flip(); - return processStatefulWrite(STATE_HDR_VAL, userData, pos ,length); - } - writeString(buffer, string); - buffer.put((byte) '\r').put((byte) '\n'); + } catch (IOException|RuntimeException e) { + //WFLY-4696, just to be safe + if(pooledBuffer != null) { + pooledBuffer.free(); + pooledBuffer = null; } - fiCookie = headers.fiNextNonEmpty(fiCookie); + throw e; } - buffer.put((byte) '\r').put((byte) '\n'); - buffer.flip(); - do { - long res = 0; - ByteBuffer[] data; - if (userData == null) { - res = next.write(buffer); - } else if (userData instanceof ByteBuffer){ - data = writevBuffer; - if(data == null) { - data = writevBuffer = new ByteBuffer[2]; - } - data[0] = buffer; - data[1] = (ByteBuffer) userData; - res = next.write(data, 0, 2); - } else { - data = writevBuffer; - if(data == null || data.length < length + 1) { - data = writevBuffer = new ByteBuffer[length + 1]; - } - data[0] = buffer; - System.arraycopy(userData, pos, data, 1, length); - res = next.write(data, 0, data.length); - } - if (res == 0) { - return STATE_BUF_FLUSH; - } - } while (buffer.hasRemaining()); - bufferDone(); - return STATE_BODY; } private void bufferDone() { @@ -554,29 +562,34 @@ } public int write(final ByteBuffer src) throws IOException { - int oldState = this.state; - int state = oldState & MASK_STATE; - int alreadyWritten = 0; - int originalRemaining = -1; try { - if (state != 0) { - originalRemaining = src.remaining(); - state = processWrite(state, src, -1, -1); + int oldState = this.state; + int state = oldState & MASK_STATE; + int alreadyWritten = 0; + int originalRemaining = -1; + try { if (state != 0) { - return 0; + originalRemaining = src.remaining(); + state = processWrite(state, src, -1, -1); + if (state != 0) { + return 0; + } + alreadyWritten = originalRemaining - src.remaining(); + if (allAreSet(oldState, FLAG_SHUTDOWN)) { + next.terminateWrites(); + throw new ClosedChannelException(); + } } - alreadyWritten = originalRemaining - src.remaining(); - if (allAreSet(oldState, FLAG_SHUTDOWN)) { - next.terminateWrites(); - throw new ClosedChannelException(); + if (alreadyWritten != originalRemaining) { + return next.write(src) + alreadyWritten; } + return alreadyWritten; + } finally { + this.state = oldState & ~MASK_STATE | state; } - if (alreadyWritten != originalRemaining) { - return next.write(src) + alreadyWritten; - } - return alreadyWritten; - } finally { - this.state = oldState & ~MASK_STATE | state; + } catch(IOException|RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; } } @@ -607,27 +620,64 @@ return ret; } return length == 1 ? next.write(srcs[offset]) : next.write(srcs, offset, length); + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; } finally { this.state = oldVal & ~MASK_STATE | state; } } public long transferFrom(final FileChannel src, final long position, final long count) throws IOException { - return src.transferTo(position, count, new ConduitWritableByteChannel(this)); + try { + if (state != 0) { + final Pooled pooled = exchange.getConnection().getBufferPool().allocate(); + ByteBuffer buffer = pooled.getResource(); + try { + int res = src.read(buffer); + if (res <= 0) { + return res; + } + buffer.flip(); + return write(buffer); + } finally { + pooled.free(); + } + } else { + return next.transferFrom(src, position, count); + } + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; + } } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { - return IoUtils.transfer(source, count, throughBuffer, new ConduitWritableByteChannel(this)); + if (state != 0) { + return IoUtils.transfer(source, count, throughBuffer, new ConduitWritableByteChannel(this)); + } else { + return next.transferFrom(source, count, throughBuffer); + } } @Override public int writeFinal(ByteBuffer src) throws IOException { - return Conduits.writeFinalBasic(this, src); + try { + return Conduits.writeFinalBasic(this, src); + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; + } } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { - return Conduits.writeFinalBasic(this, srcs, offset, length); + try { + return Conduits.writeFinalBasic(this, srcs, offset, length); + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; + } } public boolean flush() throws IOException { @@ -645,35 +695,40 @@ } } return next.flush(); + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; } finally { this.state = oldVal & ~MASK_STATE | state; } } public void terminateWrites() throws IOException { - int oldVal = this.state; - if (allAreClear(oldVal, MASK_STATE)) { - next.terminateWrites(); - return; + try { + int oldVal = this.state; + if (allAreClear(oldVal, MASK_STATE)) { + next.terminateWrites(); + return; + } + this.state = oldVal | FLAG_SHUTDOWN; + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; } - this.state = oldVal | FLAG_SHUTDOWN; } public void truncateWrites() throws IOException { - int oldVal = this.state; - if (allAreClear(oldVal, MASK_STATE)) { - try { - next.truncateWrites(); - } finally { - if (pooledBuffer != null) { - bufferDone(); - } + try { + next.truncateWrites(); + } catch (IOException | RuntimeException e) { + IoUtils.safeClose(exchange.getConnection()); + throw e; + } finally { + if (pooledBuffer != null) { + bufferDone(); } - return; } - this.state = oldVal & ~MASK_STATE | FLAG_SHUTDOWN | STATE_BODY; - throw new TruncatedResponseException(); } public XnioWorker getWorker() { Index: 3rdParty_sources/undertow/io/undertow/server/protocol/http/HttpServerConnection.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/protocol/http/Attic/HttpServerConnection.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/protocol/http/HttpServerConnection.java 25 Nov 2014 10:47:00 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/protocol/http/HttpServerConnection.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -76,13 +76,9 @@ addCloseListener(new CloseListener() { @Override public void closed(ServerConnection connection) { - if(getExtraBytes() != null) { - getExtraBytes().free(); - } responseConduit.freeBuffers(); } }); - } @Override Index: 3rdParty_sources/undertow/io/undertow/server/protocol/http/HttpTransferEncoding.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/protocol/http/Attic/HttpTransferEncoding.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/protocol/http/HttpTransferEncoding.java 25 Nov 2014 10:47:00 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/protocol/http/HttpTransferEncoding.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -213,6 +213,11 @@ //this will just discard the data //we still go through with the rest of the logic, to make sure all headers are set correctly channel = new HeadStreamSinkConduit(channel, terminateResponseListener(exchange)); + } else if(!Connectors.isEntityBodyAllowed(exchange)) { + //we are not allowed to send an entity body for some requests + exchange.getResponseHeaders().remove(Headers.CONTENT_LENGTH); + exchange.getResponseHeaders().remove(Headers.TRANSFER_ENCODING); + channel = new HeadStreamSinkConduit(channel, terminateResponseListener(exchange)); } final HeaderMap responseHeaders = exchange.getResponseHeaders(); Index: 3rdParty_sources/undertow/io/undertow/server/protocol/spdy/SpdyReceiveListener.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/protocol/spdy/Attic/SpdyReceiveListener.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/protocol/spdy/SpdyReceiveListener.java 25 Nov 2014 10:47:01 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/protocol/spdy/SpdyReceiveListener.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -31,7 +31,6 @@ import io.undertow.protocols.spdy.SpdySynStreamStreamSourceChannel; import io.undertow.util.Headers; import io.undertow.util.HttpString; -import io.undertow.util.URLUtils; import org.xnio.ChannelListener; import org.xnio.IoUtils; import org.xnio.OptionMap; @@ -101,7 +100,7 @@ exchange.setRequestMethod(new HttpString(exchange.getRequestHeaders().getFirst(METHOD))); exchange.getRequestHeaders().put(Headers.HOST, exchange.getRequestHeaders().getFirst(HOST)); final String path = exchange.getRequestHeaders().getFirst(PATH); - setRequestPath(exchange, path, encoding, allowEncodingSlash, decodeBuffer); + Connectors.setExchangeRequestPath(exchange, path, encoding, decode, allowEncodingSlash, decodeBuffer); SSLSession session = channel.getSslSession(); if(session != null) { @@ -140,71 +139,4 @@ frame.getSpdyChannel().sendPing(id); } } - - - /** - * Sets the request path and query parameters, decoding to the requested charset. - * - * @param exchange The exchange - * @param encodedPath The encoded path - * @param charset The charset - */ - private void setRequestPath(final HttpServerExchange exchange, final String encodedPath, final String charset, final boolean allowEncodedSlash, StringBuilder decodeBuffer) { - boolean requiresDecode = false; - for (int i = 0; i < encodedPath.length(); ++i) { - char c = encodedPath.charAt(i); - if (c == '?') { - String part; - String encodedPart = encodedPath.substring(0, i); - if (requiresDecode) { - part = URLUtils.decode(encodedPart, charset, allowEncodedSlash, decodeBuffer); - } else { - part = encodedPart; - } - exchange.setRequestPath(part); - exchange.setRelativePath(part); - exchange.setRequestURI(encodedPart); - final String qs = encodedPath.substring(i + 1); - exchange.setQueryString(qs); - URLUtils.parseQueryString(qs, exchange, encoding, decode); - return; - } else if(c == ';') { - String part; - String encodedPart = encodedPath.substring(0, i); - if (requiresDecode) { - part = URLUtils.decode(encodedPart, charset, allowEncodedSlash, decodeBuffer); - } else { - part = encodedPart; - } - exchange.setRequestPath(part); - exchange.setRelativePath(part); - exchange.setRequestURI(encodedPart); - for(int j = i; j < encodedPath.length(); ++j) { - if (encodedPath.charAt(j) == '?') { - String pathParams = encodedPath.substring(i + 1, j); - URLUtils.parsePathParms(pathParams, exchange, encoding, decode); - String qs = encodedPath.substring(j + 1); - exchange.setQueryString(qs); - URLUtils.parseQueryString(qs, exchange, encoding, decode); - return; - } - } - URLUtils.parsePathParms(encodedPath.substring(i + 1), exchange, encoding, decode); - return; - } else if(c == '%' || c == '+') { - requiresDecode = true; - } - } - - String part; - if (requiresDecode) { - part = URLUtils.decode(encodedPath, charset, allowEncodedSlash, decodeBuffer); - } else { - part = encodedPath; - } - exchange.setRequestPath(part); - exchange.setRelativePath(part); - exchange.setRequestURI(encodedPath); - } - } Index: 3rdParty_sources/undertow/io/undertow/server/session/InMemorySessionManager.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/session/Attic/InMemorySessionManager.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/session/InMemorySessionManager.java 25 Nov 2014 10:46:57 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/session/InMemorySessionManager.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -235,6 +235,7 @@ private volatile Object evictionToken; private final SessionConfig sessionCookieConfig; private volatile long expireTime = -1; + private volatile boolean invalidationStarted = false; final XnioExecutor executor; final XnioWorker worker; @@ -268,9 +269,13 @@ } synchronized void bumpTimeout() { + if(invalidationStarted) { + return; + } + final int maxInactiveInterval = getMaxInactiveInterval(); if (maxInactiveInterval > 0) { - long newExpireTime = System.currentTimeMillis() + (maxInactiveInterval * 1000); + long newExpireTime = System.currentTimeMillis() + (maxInactiveInterval * 1000L); if(timerCancelKey != null && (newExpireTime < expireTime)) { // We have to re-schedule as the new maxInactiveInterval is lower than the old one if (!timerCancelKey.remove()) { @@ -283,7 +288,7 @@ //+1 second, to make sure that the time has actually expired //we don't re-schedule every time, as it is expensive //instead when it expires we check if the timeout has been bumped, and if so we re-schedule - timerCancelKey = executor.executeAfter(cancelTask, (maxInactiveInterval * 1000) + 1, TimeUnit.MILLISECONDS); + timerCancelKey = executor.executeAfter(cancelTask, (maxInactiveInterval * 1000L) + 1, TimeUnit.MILLISECONDS); } } if (evictionToken != null) { @@ -399,18 +404,21 @@ invalidate(exchange, SessionListener.SessionDestroyedReason.INVALIDATED); } - synchronized void invalidate(final HttpServerExchange exchange, SessionListener.SessionDestroyedReason reason) { - if (timerCancelKey != null) { - timerCancelKey.remove(); - } - InMemorySession sess = sessionManager.sessions.get(sessionId); - if (sess == null) { - if (reason == SessionListener.SessionDestroyedReason.INVALIDATED) { - throw UndertowMessages.MESSAGES.sessionAlreadyInvalidated(); + void invalidate(final HttpServerExchange exchange, SessionListener.SessionDestroyedReason reason) { + synchronized(SessionImpl.this) { + if (timerCancelKey != null) { + timerCancelKey.remove(); } - return; + InMemorySession sess = sessionManager.sessions.get(sessionId); + if (sess == null) { + if (reason == SessionListener.SessionDestroyedReason.INVALIDATED) { + throw UndertowMessages.MESSAGES.sessionAlreadyInvalidated(); + } + return; + } + invalidationStarted = true; } - sessionManager.sessionListeners.sessionDestroyed(sess.session, exchange, reason); + sessionManager.sessionListeners.sessionDestroyed(this, exchange, reason); sessionManager.sessions.remove(sessionId); if (exchange != null) { sessionCookieConfig.clearSession(exchange, this.getId()); Index: 3rdParty_sources/undertow/io/undertow/server/session/PathParameterSessionConfig.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/server/session/Attic/PathParameterSessionConfig.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/server/session/PathParameterSessionConfig.java 25 Nov 2014 10:46:57 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/server/session/PathParameterSessionConfig.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -80,6 +80,7 @@ String path = url; String query = ""; String anchor = ""; + String fragment = ""; int question = url.indexOf('?'); if (question >= 0) { path = url.substring(0, question); @@ -90,9 +91,20 @@ anchor = path.substring(pound); path = path.substring(0, pound); } + int fragmentIndex = url.lastIndexOf(';'); + if(fragmentIndex >= 0) { + fragment = path.substring(fragmentIndex); + path = path.substring(0, fragmentIndex); + } + StringBuilder sb = new StringBuilder(path); if (sb.length() > 0) { // jsessionid can't be first. - sb.append(';'); + if(fragmentIndex > 0) { + sb.append(fragment); + sb.append("&"); + } else { + sb.append(';'); + } sb.append(name.toLowerCase(Locale.ENGLISH)); sb.append('='); sb.append(sessionId); Index: 3rdParty_sources/undertow/io/undertow/servlet/api/DeploymentInfo.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/api/Attic/DeploymentInfo.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/api/DeploymentInfo.java 25 Nov 2014 10:46:56 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/api/DeploymentInfo.java 27 Aug 2015 06:12:25 -0000 1.1.2.3 @@ -207,7 +207,11 @@ } public DeploymentInfo setContextPath(final String contextPath) { - this.contextPath = contextPath; + if(contextPath != null && contextPath.isEmpty()) { + this.contextPath = "/"; //we represent the root context as / instead of "", but both work + } else { + this.contextPath = contextPath; + } return this; } Index: 3rdParty_sources/undertow/io/undertow/servlet/core/DeploymentManagerImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/core/Attic/DeploymentManagerImpl.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/core/DeploymentManagerImpl.java 25 Nov 2014 10:46:47 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/core/DeploymentManagerImpl.java 27 Aug 2015 06:12:25 -0000 1.1.2.3 @@ -159,6 +159,7 @@ } final List setup = new ArrayList<>(); + setup.add(ServletRequestContextThreadSetupAction.INSTANCE); setup.add(new ContextClassLoaderSetupAction(deploymentInfo.getClassLoader())); setup.addAll(deploymentInfo.getThreadSetupActions()); final CompositeThreadSetupAction threadSetupAction = new CompositeThreadSetupAction(setup); Index: 3rdParty_sources/undertow/io/undertow/servlet/core/ErrorPages.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/core/Attic/ErrorPages.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/core/ErrorPages.java 25 Nov 2014 10:46:47 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/core/ErrorPages.java 27 Aug 2015 06:12:25 -0000 1.1.2.3 @@ -18,6 +18,8 @@ package io.undertow.servlet.core; +import io.undertow.util.StatusCodes; + import java.util.Map; import javax.servlet.ServletException; @@ -65,7 +67,7 @@ } } if (location == null) { - location = defaultErrorPage; + location = getErrorLocation(StatusCodes.INTERNAL_SERVER_ERROR); } return location; } Index: 3rdParty_sources/undertow/io/undertow/servlet/core/SecurityActions.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/core/Attic/SecurityActions.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/core/SecurityActions.java 25 Nov 2014 10:46:47 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/core/SecurityActions.java 27 Aug 2015 06:12:25 -0000 1.1.2.3 @@ -125,6 +125,45 @@ } } + static void setCurrentRequestContext(final ServletRequestContext servletRequestContext) { + if (System.getSecurityManager() == null) { + ServletRequestContext.setCurrentRequestContext(servletRequestContext); + } else { + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Object run() { + ServletRequestContext.setCurrentRequestContext(servletRequestContext); + return null; + } + }); + } + } + + static void clearCurrentServletAttachments() { + if (System.getSecurityManager() == null) { + ServletRequestContext.clearCurrentServletAttachments(); + } else { + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Object run() { + ServletRequestContext.clearCurrentServletAttachments(); + return null; + } + }); + } + } + static ServletRequestContext requireCurrentServletRequestContext() { + if (System.getSecurityManager() == null) { + return ServletRequestContext.requireCurrent(); + } else { + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public ServletRequestContext run() { + return ServletRequestContext.requireCurrent(); + } + }); + } + } static ServletInitialHandler createServletInitialHandler(final ServletPathMatches paths, final HttpHandler next, final CompositeThreadSetupAction setupAction, final ServletContextImpl servletContext) { if (System.getSecurityManager() == null) { return new ServletInitialHandler(paths, next, setupAction, servletContext); Index: 3rdParty_sources/undertow/io/undertow/servlet/core/ServletContainerImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/core/Attic/ServletContainerImpl.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/core/ServletContainerImpl.java 25 Nov 2014 10:46:47 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/core/ServletContainerImpl.java 27 Aug 2015 06:12:25 -0000 1.1.2.3 @@ -71,7 +71,8 @@ @Override public DeploymentManager getDeploymentByPath(final String path) { - DeploymentManager exact = deploymentsByPath.get(path); + + DeploymentManager exact = deploymentsByPath.get(path.isEmpty() ? "/" : path); if (exact != null) { return exact; } @@ -88,6 +89,6 @@ } } } - return deploymentsByPath.get(""); + return deploymentsByPath.get("/"); } } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `3rdParty_sources/undertow/io/undertow/servlet/core/ServletRequestContextThreadSetupAction.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/undertow/io/undertow/servlet/handlers/DefaultServlet.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/handlers/Attic/DefaultServlet.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/handlers/DefaultServlet.java 25 Nov 2014 10:46:54 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/handlers/DefaultServlet.java 27 Aug 2015 06:12:24 -0000 1.1.2.3 @@ -33,6 +33,7 @@ import io.undertow.util.ETagUtils; import io.undertow.util.Headers; import io.undertow.util.Methods; +import io.undertow.util.StatusCodes; import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; @@ -129,7 +130,7 @@ protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { String path = getPath(req); if (!isAllowed(path, req.getDispatcherType())) { - resp.sendError(404); + resp.sendError(StatusCodes.NOT_FOUND); return; } if(File.separatorChar != '/') { @@ -143,12 +144,13 @@ } else { resource = null; } + if (resource == null) { if (req.getDispatcherType() == DispatcherType.INCLUDE) { //servlet 9.3 throw new FileNotFoundException(path); } else { - resp.sendError(404); + resp.sendError(StatusCodes.NOT_FOUND); } return; } else if (resource.isDirectory()) { @@ -165,9 +167,14 @@ StringBuilder output = DirectoryUtils.renderDirectoryListing(req.getRequestURI(), resource); resp.getWriter().write(output.toString()); } else { - resp.sendError(403); + resp.sendError(StatusCodes.FORBIDDEN); } } else { + if(path.endsWith("/")) { + //UNDERTOW-432 + resp.sendError(StatusCodes.NOT_FOUND); + return; + } serveFileBlocking(req, resp, resource); } } @@ -243,16 +250,18 @@ private void serveFileBlocking(final HttpServletRequest req, final HttpServletResponse resp, final Resource resource) throws IOException { final ETag etag = resource.getETag(); final Date lastModified = resource.getLastModified(); - if (!ETagUtils.handleIfMatch(req.getHeader(Headers.IF_MATCH_STRING), etag, false) || - !DateUtils.handleIfUnmodifiedSince(req.getHeader(Headers.IF_UNMODIFIED_SINCE_STRING), lastModified)) { - resp.setStatus(412); - return; + if(req.getDispatcherType() != DispatcherType.INCLUDE) { + if (!ETagUtils.handleIfMatch(req.getHeader(Headers.IF_MATCH_STRING), etag, false) || + !DateUtils.handleIfUnmodifiedSince(req.getHeader(Headers.IF_UNMODIFIED_SINCE_STRING), lastModified)) { + resp.setStatus(StatusCodes.PRECONDITION_FAILED); + return; + } + if (!ETagUtils.handleIfNoneMatch(req.getHeader(Headers.IF_NONE_MATCH_STRING), etag, true) || + !DateUtils.handleIfModifiedSince(req.getHeader(Headers.IF_MODIFIED_SINCE_STRING), lastModified)) { + resp.setStatus(StatusCodes.NOT_MODIFIED); + return; + } } - if (!ETagUtils.handleIfNoneMatch(req.getHeader(Headers.IF_NONE_MATCH_STRING), etag, true) || - !DateUtils.handleIfModifiedSince(req.getHeader(Headers.IF_MODIFIED_SINCE_STRING), lastModified)) { - resp.setStatus(304); - return; - } //todo: handle range requests //we are going to proceed. Set the appropriate headers if(resp.getContentType() == null) { @@ -277,7 +286,11 @@ Long contentLength = resource.getContentLength(); if (contentLength != null) { resp.getOutputStream(); - resp.setContentLengthLong(contentLength); + if(contentLength > Integer.MAX_VALUE) { + resp.setContentLengthLong(contentLength); + } else { + resp.setContentLength(contentLength.intValue()); + } } } catch (IllegalStateException e) { Index: 3rdParty_sources/undertow/io/undertow/servlet/handlers/SecurityActions.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/handlers/Attic/SecurityActions.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/handlers/SecurityActions.java 25 Nov 2014 10:46:54 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/handlers/SecurityActions.java 27 Aug 2015 06:12:24 -0000 1.1.2.3 @@ -39,20 +39,6 @@ } } - static void setCurrentRequestContext(final ServletRequestContext servletRequestContext) { - if (System.getSecurityManager() == null) { - ServletRequestContext.setCurrentRequestContext(servletRequestContext); - } else { - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Object run() { - ServletRequestContext.setCurrentRequestContext(servletRequestContext); - return null; - } - }); - } - } - static ServletRequestContext requireCurrentServletRequestContext() { if (System.getSecurityManager() == null) { return ServletRequestContext.requireCurrent(); @@ -65,18 +51,4 @@ }); } } - - static void clearCurrentServletAttachments() { - if (System.getSecurityManager() == null) { - ServletRequestContext.clearCurrentServletAttachments(); - } else { - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Object run() { - ServletRequestContext.clearCurrentServletAttachments(); - return null; - } - }); - } - } } Index: 3rdParty_sources/undertow/io/undertow/servlet/handlers/ServletHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/handlers/Attic/ServletHandler.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/handlers/ServletHandler.java 25 Nov 2014 10:46:54 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/handlers/ServletHandler.java 27 Aug 2015 06:12:24 -0000 1.1.2.3 @@ -34,6 +34,7 @@ import io.undertow.servlet.api.InstanceHandle; import io.undertow.servlet.core.ManagedServlet; import io.undertow.servlet.spec.AsyncContextImpl; +import io.undertow.util.StatusCodes; /** * The handler that is responsible for invoking the servlet @@ -59,15 +60,15 @@ public void handleRequest(final HttpServerExchange exchange) throws IOException, ServletException { if (managedServlet.isPermanentlyUnavailable()) { UndertowServletLogger.REQUEST_LOGGER.debugf("Returning 404 for servlet %s due to permanent unavailability", managedServlet.getServletInfo().getName()); - exchange.setResponseCode(404); + exchange.setResponseCode(StatusCodes.NOT_FOUND); return; } long until = unavailableUntil; if (until != 0) { UndertowServletLogger.REQUEST_LOGGER.debugf("Returning 503 for servlet %s due to temporary unavailability", managedServlet.getServletInfo().getName()); if (System.currentTimeMillis() < until) { - exchange.setResponseCode(503); + exchange.setResponseCode(StatusCodes.SERVICE_UNAVAILABLE); return; } else { unavailableUntilUpdater.compareAndSet(this, until, 0); @@ -99,11 +100,11 @@ UndertowServletLogger.REQUEST_LOGGER.stoppingServletDueToPermanentUnavailability(managedServlet.getServletInfo().getName(), e); managedServlet.stop(); managedServlet.setPermanentlyUnavailable(true); - exchange.setResponseCode(404); + exchange.setResponseCode(StatusCodes.NOT_FOUND); } else { unavailableUntilUpdater.set(this, System.currentTimeMillis() + e.getUnavailableSeconds() * 1000); UndertowServletLogger.REQUEST_LOGGER.stoppingServletUntilDueToTemporaryUnavailability(managedServlet.getServletInfo().getName(), new Date(until), e); - exchange.setResponseCode(503); + exchange.setResponseCode(StatusCodes.SERVICE_UNAVAILABLE); } } finally { if(servlet != null) { Index: 3rdParty_sources/undertow/io/undertow/servlet/handlers/ServletInitialHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/handlers/Attic/ServletInitialHandler.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/handlers/ServletInitialHandler.java 25 Nov 2014 10:46:54 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/handlers/ServletInitialHandler.java 27 Aug 2015 06:12:24 -0000 1.1.2.3 @@ -31,6 +31,7 @@ import io.undertow.servlet.core.ApplicationListeners; import io.undertow.servlet.core.CompositeThreadSetupAction; import io.undertow.servlet.core.ServletBlockingHttpExchange; +import io.undertow.servlet.spec.AsyncContextImpl; import io.undertow.servlet.spec.HttpServletRequestImpl; import io.undertow.servlet.spec.HttpServletResponseImpl; import io.undertow.servlet.spec.RequestDispatcherImpl; @@ -115,7 +116,7 @@ public void handleRequest(final HttpServerExchange exchange) throws Exception { final String path = exchange.getRelativePath(); if(isForbiddenPath(path)) { - exchange.setResponseCode(404); + exchange.setResponseCode(StatusCodes.NOT_FOUND); return; } final ServletPathMatch info = paths.getServletHandlerByPath(path); @@ -129,7 +130,7 @@ if (info.getType() == ServletPathMatch.Type.REDIRECT && !isUpgradeRequest) { //UNDERTOW-89 //we redirect on GET requests to the root context to add an / to the end - exchange.setResponseCode(302); + exchange.setResponseCode(StatusCodes.TEMPORARY_REDIRECT); exchange.getResponseHeaders().put(Headers.LOCATION, RedirectBuilder.redirect(exchange, exchange.getRelativePath() + "/", true)); return; } else if (info.getType() == ServletPathMatch.Type.REWRITE) { @@ -254,7 +255,6 @@ ThreadSetupAction.Handle handle = setupAction.setup(exchange); try { - SecurityActions.setCurrentRequestContext(servletRequestContext); servletRequestContext.setRunningInsideHandler(true); try { listeners.requestInitialized(request); @@ -276,11 +276,11 @@ } else { if (!exchange.isResponseStarted()) { response.reset(); //reset the response - exchange.setResponseCode(500); + exchange.setResponseCode(StatusCodes.INTERNAL_SERVER_ERROR); exchange.getResponseHeaders().clear(); String location = servletContext.getDeployment().getErrorPages().getErrorLocation(t); if (location == null) { - location = servletContext.getDeployment().getErrorPages().getErrorLocation(500); + location = servletContext.getDeployment().getErrorPages().getErrorLocation(StatusCodes.INTERNAL_SERVER_ERROR); } if (location != null) { RequestDispatcherImpl dispatcher = new RequestDispatcherImpl(location, servletContext); @@ -293,7 +293,7 @@ if (servletRequestContext.displayStackTraces()) { ServletDebugPageHandler.handleRequest(exchange, servletRequestContext, t); } else { - servletRequestContext.getOriginalResponse().doErrorDispatch(500, StatusCodes.INTERNAL_SERVER_ERROR_STRING); + servletRequestContext.getOriginalResponse().doErrorDispatch(StatusCodes.INTERNAL_SERVER_ERROR, StatusCodes.INTERNAL_SERVER_ERROR_STRING); } } } @@ -306,13 +306,16 @@ //if it is not dispatched and is not a mock request if (!exchange.isDispatched() && !(exchange.getConnection() instanceof MockServerConnection)) { servletRequestContext.getOriginalResponse().responseDone(); + servletRequestContext.getOriginalRequest().clearAttributes(); } - } finally { - try { - handle.tearDown(); - } finally { - SecurityActions.clearCurrentServletAttachments(); + if(!exchange.isDispatched()) { + AsyncContextImpl ctx = servletRequestContext.getOriginalRequest().getAsyncContextInternal(); + if(ctx != null) { + ctx.complete(); + } } + } finally { + handle.tearDown(); } } Index: 3rdParty_sources/undertow/io/undertow/servlet/handlers/ServletPathMatches.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/handlers/Attic/ServletPathMatches.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/handlers/ServletPathMatches.java 25 Nov 2014 10:46:54 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/handlers/ServletPathMatches.java 27 Aug 2015 06:12:24 -0000 1.1.2.3 @@ -381,10 +381,10 @@ for (final Map.Entry entry : pathServlets.entrySet()) { String key = entry.getKey(); if (key.endsWith("/*")) { - final String base = key.substring(0, key.length() - 2); + final String base = key.substring(0, key.length() - 1); if (match == null || base.length() > match.length()) { if (path.startsWith(base)) { - match = base; + match = base.substring(0, base.length() - 1); servlet = entry.getValue(); } } Index: 3rdParty_sources/undertow/io/undertow/servlet/handlers/security/ServletAuthenticationCallHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/handlers/security/Attic/ServletAuthenticationCallHandler.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/handlers/security/ServletAuthenticationCallHandler.java 25 Nov 2014 10:46:59 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/handlers/security/ServletAuthenticationCallHandler.java 27 Aug 2015 06:12:25 -0000 1.1.2.3 @@ -21,6 +21,7 @@ import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; import io.undertow.servlet.handlers.ServletRequestContext; +import io.undertow.util.StatusCodes; /** * This is the final {@link io.undertow.server.HttpHandler} in the security chain, it's purpose is to act as a barrier at the end of the chain to @@ -56,7 +57,7 @@ next.handleRequest(exchange); } } else { - if(exchange.getResponseCode() >= 400 && !exchange.isComplete()) { + if(exchange.getResponseCode() >= StatusCodes.BAD_REQUEST && !exchange.isComplete()) { ServletRequestContext src = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); src.getOriginalResponse().sendError(exchange.getResponseCode()); } else { Index: 3rdParty_sources/undertow/io/undertow/servlet/handlers/security/ServletConfidentialityConstraintHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/handlers/security/Attic/ServletConfidentialityConstraintHandler.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/handlers/security/ServletConfidentialityConstraintHandler.java 25 Nov 2014 10:46:59 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/handlers/security/ServletConfidentialityConstraintHandler.java 27 Aug 2015 06:12:25 -0000 1.1.2.3 @@ -26,6 +26,7 @@ import io.undertow.servlet.api.ConfidentialPortManager; import io.undertow.servlet.api.TransportGuaranteeType; import io.undertow.servlet.handlers.ServletRequestContext; +import io.undertow.util.StatusCodes; import javax.servlet.http.HttpServletResponse; import java.net.URI; @@ -57,7 +58,7 @@ if (TransportGuaranteeType.REJECTED == transportGuarantee) { HttpServletResponse response = (HttpServletResponse) servletRequestContext.getServletResponse(); - response.sendError(403); + response.sendError(StatusCodes.FORBIDDEN); return; } super.handleRequest(exchange); Index: 3rdParty_sources/undertow/io/undertow/servlet/handlers/security/ServletSecurityRoleHandler.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/handlers/security/Attic/ServletSecurityRoleHandler.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/handlers/security/ServletSecurityRoleHandler.java 25 Nov 2014 10:46:59 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/handlers/security/ServletSecurityRoleHandler.java 27 Aug 2015 06:12:25 -0000 1.1.2.3 @@ -23,6 +23,7 @@ import io.undertow.servlet.api.AuthorizationManager; import io.undertow.servlet.api.SingleConstraintMatch; import io.undertow.servlet.handlers.ServletRequestContext; +import io.undertow.util.StatusCodes; import javax.servlet.DispatcherType; import javax.servlet.ServletRequest; @@ -54,7 +55,7 @@ if (!authorizationManager.canAccessResource(constraints, sc.getAuthenticatedAccount(), servletRequestContext.getCurrentServlet().getManagedServlet().getServletInfo(), servletRequestContext.getOriginalRequest(), servletRequestContext.getDeployment())) { HttpServletResponse response = (HttpServletResponse) servletRequestContext.getServletResponse(); - response.sendError(403); + response.sendError(StatusCodes.FORBIDDEN); return; } } Index: 3rdParty_sources/undertow/io/undertow/servlet/spec/AsyncContextImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/spec/Attic/AsyncContextImpl.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/spec/AsyncContextImpl.java 25 Nov 2014 10:46:47 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/spec/AsyncContextImpl.java 27 Aug 2015 06:12:24 -0000 1.1.2.3 @@ -302,6 +302,7 @@ response.responseDone(); try { servletRequestContext.getOriginalRequest().closeAndDrainRequest(); + servletRequestContext.getOriginalRequest().clearAttributes(); } catch (IOException e) { UndertowLogger.REQUEST_IO_LOGGER.ioException(e); } Index: 3rdParty_sources/undertow/io/undertow/servlet/spec/HttpServletRequestImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/spec/Attic/HttpServletRequestImpl.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/spec/HttpServletRequestImpl.java 25 Nov 2014 10:46:46 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/spec/HttpServletRequestImpl.java 27 Aug 2015 06:12:24 -0000 1.1.2.3 @@ -408,12 +408,10 @@ throw UndertowServletMessages.MESSAGES.authenticationFailed(); } } else { - if(exchange.isResponseStarted()) { - //the auth mechanism commited the response, so we return false - return false; - } else { - //as the response was not commited we throw an exception as per the javadoc + if(!exchange.isResponseStarted() && exchange.getResponseCode() == 200) { throw UndertowServletMessages.MESSAGES.authenticationFailed(); + } else { + return false; } } } @@ -901,7 +899,7 @@ @Override public String getLocalName() { - return exchange.getDestinationAddress().getHostName(); + return exchange.getDestinationAddress().getHostString(); } @Override @@ -1075,9 +1073,24 @@ } private SessionConfig.SessionCookieSource sessionCookieSource() { + HttpSession session = getSession(false); + if(session == null || session.isNew()) { + return SessionConfig.SessionCookieSource.NONE; + } if(sessionCookieSource == null) { sessionCookieSource = originalServletContext.getSessionConfig().sessionCookieSource(exchange); } return sessionCookieSource; } + + @Override + public String toString() { + return "HttpServletRequestImpl [ " + getMethod() + ' ' + getRequestURI() + " ]"; + } + + public void clearAttributes() { + if(attributes != null) { + this.attributes.clear(); + } + } } Index: 3rdParty_sources/undertow/io/undertow/servlet/spec/HttpServletResponseImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/spec/Attic/HttpServletResponseImpl.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/spec/HttpServletResponseImpl.java 25 Nov 2014 10:46:47 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/spec/HttpServletResponseImpl.java 27 Aug 2015 06:12:24 -0000 1.1.2.3 @@ -173,7 +173,7 @@ throw UndertowServletMessages.MESSAGES.responseAlreadyCommited(); } resetBuffer(); - setStatus(302); + setStatus(StatusCodes.FOUND); String realPath; if (location.contains("://")) {//absolute url exchange.getResponseHeaders().put(Headers.LOCATION, location); @@ -530,7 +530,7 @@ writer = null; responseState = ResponseState.NONE; exchange.getResponseHeaders().clear(); - exchange.setResponseCode(200); + exchange.setResponseCode(StatusCodes.OK); treatAsCommitted = false; } @@ -624,7 +624,7 @@ if (isEncodeable(toAbsolute(url))) { return originalServletContext.getSessionConfig().rewriteUrl(url, servletContext.getSession(originalServletContext, exchange, true).getId()); } else { - return (url); + return url; } } @@ -683,7 +683,7 @@ * * @param location Absolute URL to be validated */ - protected boolean isEncodeable(final String location) { + private boolean isEncodeable(final String location) { if (location == null) return (false); @@ -701,10 +701,11 @@ } final HttpSession session = hreq.getSession(false); - if (session == null) - return (false); - if (hreq.isRequestedSessionIdFromCookie()) - return (false); + if (session == null) { + return false; + } else if (!hreq.isRequestedSessionIdFromURL() && !session.isNew()) { + return false; + } return doIsEncodeable(hreq, session, location); } @@ -750,8 +751,8 @@ if (file == null) { return false; } - String tok = originalServletContext.getSessionCookieConfig().getName() + "=" + session.getId(); - if (file.indexOf(tok) >= 0) { + String tok = originalServletContext.getSessionCookieConfig().getName().toLowerCase() + "=" + session.getId(); + if (file.contains(tok)) { return false; } Index: 3rdParty_sources/undertow/io/undertow/servlet/spec/HttpSessionImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/spec/Attic/HttpSessionImpl.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/spec/HttpSessionImpl.java 25 Nov 2014 10:46:46 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/spec/HttpSessionImpl.java 27 Aug 2015 06:12:24 -0000 1.1.2.3 @@ -50,28 +50,30 @@ private final ServletContext servletContext; private final boolean newSession; private volatile boolean invalid; + private final ServletRequestContext servletRequestContext; - private HttpSessionImpl(final Session session, final ServletContext servletContext, final boolean newSession) { + private HttpSessionImpl(final Session session, final ServletContext servletContext, final boolean newSession, ServletRequestContext servletRequestContext) { this.session = session; this.servletContext = servletContext; this.newSession = newSession; + this.servletRequestContext = servletRequestContext; } public static HttpSessionImpl forSession(final Session session, final ServletContext servletContext, final boolean newSession) { // forSession is called by privileged actions only so no need to do it again ServletRequestContext current = ServletRequestContext.current(); if (current == null) { - return new HttpSessionImpl(session, servletContext, newSession); + return new HttpSessionImpl(session, servletContext, newSession, null); } else { HttpSessionImpl httpSession = current.getSession(); if (httpSession == null) { - httpSession = new HttpSessionImpl(session, servletContext, newSession); + httpSession = new HttpSessionImpl(session, servletContext, newSession, current); current.setSession(httpSession); } else { if(httpSession.session != session) { //in some rare cases it may be that there are two different service contexts involved in the one request //in this case we just return a new session rather than using the thread local version - httpSession = new HttpSessionImpl(session, servletContext, newSession); + httpSession = new HttpSessionImpl(session, servletContext, newSession, current); } } return httpSession; @@ -190,11 +192,14 @@ @Override public void invalidate() { invalid = true; - ServletRequestContext current = SecurityActions.currentServletRequestContext(); - if (current == null) { + if (servletRequestContext == null) { session.invalidate(null); } else { - session.invalidate(current.getOriginalRequest().getExchange()); + if(servletRequestContext.getOriginalRequest().getServletContext() == servletContext) { + session.invalidate(servletRequestContext.getOriginalRequest().getExchange()); + } else { + session.invalidate(null); + } } } Index: 3rdParty_sources/undertow/io/undertow/servlet/spec/ServletContextImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/spec/Attic/ServletContextImpl.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/spec/ServletContextImpl.java 25 Nov 2014 10:46:47 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/spec/ServletContextImpl.java 27 Aug 2015 06:12:24 -0000 1.1.2.3 @@ -110,7 +110,8 @@ private volatile Set defaultSessionTrackingModes = new HashSet<>(Arrays.asList(new SessionTrackingMode[]{SessionTrackingMode.COOKIE, SessionTrackingMode.URL})); private volatile SessionConfig sessionConfig; private volatile boolean initialized = false; - private int filterMappingInsertPosition = 0; + private int filterMappingUrlPatternInsertPosition = 0; + private int filterMappingServletNameInsertPosition = 0; public ServletContextImpl(final ServletContainer servletContainer, final Deployment deployment) { @@ -829,11 +830,11 @@ } } } else { - if(dispatcherTypes == null || dispatcherTypes.isEmpty()) { - deploymentInfo.insertFilterServletNameMapping(filterMappingInsertPosition++, filterInfo.getName(), servlet, DispatcherType.REQUEST); + if (dispatcherTypes == null || dispatcherTypes.isEmpty()) { + deploymentInfo.insertFilterServletNameMapping(filterMappingServletNameInsertPosition++, filterInfo.getName(), servlet, DispatcherType.REQUEST); } else { - for(final DispatcherType dispatcher : dispatcherTypes) { - deploymentInfo.insertFilterServletNameMapping(filterMappingInsertPosition++, filterInfo.getName(), servlet, dispatcher); + for (final DispatcherType dispatcher : dispatcherTypes) { + deploymentInfo.insertFilterServletNameMapping(filterMappingServletNameInsertPosition++, filterInfo.getName(), servlet, dispatcher); } } } @@ -853,15 +854,15 @@ } } } else { - if(dispatcherTypes == null || dispatcherTypes.isEmpty()) { - deploymentInfo.insertFilterUrlMapping(filterMappingInsertPosition++, filterInfo.getName(), url, DispatcherType.REQUEST); + if (dispatcherTypes == null || dispatcherTypes.isEmpty()) { + deploymentInfo.insertFilterUrlMapping(filterMappingUrlPatternInsertPosition++, filterInfo.getName(), url, DispatcherType.REQUEST); } else { - for(final DispatcherType dispatcher : dispatcherTypes) { - deploymentInfo.insertFilterUrlMapping(filterMappingInsertPosition++, filterInfo.getName(), url, dispatcher); + for (final DispatcherType dispatcher : dispatcherTypes) { + deploymentInfo.insertFilterUrlMapping(filterMappingUrlPatternInsertPosition++, filterInfo.getName(), url, dispatcher); } } } } deployment.getServletPaths().invalidate(); } -} +} \ No newline at end of file Index: 3rdParty_sources/undertow/io/undertow/servlet/spec/ServletInputStreamImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/spec/Attic/ServletInputStreamImpl.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/spec/ServletInputStreamImpl.java 25 Nov 2014 10:46:47 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/spec/ServletInputStreamImpl.java 27 Aug 2015 06:12:24 -0000 1.1.2.3 @@ -240,6 +240,7 @@ if (anyAreSet(state, FLAG_CLOSED)) { return; } + this.state = state | FLAG_CLOSED; try { while (allAreClear(state, FLAG_FINISHED)) { readIntoBuffer(); @@ -249,13 +250,13 @@ } } } finally { + state |= FLAG_FINISHED; if (pooled != null) { pooled.free(); pooled = null; } + channel.shutdownReads(); } - channel.shutdownReads(); - state |= FLAG_FINISHED | FLAG_CLOSED; } private class ServletInputStreamChannelListener implements ChannelListener { Index: 3rdParty_sources/undertow/io/undertow/servlet/spec/ServletOutputStreamImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/spec/Attic/ServletOutputStreamImpl.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/spec/ServletOutputStreamImpl.java 25 Nov 2014 10:46:47 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/spec/ServletOutputStreamImpl.java 27 Aug 2015 06:12:24 -0000 1.1.2.3 @@ -608,6 +608,9 @@ channel.shutdownWrites(); Channels.flushBlocking(channel); } + } catch (IOException e) { + IoUtils.safeClose(this.channel); + throw e; } finally { if (pooledBuffer != null) { pooledBuffer.free(); @@ -670,9 +673,8 @@ private void createChannel() { if (channel == null) { channel = servletRequestContext.getExchange().getResponseChannel(); - channel.getWriteSetter().set(internalListener); if(internalListener != null) { - channel.resumeWrites(); + channel.getWriteSetter().set(internalListener); } } } @@ -743,16 +745,23 @@ //so we don't have to force the creation of the response channel //under normal circumstances this will break write listener delegation this.internalListener = new WriteChannelListener(); + if(this.channel != null) { + this.channel.getWriteSetter().set(internalListener); + } //we resume from an async task, after the request has been dispatched asyncContext.addAsyncTask(new Runnable() { @Override public void run() { - servletRequestContext.getExchange().getIoThread().execute(new Runnable() { - @Override - public void run() { - internalListener.handleEvent(null); - } - }); + if(channel == null) { + servletRequestContext.getExchange().getIoThread().execute(new Runnable() { + @Override + public void run() { + internalListener.handleEvent(null); + } + }); + } else { + channel.resumeWrites(); + } } }); } @@ -783,18 +792,20 @@ long toWrite = Buffers.remaining(buffersToWrite); long written = 0; long res; - do { - try { - res = channel.write(buffersToWrite); - written += res; - if (res == 0) { + if(toWrite > 0) { //should always be true, but just to be defensive + do { + try { + res = channel.write(buffersToWrite); + written += res; + if (res == 0) { + return; + } + } catch (IOException e) { + handleError(e); return; } - } catch (IOException e) { - handleError(e); - return; - } - } while (written < toWrite); + } while (written < toWrite); + } buffersToWrite = null; buffer.clear(); } @@ -835,11 +846,11 @@ } } else { - if (asyncContext.isDispatched()) { //this is no longer an async request //we just return for now //TODO: what do we do here? Revert back to blocking mode? + channel.suspendWrites(); return; } @@ -860,6 +871,10 @@ if(channel != null) { channel.suspendWrites(); } + } else { + if(channel != null) { + channel.resumeWrites(); + } } } catch (Throwable e) { IoUtils.safeClose(channel); Index: 3rdParty_sources/undertow/io/undertow/servlet/spec/SessionCookieConfigImpl.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/spec/Attic/SessionCookieConfigImpl.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/spec/SessionCookieConfigImpl.java 25 Nov 2014 10:46:47 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/spec/SessionCookieConfigImpl.java 27 Aug 2015 06:12:24 -0000 1.1.2.3 @@ -40,6 +40,9 @@ @Override public String rewriteUrl(final String originalUrl, final String sessionid) { + if(fallback != null) { + return fallback.rewriteUrl(originalUrl, sessionid); + } return originalUrl; } Index: 3rdParty_sources/undertow/io/undertow/servlet/util/SavedRequest.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/util/Attic/SavedRequest.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/util/SavedRequest.java 25 Nov 2014 10:47:01 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/util/SavedRequest.java 27 Aug 2015 06:12:24 -0000 1.1.2.3 @@ -37,7 +37,11 @@ import java.io.Serializable; import java.nio.ByteBuffer; import java.security.AccessController; +import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; +import java.util.List; +import java.util.Map; /** * Saved servlet request. @@ -51,15 +55,17 @@ private final byte[] data; private final int dataLength; private final HttpString method; - private final String requestUri; - private final HeaderMap headerMap; + private final String requestPath; + private final HashMap> headerMap = new HashMap<>(); - public SavedRequest(byte[] data, int dataLength, HttpString method, String requestUri, HeaderMap headerMap) { + public SavedRequest(byte[] data, int dataLength, HttpString method, String requestPath, HeaderMap headerMap) { this.data = data; this.dataLength = dataLength; this.method = method; - this.requestUri = requestUri; - this.headerMap = headerMap; + this.requestPath = requestPath; + for(HeaderValues val : headerMap) { + this.headerMap.put(val.getHeaderName(), new ArrayList<>(val)); + } } public static void trySaveRequest(final HttpServerExchange exchange) { @@ -95,7 +101,7 @@ } headers.putAll(entry.getHeaderName(), entry); } - SavedRequest request = new SavedRequest(buffer, read, exchange.getRequestMethod(), exchange.getRequestURI(), exchange.getRequestHeaders()); + SavedRequest request = new SavedRequest(buffer, read, exchange.getRequestMethod(), exchange.getRequestPath(), exchange.getRequestHeaders()); final ServletRequestContext sc = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); HttpSessionImpl session = sc.getCurrentServletContext().getSession(exchange, true); Session underlyingSession; @@ -123,8 +129,8 @@ } SavedRequest request = (SavedRequest) underlyingSession.getAttribute(SESSION_KEY); if(request != null) { - if(request.requestUri.equals(exchange.getRequestURI()) && exchange.isRequestComplete()) { - UndertowLogger.REQUEST_LOGGER.debugf("restoring request body for request to %s", request.requestUri); + if(request.requestPath.equals(exchange.getRequestPath()) && exchange.isRequestComplete()) { + UndertowLogger.REQUEST_LOGGER.debugf("restoring request body for request to %s", request.requestPath); exchange.setRequestMethod(request.method); Connectors.ungetRequestBytes(exchange, new ImmediatePooled<>(ByteBuffer.wrap(request.data, 0, request.dataLength))); underlyingSession.removeAttribute(SESSION_KEY); @@ -137,8 +143,8 @@ headerIterator.remove(); } } - for(HeaderValues header : request.headerMap) { - exchange.getRequestHeaders().putAll(header.getHeaderName(), header); + for(Map.Entry> header : request.headerMap.entrySet()) { + exchange.getRequestHeaders().putAll(header.getKey(), header.getValue()); } } } Index: 3rdParty_sources/undertow/io/undertow/servlet/websockets/WebSocketServlet.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/servlet/websockets/Attic/WebSocketServlet.java,v diff -u -r1.1.2.2 -r1.1.2.3 --- 3rdParty_sources/undertow/io/undertow/servlet/websockets/WebSocketServlet.java 25 Nov 2014 10:47:02 -0000 1.1.2.2 +++ 3rdParty_sources/undertow/io/undertow/servlet/websockets/WebSocketServlet.java 27 Aug 2015 06:12:25 -0000 1.1.2.3 @@ -22,6 +22,7 @@ import io.undertow.server.HttpServerExchange; import io.undertow.server.HttpUpgradeListener; import io.undertow.servlet.UndertowServletMessages; +import io.undertow.util.StatusCodes; import io.undertow.websockets.WebSocketConnectionCallback; import io.undertow.websockets.core.WebSocketChannel; import io.undertow.websockets.core.protocol.Handshake; @@ -104,7 +105,7 @@ if (handshaker == null) { UndertowLogger.REQUEST_LOGGER.debug("Could not find hand shaker for web socket request"); - resp.sendError(400); + resp.sendError(StatusCodes.BAD_REQUEST); return; } final Handshake selected = handshaker; Index: 3rdParty_sources/undertow/io/undertow/util/Cookies.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/util/Attic/Cookies.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/util/Cookies.java 25 Nov 2014 10:46:50 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/util/Cookies.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -18,6 +18,7 @@ package io.undertow.util; +import io.undertow.UndertowLogger; import io.undertow.UndertowMessages; import io.undertow.server.handlers.Cookie; import io.undertow.server.handlers.CookieImpl; @@ -227,7 +228,11 @@ start = i + 1; state = 2; } else if (c == ';') { - cookieCount = createCookie(name, cookie.substring(start, i), maxCookies, cookieCount, cookies, additional); + if(name != null) { + cookieCount = createCookie(name, cookie.substring(start, i), maxCookies, cookieCount, cookies, additional); + } else if(UndertowLogger.REQUEST_LOGGER.isTraceEnabled()) { + UndertowLogger.REQUEST_LOGGER.trace("Ignoring invalid cookies in header " + cookie); + } state = 0; start = i + 1; } Index: 3rdParty_sources/undertow/io/undertow/util/DateUtils.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/util/Attic/DateUtils.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/util/DateUtils.java 25 Nov 2014 10:46:51 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/util/DateUtils.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -54,7 +54,6 @@ @Override protected SimpleDateFormat initialValue() { SimpleDateFormat df = new SimpleDateFormat(RFC1123_PATTERN, LOCALE_US); - df.setTimeZone(GMT_ZONE); return df; } }; @@ -94,7 +93,12 @@ * @return The RFC-1123 formatted date */ public static String toDateString(final Date date) { - return RFC1123_PATTERN_FORMAT.get().format(date); + SimpleDateFormat df = RFC1123_PATTERN_FORMAT.get(); + //we always need to set the time zone + //because date format is stupid, and calling parse() can mutate the timezone + //see UNDERTOW-458 + df.setTimeZone(GMT_ZONE); + return df.format(date); } @@ -128,6 +132,7 @@ ParsePosition pp = new ParsePosition(0); SimpleDateFormat dateFormat = RFC1123_PATTERN_FORMAT.get(); + dateFormat.setTimeZone(GMT_ZONE); Date val = dateFormat.parse(trimmedDate, pp); if (val != null && pp.getIndex() == trimmedDate.length()) { return val; Index: 3rdParty_sources/undertow/io/undertow/util/FlexBase64.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/util/Attic/FlexBase64.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/util/FlexBase64.java 25 Nov 2014 10:46:50 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/util/FlexBase64.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -1046,6 +1046,7 @@ break; } else if (b != ' ' && b != '\t' && b != '\r') { pos--; + break; } Index: 3rdParty_sources/undertow/io/undertow/util/HeaderMap.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/util/Attic/HeaderMap.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/util/HeaderMap.java 25 Nov 2014 10:46:51 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/util/HeaderMap.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -411,8 +411,10 @@ while (ri < len) { final Object item = table[ri]; if (item != null) { - if (item instanceof HeaderValues && !((HeaderValues) item).isEmpty()) { - return (long)ri << 32L; + if (item instanceof HeaderValues) { + if(!((HeaderValues) item).isEmpty()) { + return (long) ri << 32L; + } } else { final HeaderValues[] row = (HeaderValues[]) item; ci = 0; Index: 3rdParty_sources/undertow/io/undertow/util/Headers.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/util/Attic/Headers.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/util/Headers.java 25 Nov 2014 10:46:50 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/util/Headers.java 27 Aug 2015 06:12:25 -0000 1.1.2.4 @@ -105,6 +105,8 @@ public static final String X_FORWARDED_PROTO_STRING = "X-Forwarded-Proto"; public static final String X_FORWARDED_HOST_STRING = "X-Forwarded-Host"; public static final String X_FORWARDED_PORT_STRING = "X-Forwarded-Port"; + public static final String X_DISABLE_PUSH_STRING = "X-Disable-Push"; + public static final String X_FORWARDED_SERVER_STRING = "X-Forwarded-Server"; // Header names @@ -179,10 +181,12 @@ public static final HttpString VIA = new HttpString(VIA_STRING, 64); public static final HttpString WARNING = new HttpString(WARNING_STRING, 65); public static final HttpString WWW_AUTHENTICATE = new HttpString(WWW_AUTHENTICATE_STRING, 66); - public static final HttpString X_FORWARDED_FOR = new HttpString(X_FORWARDED_FOR_STRING, 67); - public static final HttpString X_FORWARDED_HOST = new HttpString(X_FORWARDED_HOST_STRING, 68); - public static final HttpString X_FORWARDED_PORT = new HttpString(X_FORWARDED_PORT_STRING, 69); - public static final HttpString X_FORWARDED_PROTO = new HttpString(X_FORWARDED_PROTO_STRING, 70); + public static final HttpString X_DISABLE_PUSH = new HttpString(X_DISABLE_PUSH_STRING, 67); + public static final HttpString X_FORWARDED_FOR = new HttpString(X_FORWARDED_FOR_STRING, 68); + public static final HttpString X_FORWARDED_HOST = new HttpString(X_FORWARDED_HOST_STRING, 69); + public static final HttpString X_FORWARDED_PORT = new HttpString(X_FORWARDED_PORT_STRING, 70); + public static final HttpString X_FORWARDED_PROTO = new HttpString(X_FORWARDED_PROTO_STRING, 71); + public static final HttpString X_FORWARDED_SERVER = new HttpString(X_FORWARDED_SERVER_STRING, 72); // Content codings @@ -251,7 +255,7 @@ int start = pos + key.length() + 1; for (end = start; end < header.length(); ++end) { char c = header.charAt(end); - if (c == ' ' || c == '\t') { + if (c == ' ' || c == '\t' || c == ';') { break; } } Index: 3rdParty_sources/undertow/io/undertow/websockets/client/WebSocketClient.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/undertow/io/undertow/websockets/client/Attic/WebSocketClient.java,v diff -u -r1.1.2.3 -r1.1.2.4 --- 3rdParty_sources/undertow/io/undertow/websockets/client/WebSocketClient.java 25 Nov 2014 10:47:01 -0000 1.1.2.3 +++ 3rdParty_sources/undertow/io/undertow/websockets/client/WebSocketClient.java 27 Aug 2015 06:12:24 -0000 1.1.2.4 @@ -64,15 +64,16 @@ public static IoFuture connect(XnioWorker worker, XnioSsl ssl, final Pool bufferPool, final OptionMap optionMap, final URI uri, WebSocketVersion version, WebSocketClientNegotiation clientNegotiation) { final FutureResult ioFuture = new FutureResult<>(); + final String scheme = uri.getScheme().equals("wss") ? "https" : "http"; final URI newUri; try { - newUri = new URI(uri.getScheme().equals("wss") ? "https" : "http", uri.getUserInfo(), uri.getHost(), uri.getPort() == -1 ? (uri.getScheme().equals("wss") ? 443 : 80) : uri.getPort(), uri.getPath().isEmpty() ? "/" : uri.getPath(), uri.getQuery(), uri.getFragment()); + newUri = new URI(scheme, uri.getUserInfo(), uri.getHost(), uri.getPort() == -1 ? (uri.getScheme().equals("wss") ? 443 : 80) : uri.getPort(), uri.getPath().isEmpty() ? "/" : uri.getPath(), uri.getQuery(), uri.getFragment()); } catch (URISyntaxException e) { throw new RuntimeException(e); } final WebSocketClientHandshake handshake = WebSocketClientHandshake.create(version, newUri, clientNegotiation); final Map originalHeaders = handshake.createHeaders(); - originalHeaders.put(Headers.ORIGIN_STRING, uri.getHost()); + originalHeaders.put(Headers.ORIGIN_STRING, scheme + "://" + uri.getHost()); final Map> headers = new HashMap<>(); for(Map.Entry entry : originalHeaders.entrySet()) { List list = new ArrayList<>();