View Javadoc
1   /*
2    * Copyright 2012 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.multipart;
17  
18  import io.netty.buffer.ByteBuf;
19  import io.netty.buffer.CompositeByteBuf;
20  import io.netty.handler.codec.http.HttpConstants;
21  
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.FileOutputStream;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.nio.ByteBuffer;
28  import java.nio.channels.FileChannel;
29  import java.nio.charset.Charset;
30  
31  import static io.netty.buffer.Unpooled.*;
32  
33  /**
34   * Abstract Memory HttpData implementation
35   */
36  public abstract class AbstractMemoryHttpData extends AbstractHttpData {
37  
38      private ByteBuf byteBuf;
39      private int chunkPosition;
40      protected boolean isRenamed;
41  
42      protected AbstractMemoryHttpData(String name, Charset charset, long size) {
43          super(name, charset, size);
44      }
45  
46      @Override
47      public void setContent(ByteBuf buffer) throws IOException {
48          if (buffer == null) {
49              throw new NullPointerException("buffer");
50          }
51          long localsize = buffer.readableBytes();
52          if (definedSize > 0 && definedSize < localsize) {
53              throw new IOException("Out of size: " + localsize + " > " +
54                      definedSize);
55          }
56          if (byteBuf != null) {
57              byteBuf.release();
58          }
59          byteBuf = buffer;
60          size = localsize;
61          completed = true;
62      }
63  
64      @Override
65      public void setContent(InputStream inputStream) throws IOException {
66          if (inputStream == null) {
67              throw new NullPointerException("inputStream");
68          }
69          ByteBuf buffer = buffer();
70          byte[] bytes = new byte[4096 * 4];
71          int read = inputStream.read(bytes);
72          int written = 0;
73          while (read > 0) {
74              buffer.writeBytes(bytes, 0, read);
75              written += read;
76              read = inputStream.read(bytes);
77          }
78          size = written;
79          if (definedSize > 0 && definedSize < size) {
80              throw new IOException("Out of size: " + size + " > " + definedSize);
81          }
82          if (byteBuf != null) {
83              byteBuf.release();
84          }
85          byteBuf = buffer;
86          completed = true;
87      }
88  
89      @Override
90      public void addContent(ByteBuf buffer, boolean last)
91              throws IOException {
92          if (buffer != null) {
93              long localsize = buffer.readableBytes();
94              if (definedSize > 0 && definedSize < size + localsize) {
95                  throw new IOException("Out of size: " + (size + localsize) +
96                          " > " + definedSize);
97              }
98              size += localsize;
99              if (byteBuf == null) {
100                 byteBuf = buffer;
101             } else if (byteBuf instanceof CompositeByteBuf) {
102                 CompositeByteBuf cbb = (CompositeByteBuf) byteBuf;
103                 cbb.addComponent(true, buffer);
104             } else {
105                 CompositeByteBuf cbb = compositeBuffer(Integer.MAX_VALUE);
106                 cbb.addComponents(true, byteBuf, buffer);
107                 byteBuf = cbb;
108             }
109         }
110         if (last) {
111             completed = true;
112         } else {
113             if (buffer == null) {
114                 throw new NullPointerException("buffer");
115             }
116         }
117     }
118 
119     @Override
120     public void setContent(File file) throws IOException {
121         if (file == null) {
122             throw new NullPointerException("file");
123         }
124         long newsize = file.length();
125         if (newsize > Integer.MAX_VALUE) {
126             throw new IllegalArgumentException(
127                     "File too big to be loaded in memory");
128         }
129         FileInputStream inputStream = new FileInputStream(file);
130         FileChannel fileChannel = inputStream.getChannel();
131         byte[] array = new byte[(int) newsize];
132         ByteBuffer byteBuffer = ByteBuffer.wrap(array);
133         int read = 0;
134         while (read < newsize) {
135             read += fileChannel.read(byteBuffer);
136         }
137         fileChannel.close();
138         inputStream.close();
139         byteBuffer.flip();
140         if (byteBuf != null) {
141             byteBuf.release();
142         }
143         byteBuf = wrappedBuffer(Integer.MAX_VALUE, byteBuffer);
144         size = newsize;
145         completed = true;
146     }
147 
148     @Override
149     public void delete() {
150         if (byteBuf != null) {
151             byteBuf.release();
152             byteBuf = null;
153         }
154     }
155 
156     @Override
157     public byte[] get() {
158         if (byteBuf == null) {
159             return EMPTY_BUFFER.array();
160         }
161         byte[] array = new byte[byteBuf.readableBytes()];
162         byteBuf.getBytes(byteBuf.readerIndex(), array);
163         return array;
164     }
165 
166     @Override
167     public String getString() {
168         return getString(HttpConstants.DEFAULT_CHARSET);
169     }
170 
171     @Override
172     public String getString(Charset encoding) {
173         if (byteBuf == null) {
174             return "";
175         }
176         if (encoding == null) {
177             encoding = HttpConstants.DEFAULT_CHARSET;
178         }
179         return byteBuf.toString(encoding);
180     }
181 
182     /**
183      * Utility to go from a In Memory FileUpload
184      * to a Disk (or another implementation) FileUpload
185      * @return the attached ByteBuf containing the actual bytes
186      */
187     @Override
188     public ByteBuf getByteBuf() {
189         return byteBuf;
190     }
191 
192     @Override
193     public ByteBuf getChunk(int length) throws IOException {
194         if (byteBuf == null || length == 0 || byteBuf.readableBytes() == 0) {
195             chunkPosition = 0;
196             return EMPTY_BUFFER;
197         }
198         int sizeLeft = byteBuf.readableBytes() - chunkPosition;
199         if (sizeLeft == 0) {
200             chunkPosition = 0;
201             return EMPTY_BUFFER;
202         }
203         int sliceLength = length;
204         if (sizeLeft < length) {
205             sliceLength = sizeLeft;
206         }
207         ByteBuf chunk = byteBuf.slice(chunkPosition, sliceLength).retain();
208         chunkPosition += sliceLength;
209         return chunk;
210     }
211 
212     @Override
213     public boolean isInMemory() {
214         return true;
215     }
216 
217     @Override
218     public boolean renameTo(File dest) throws IOException {
219         if (dest == null) {
220             throw new NullPointerException("dest");
221         }
222         if (byteBuf == null) {
223             // empty file
224             dest.createNewFile();
225             isRenamed = true;
226             return true;
227         }
228         int length = byteBuf.readableBytes();
229         FileOutputStream outputStream = new FileOutputStream(dest);
230         FileChannel fileChannel = outputStream.getChannel();
231         int written = 0;
232         if (byteBuf.nioBufferCount() == 1) {
233             ByteBuffer byteBuffer = byteBuf.nioBuffer();
234             while (written < length) {
235                 written += fileChannel.write(byteBuffer);
236             }
237         } else {
238             ByteBuffer[] byteBuffers = byteBuf.nioBuffers();
239             while (written < length) {
240                 written += fileChannel.write(byteBuffers);
241             }
242         }
243 
244         fileChannel.force(false);
245         fileChannel.close();
246         outputStream.close();
247         isRenamed = true;
248         return written == length;
249     }
250 
251     @Override
252     public File getFile() throws IOException {
253         throw new IOException("Not represented by a file");
254     }
255 }