View Javadoc

1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.codec.http;
17  
18  import io.netty.buffer.ByteBuf;
19  import io.netty.buffer.ByteBufAllocator;
20  import io.netty.channel.ChannelHandlerContext;
21  import io.netty.handler.stream.ChunkedInput;
22  
23  /**
24   * A [email protected] ChunkedInput} that fetches data chunk by chunk for use with HTTP chunked transfers.
25   * <p>
26   * Each chunk from the input data will be wrapped within a [email protected] HttpContent}. At the end of the input data,
27   * [email protected] LastHttpContent} will be written.
28   * <p>
29   * Ensure that your HTTP response header contains [email protected] Transfer-Encoding: chunked}.
30   * <p>
31   * <pre>
32   * public void messageReceived(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
33   *     HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
34   *     response.headers().set(TRANSFER_ENCODING, CHUNKED);
35   *     ctx.write(response);
36   *
37   *     HttpContentChunkedInput httpChunkWriter = new HttpChunkedInput(
38   *         new ChunkedFile(&quot;/tmp/myfile.txt&quot;));
39   *     ChannelFuture sendFileFuture = ctx.write(httpChunkWriter);
40   * }
41   * </pre>
42   */
43  public class HttpChunkedInput implements ChunkedInput<HttpContent> {
44  
45      private final ChunkedInput<ByteBuf> input;
46      private final LastHttpContent lastHttpContent;
47      private boolean sentLastChunk;
48  
49      /**
50       * Creates a new instance using the specified input.
51       * @param input [email protected] ChunkedInput} containing data to write
52       */
53      public HttpChunkedInput(ChunkedInput<ByteBuf> input) {
54          this.input = input;
55          lastHttpContent = LastHttpContent.EMPTY_LAST_CONTENT;
56      }
57  
58      /**
59       * Creates a new instance using the specified input. [email protected] lastHttpContent} will be written as the terminating
60       * chunk.
61       * @param input [email protected] ChunkedInput} containing data to write
62       * @param lastHttpContent [email protected] LastHttpContent} that will be written as the terminating chunk. Use this for
63       *            training headers.
64       */
65      public HttpChunkedInput(ChunkedInput<ByteBuf> input, LastHttpContent lastHttpContent) {
66          this.input = input;
67          this.lastHttpContent = lastHttpContent;
68      }
69  
70      @Override
71      public boolean isEndOfInput() throws Exception {
72          if (input.isEndOfInput()) {
73              // Only end of input after last HTTP chunk has been sent
74              return sentLastChunk;
75          } else {
76              return false;
77          }
78      }
79  
80      @Override
81      public void close() throws Exception {
82          input.close();
83      }
84  
85      @Deprecated
86      @Override
87      public HttpContent readChunk(ChannelHandlerContext ctx) throws Exception {
88          return readChunk(ctx.alloc());
89      }
90  
91      @Override
92      public HttpContent readChunk(ByteBufAllocator allocator) throws Exception {
93          if (input.isEndOfInput()) {
94              if (sentLastChunk) {
95                  return null;
96              } else {
97                  // Send last chunk for this input
98                  sentLastChunk = true;
99                  return lastHttpContent;
100             }
101         } else {
102             ByteBuf buf = input.readChunk(allocator);
103             if (buf == null) {
104                 return null;
105             }
106             return new DefaultHttpContent(buf);
107         }
108     }
109 
110     @Override
111     public long length() {
112         return input.length();
113     }
114 
115     @Override
116     public long progress() {
117         return input.progress();
118     }
119 }