24
24
import io .netty .buffer .ByteBufAllocator ;
25
25
import io .netty .buffer .Unpooled ;
26
26
import io .netty .channel .Channel ;
27
- import io .netty .channel .ChannelFuture ;
28
27
import io .netty .channel .ChannelFutureListener ;
29
28
import io .netty .channel .ChannelHandlerContext ;
30
29
import io .netty .channel .ChannelPipeline ;
@@ -137,12 +136,7 @@ public void sendFile(File file, HttpHeaders headers) throws IOException {
137
136
// The FileRegion will close the file channel when it is done sending.
138
137
FileRegion region = new DefaultFileRegion (raf .getChannel (), 0 , file .length ());
139
138
channel .write (region );
140
- channel .writeAndFlush (LastHttpContent .EMPTY_LAST_CONTENT ).addListener (new ChannelFutureListener () {
141
- @ Override
142
- public void operationComplete (ChannelFuture future ) {
143
- completion .run ();
144
- }
145
- });
139
+ channel .writeAndFlush (LastHttpContent .EMPTY_LAST_CONTENT ).addListener (future -> completion .run ());
146
140
} catch (Throwable t ) {
147
141
completion .run ();
148
142
throw t ;
@@ -188,18 +182,14 @@ public void sendContent(HttpResponseStatus status, final BodyProducer bodyProduc
188
182
checkNotResponded ();
189
183
190
184
// Streams the data produced by the given BodyProducer
191
- channel .writeAndFlush (response ).addListener (new ChannelFutureListener () {
192
-
193
- @ Override
194
- public void operationComplete (ChannelFuture future ) throws Exception {
195
- if (!future .isSuccess ()) {
196
- callBodyProducerHandleError (bodyProducer , future .cause ());
197
- channel .close ();
198
- return ;
199
- }
200
- channel .writeAndFlush (new HttpChunkedInput (new BodyProducerChunkedInput (bodyProducer , contentLength )))
201
- .addListener (createBodyProducerCompletionListener (bodyProducer ));
185
+ channel .writeAndFlush (response ).addListener (future -> {
186
+ if (!future .isSuccess ()) {
187
+ callBodyProducerHandleError (bodyProducer , future .cause ());
188
+ channel .close ();
189
+ return ;
202
190
}
191
+ channel .writeAndFlush (new HttpChunkedInput (new BodyProducerChunkedInput (bodyProducer , contentLength )))
192
+ .addListener (createBodyProducerCompletionListener (bodyProducer ));
203
193
});
204
194
}
205
195
@@ -211,21 +201,18 @@ boolean isResponded() {
211
201
}
212
202
213
203
private ChannelFutureListener createBodyProducerCompletionListener (final BodyProducer bodyProducer ) {
214
- return new ChannelFutureListener () {
215
- @ Override
216
- public void operationComplete (ChannelFuture future ) throws Exception {
217
- if (!future .isSuccess ()) {
218
- callBodyProducerHandleError (bodyProducer , future .cause ());
219
- channel .close ();
220
- return ;
221
- }
204
+ return future -> {
205
+ if (!future .isSuccess ()) {
206
+ callBodyProducerHandleError (bodyProducer , future .cause ());
207
+ channel .close ();
208
+ return ;
209
+ }
222
210
223
- try {
224
- bodyProducer .finished ();
225
- } catch (Throwable t ) {
226
- callBodyProducerHandleError (bodyProducer , t );
227
- channel .close ();
228
- }
211
+ try {
212
+ bodyProducer .finished ();
213
+ } catch (Throwable t ) {
214
+ callBodyProducerHandleError (bodyProducer , t );
215
+ channel .close ();
229
216
}
230
217
};
231
218
}
@@ -256,19 +243,11 @@ private Runnable prepareSendFile(Channel channel) {
256
243
try {
257
244
final ChannelPipeline pipeline = channel .pipeline ();
258
245
pipeline .remove ("compressor" );
259
- return new Runnable () {
260
- @ Override
261
- public void run () {
262
- pipeline .addAfter ("codec" , "compressor" , new HttpContentCompressor ());
263
- }
264
- };
246
+ return () -> pipeline .addAfter ("codec" , "compressor" , new HttpContentCompressor ());
265
247
} catch (NoSuchElementException e ) {
266
248
// Ignore if there is no compressor
267
- return new Runnable () {
268
- @ Override
269
- public void run () {
270
- // no-op
271
- }
249
+ return () -> {
250
+ // no-op
272
251
};
273
252
}
274
253
}
@@ -299,9 +278,19 @@ public boolean isEndOfInput() throws Exception {
299
278
}
300
279
301
280
completed = !nextChunk .isReadable ();
302
- if (completed && length >= 0 && bytesProduced != length ) {
303
- throw new IllegalStateException ("Body size doesn't match with content length. " +
304
- "Content-Length: " + length + ", bytes produced: " + bytesProduced );
281
+ if (completed ) {
282
+ try {
283
+ if (length >= 0 && bytesProduced != length ) {
284
+ throw new IllegalStateException ("Body size doesn't match with content length. " +
285
+ "Content-Length: " + length + ", bytes produced: " + bytesProduced );
286
+ }
287
+ } finally {
288
+ // We should release the buffer if it is completed since this will be the last place that uses the buffer,
289
+ // as the buffer won't be returned by the readChunk method.
290
+ // Also, the buffer won't get double released since this method entrance is protected by the `completed`
291
+ // field.
292
+ nextChunk .release ();
293
+ }
305
294
}
306
295
307
296
return completed ;
0 commit comments