1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.client;
20
21 import java.io.Closeable;
22 import java.nio.ByteBuffer;
23 import java.util.Collections;
24 import java.util.Iterator;
25
26 import org.eclipse.jetty.client.api.ContentProvider;
27 import org.eclipse.jetty.util.BufferUtil;
28 import org.eclipse.jetty.util.Callback;
29 import org.eclipse.jetty.util.log.Log;
30 import org.eclipse.jetty.util.log.Logger;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 public class HttpContent implements Callback, Closeable
67 {
68 private static final Logger LOG = Log.getLogger(HttpContent.class);
69 private static final ByteBuffer AFTER = ByteBuffer.allocate(0);
70 private static final ByteBuffer CLOSE = ByteBuffer.allocate(0);
71
72 private final ContentProvider provider;
73 private final Iterator<ByteBuffer> iterator;
74 private ByteBuffer buffer;
75 private ByteBuffer content;
76 private boolean last;
77
78 public HttpContent(ContentProvider provider)
79 {
80 this.provider = provider;
81 this.iterator = provider == null ? Collections.<ByteBuffer>emptyIterator() : provider.iterator();
82 }
83
84
85
86
87 public boolean hasContent()
88 {
89 return provider != null;
90 }
91
92
93
94
95 public boolean isLast()
96 {
97 return last;
98 }
99
100
101
102
103 public ByteBuffer getByteBuffer()
104 {
105 return buffer;
106 }
107
108
109
110
111 public ByteBuffer getContent()
112 {
113 return content;
114 }
115
116
117
118
119
120
121
122
123
124
125
126
127 public boolean advance()
128 {
129 if (iterator instanceof Synchronizable)
130 {
131 synchronized (((Synchronizable)iterator).getLock())
132 {
133 return advance(iterator);
134 }
135 }
136 else
137 {
138 return advance(iterator);
139 }
140 }
141
142 private boolean advance(Iterator<ByteBuffer> iterator)
143 {
144 boolean hasNext = iterator.hasNext();
145 ByteBuffer bytes = hasNext ? iterator.next() : null;
146 boolean hasMore = hasNext && iterator.hasNext();
147 boolean wasLast = last;
148 last = !hasMore;
149
150 if (hasNext)
151 {
152 buffer = bytes;
153 content = bytes == null ? null : bytes.slice();
154 if (LOG.isDebugEnabled())
155 LOG.debug("Advanced content to {} chunk {}", hasMore ? "next" : "last", String.valueOf(bytes));
156 return bytes != null;
157 }
158 else
159 {
160
161 if (wasLast)
162 {
163 buffer = content = AFTER;
164 if (LOG.isDebugEnabled())
165 LOG.debug("Advanced content past last chunk");
166 }
167 else
168 {
169 buffer = content = CLOSE;
170 if (LOG.isDebugEnabled())
171 LOG.debug("Advanced content to last chunk");
172 }
173 return false;
174 }
175 }
176
177
178
179
180 public boolean isConsumed()
181 {
182 return buffer == AFTER;
183 }
184
185 @Override
186 public void succeeded()
187 {
188 if (isConsumed())
189 return;
190 if (buffer == CLOSE)
191 return;
192 if (iterator instanceof Callback)
193 ((Callback)iterator).succeeded();
194 }
195
196 @Override
197 public void failed(Throwable x)
198 {
199 if (isConsumed())
200 return;
201 if (buffer == CLOSE)
202 return;
203 if (iterator instanceof Callback)
204 ((Callback)iterator).failed(x);
205 }
206
207 @Override
208 public void close()
209 {
210 try
211 {
212 if (iterator instanceof Closeable)
213 ((Closeable)iterator).close();
214 }
215 catch (Throwable x)
216 {
217 LOG.ignore(x);
218 }
219 }
220
221 @Override
222 public String toString()
223 {
224 return String.format("%s@%x - has=%b,last=%b,consumed=%b,buffer=%s",
225 getClass().getSimpleName(),
226 hashCode(),
227 hasContent(),
228 isLast(),
229 isConsumed(),
230 BufferUtil.toDetailString(getContent()));
231 }
232 }