Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
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.java59
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() | |
+ * | | --&gt; 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);
}

Back to the top