diff options
Diffstat (limited to 'jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java')
-rw-r--r-- | jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java | 59 |
1 files changed, 37 insertions, 22 deletions
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java index 237b835d62..1d01f0637c 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java @@ -33,7 +33,7 @@ import org.eclipse.jetty.util.log.Logger; * {@link HttpContent} is a stateful, linear representation of the request content provided * by a {@link ContentProvider} that can be traversed one-way to obtain content buffers to * send to a HTTP server. - * <p /> + * <p> * {@link HttpContent} offers the notion of a one-way cursor to traverse the content. * The cursor starts in a virtual "before" position and can be advanced using {@link #advance()} * until it reaches a virtual "after" position where the content is fully consumed. @@ -42,7 +42,7 @@ import org.eclipse.jetty.util.log.Logger; * | | | | | | | | | | * +---+ +---+ +---+ +---+ +---+ * ^ ^ ^ ^ - * | | --> advance() | | + * | | --> advance() | | * | | last | * | | | * before | after @@ -57,7 +57,7 @@ import org.eclipse.jetty.util.log.Logger; * </ul> * {@link HttpContent} may not have content, if the related {@link ContentProvider} is {@code null}, and this * is reflected by {@link #hasContent()}. - * <p /> + * <p> * {@link HttpContent} may have {@link AsyncContentProvider deferred content}, in which case {@link #advance()} * moves the cursor to a position that provides {@code null} {@link #getByteBuffer() buffer} and * {@link #getContent() content}. When the deferred content is available, a further call to {@link #advance()} @@ -67,11 +67,13 @@ public class HttpContent implements Callback, Closeable { private static final Logger LOG = Log.getLogger(HttpContent.class); private static final ByteBuffer AFTER = ByteBuffer.allocate(0); + private static final ByteBuffer CLOSE = ByteBuffer.allocate(0); private final ContentProvider provider; private final Iterator<ByteBuffer> iterator; private ByteBuffer buffer; - private volatile ByteBuffer content; + private ByteBuffer content; + private boolean last; public HttpContent(ContentProvider provider) { @@ -92,7 +94,7 @@ public class HttpContent implements Callback, Closeable */ public boolean isLast() { - return !iterator.hasNext(); + return last; } /** @@ -113,52 +115,61 @@ public class HttpContent implements Callback, Closeable /** * Advances the cursor to the next block of content. - * <p /> + * <p> * The next block of content may be valid (which yields a non-null buffer * returned by {@link #getByteBuffer()}), but may also be deferred * (which yields a null buffer returned by {@link #getByteBuffer()}). - * <p /> + * <p> * If the block of content pointed by the new cursor position is valid, this method returns true. * * @return true if there is content at the new cursor's position, false otherwise. */ public boolean advance() { - boolean advanced; - boolean hasNext; - ByteBuffer bytes; if (iterator instanceof Synchronizable) { synchronized (((Synchronizable)iterator).getLock()) { - advanced = iterator.hasNext(); - bytes = advanced ? iterator.next() : null; - hasNext = advanced && iterator.hasNext(); + return advance(iterator); } } else { - advanced = iterator.hasNext(); - bytes = advanced ? iterator.next() : null; - hasNext = advanced && iterator.hasNext(); + return advance(iterator); } + } + + private boolean advance(Iterator<ByteBuffer> iterator) + { + boolean hasNext = iterator.hasNext(); + ByteBuffer bytes = hasNext ? iterator.next() : null; + boolean hasMore = hasNext && iterator.hasNext(); + boolean wasLast = last; + last = !hasMore; - if (advanced) + if (hasNext) { buffer = bytes; content = bytes == null ? null : bytes.slice(); if (LOG.isDebugEnabled()) - LOG.debug("Advanced content to {} chunk {}", hasNext ? "next" : "last", bytes); + LOG.debug("Advanced content to {} chunk {}", hasMore ? "next" : "last", String.valueOf(bytes)); return bytes != null; } else { - if (content != AFTER) + // No more content, but distinguish between last and consumed. + if (wasLast) { - content = buffer = AFTER; + buffer = content = AFTER; if (LOG.isDebugEnabled()) LOG.debug("Advanced content past last chunk"); } + else + { + buffer = content = CLOSE; + if (LOG.isDebugEnabled()) + LOG.debug("Advanced content to last chunk"); + } return false; } } @@ -168,7 +179,7 @@ public class HttpContent implements Callback, Closeable */ public boolean isConsumed() { - return content == AFTER; + return buffer == AFTER; } @Override @@ -176,6 +187,8 @@ public class HttpContent implements Callback, Closeable { if (isConsumed()) return; + if (buffer == CLOSE) + return; if (iterator instanceof Callback) ((Callback)iterator).succeeded(); } @@ -185,6 +198,8 @@ public class HttpContent implements Callback, Closeable { if (isConsumed()) return; + if (buffer == CLOSE) + return; if (iterator instanceof Callback) ((Callback)iterator).failed(x); } @@ -197,7 +212,7 @@ public class HttpContent implements Callback, Closeable if (iterator instanceof Closeable) ((Closeable)iterator).close(); } - catch (Exception x) + catch (Throwable x) { LOG.ignore(x); } |