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    *   https://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.handler.codec.http.HttpConstants;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.nio.charset.Charset;
25  
26  /**
27   * Mixed implementation using both in Memory and in File with a limit of size
28   */
29  public class MixedAttribute implements Attribute {
30      private final String baseDir;
31      private final boolean deleteOnExit;
32      private Attribute attribute;
33  
34      private final long limitSize;
35      private long maxSize = DefaultHttpDataFactory.MAXSIZE;
36  
37      public MixedAttribute(String name, long limitSize) {
38          this(name, limitSize, HttpConstants.DEFAULT_CHARSET);
39      }
40  
41      public MixedAttribute(String name, long definedSize, long limitSize) {
42          this(name, definedSize, limitSize, HttpConstants.DEFAULT_CHARSET);
43      }
44  
45      public MixedAttribute(String name, long limitSize, Charset charset) {
46          this(name, limitSize, charset, DiskAttribute.baseDirectory, DiskAttribute.deleteOnExitTemporaryFile);
47      }
48  
49      public MixedAttribute(String name, long limitSize, Charset charset, String baseDir, boolean deleteOnExit) {
50          this.limitSize = limitSize;
51          attribute = new MemoryAttribute(name, charset);
52          this.baseDir = baseDir;
53          this.deleteOnExit = deleteOnExit;
54      }
55  
56      public MixedAttribute(String name, long definedSize, long limitSize, Charset charset) {
57          this(name, definedSize, limitSize, charset,
58                  DiskAttribute.baseDirectory, DiskAttribute.deleteOnExitTemporaryFile);
59      }
60  
61      public MixedAttribute(String name, long definedSize, long limitSize, Charset charset,
62                            String baseDir, boolean deleteOnExit) {
63          this.limitSize = limitSize;
64          attribute = new MemoryAttribute(name, definedSize, charset);
65          this.baseDir = baseDir;
66          this.deleteOnExit = deleteOnExit;
67      }
68  
69      public MixedAttribute(String name, String value, long limitSize) {
70          this(name, value, limitSize, HttpConstants.DEFAULT_CHARSET,
71                  DiskAttribute.baseDirectory, DiskFileUpload.deleteOnExitTemporaryFile);
72      }
73  
74      public MixedAttribute(String name, String value, long limitSize, Charset charset) {
75          this(name, value, limitSize, charset,
76                  DiskAttribute.baseDirectory, DiskFileUpload.deleteOnExitTemporaryFile);
77      }
78  
79      public MixedAttribute(String name, String value, long limitSize, Charset charset,
80                            String baseDir, boolean deleteOnExit) {
81          this.limitSize = limitSize;
82          if (value.length() > this.limitSize) {
83              try {
84                  attribute = new DiskAttribute(name, value, charset, baseDir, deleteOnExit);
85              } catch (IOException e) {
86                  // revert to Memory mode
87                  try {
88                      attribute = new MemoryAttribute(name, value, charset);
89                  } catch (IOException ignore) {
90                      throw new IllegalArgumentException(e);
91                  }
92              }
93          } else {
94              try {
95                  attribute = new MemoryAttribute(name, value, charset);
96              } catch (IOException e) {
97                  throw new IllegalArgumentException(e);
98              }
99          }
100         this.baseDir = baseDir;
101         this.deleteOnExit = deleteOnExit;
102     }
103 
104     @Override
105     public long getMaxSize() {
106         return maxSize;
107     }
108 
109     @Override
110     public void setMaxSize(long maxSize) {
111         this.maxSize = maxSize;
112         attribute.setMaxSize(maxSize);
113     }
114 
115     @Override
116     public void checkSize(long newSize) throws IOException {
117         if (maxSize >= 0 && newSize > maxSize) {
118             throw new IOException("Size exceed allowed maximum capacity");
119         }
120     }
121 
122     @Override
123     public void addContent(ByteBuf buffer, boolean last) throws IOException {
124         if (attribute instanceof MemoryAttribute) {
125             try {
126                 checkSize(attribute.length() + buffer.readableBytes());
127                 if (attribute.length() + buffer.readableBytes() > limitSize) {
128                     DiskAttribute diskAttribute = new DiskAttribute(attribute
129                             .getName(), attribute.definedLength(), baseDir, deleteOnExit);
130                     diskAttribute.setMaxSize(maxSize);
131                     if (((MemoryAttribute) attribute).getByteBuf() != null) {
132                         diskAttribute.addContent(((MemoryAttribute) attribute)
133                             .getByteBuf(), false);
134                     }
135                     attribute = diskAttribute;
136                 }
137             } catch (IOException e) {
138                 buffer.release();
139                 throw e;
140             }
141         }
142         attribute.addContent(buffer, last);
143     }
144 
145     @Override
146     public void delete() {
147         attribute.delete();
148     }
149 
150     @Override
151     public byte[] get() throws IOException {
152         return attribute.get();
153     }
154 
155     @Override
156     public ByteBuf getByteBuf() throws IOException {
157         return attribute.getByteBuf();
158     }
159 
160     @Override
161     public Charset getCharset() {
162         return attribute.getCharset();
163     }
164 
165     @Override
166     public String getString() throws IOException {
167         return attribute.getString();
168     }
169 
170     @Override
171     public String getString(Charset encoding) throws IOException {
172         return attribute.getString(encoding);
173     }
174 
175     @Override
176     public boolean isCompleted() {
177         return attribute.isCompleted();
178     }
179 
180     @Override
181     public boolean isInMemory() {
182         return attribute.isInMemory();
183     }
184 
185     @Override
186     public long length() {
187         return attribute.length();
188     }
189 
190     @Override
191     public long definedLength() {
192         return attribute.definedLength();
193     }
194 
195     @Override
196     public boolean renameTo(File dest) throws IOException {
197         return attribute.renameTo(dest);
198     }
199 
200     @Override
201     public void setCharset(Charset charset) {
202         attribute.setCharset(charset);
203     }
204 
205     @Override
206     public void setContent(ByteBuf buffer) throws IOException {
207         try {
208             checkSize(buffer.readableBytes());
209         } catch (IOException e) {
210             buffer.release();
211             throw e;
212         }
213         if (buffer.readableBytes() > limitSize) {
214             if (attribute instanceof MemoryAttribute) {
215                 // change to Disk
216                 attribute = new DiskAttribute(attribute.getName(), attribute.definedLength(), baseDir, deleteOnExit);
217                 attribute.setMaxSize(maxSize);
218             }
219         }
220         attribute.setContent(buffer);
221     }
222 
223     @Override
224     public void setContent(File file) throws IOException {
225         checkSize(file.length());
226         if (file.length() > limitSize) {
227             if (attribute instanceof MemoryAttribute) {
228                 // change to Disk
229                 attribute = new DiskAttribute(attribute.getName(), attribute.definedLength(), baseDir, deleteOnExit);
230                 attribute.setMaxSize(maxSize);
231             }
232         }
233         attribute.setContent(file);
234     }
235 
236     @Override
237     public void setContent(InputStream inputStream) throws IOException {
238         if (attribute instanceof MemoryAttribute) {
239             // change to Disk even if we don't know the size
240             attribute = new DiskAttribute(attribute.getName(), attribute.definedLength(), baseDir, deleteOnExit);
241             attribute.setMaxSize(maxSize);
242         }
243         attribute.setContent(inputStream);
244     }
245 
246     @Override
247     public HttpDataType getHttpDataType() {
248         return attribute.getHttpDataType();
249     }
250 
251     @Override
252     public String getName() {
253         return attribute.getName();
254     }
255 
256     @Override
257     public int hashCode() {
258         return attribute.hashCode();
259     }
260 
261     @Override
262     public boolean equals(Object obj) {
263         return attribute.equals(obj);
264     }
265 
266     @Override
267     public int compareTo(InterfaceHttpData o) {
268         return attribute.compareTo(o);
269     }
270 
271     @Override
272     public String toString() {
273         return "Mixed: " + attribute;
274     }
275 
276     @Override
277     public String getValue() throws IOException {
278         return attribute.getValue();
279     }
280 
281     @Override
282     public void setValue(String value) throws IOException {
283         attribute.setValue(value);
284     }
285 
286     @Override
287     public ByteBuf getChunk(int length) throws IOException {
288         return attribute.getChunk(length);
289     }
290 
291     @Override
292     public File getFile() throws IOException {
293         return attribute.getFile();
294     }
295 
296     @Override
297     public Attribute copy() {
298         return attribute.copy();
299     }
300 
301     @Override
302     public Attribute duplicate() {
303         return attribute.duplicate();
304     }
305 
306     @Override
307     public Attribute retainedDuplicate() {
308         return attribute.retainedDuplicate();
309     }
310 
311     @Override
312     public Attribute replace(ByteBuf content) {
313         return attribute.replace(content);
314     }
315 
316     @Override
317     public ByteBuf content() {
318         return attribute.content();
319     }
320 
321     @Override
322     public int refCnt() {
323         return attribute.refCnt();
324     }
325 
326     @Override
327     public Attribute retain() {
328         attribute.retain();
329         return this;
330     }
331 
332     @Override
333     public Attribute retain(int increment) {
334         attribute.retain(increment);
335         return this;
336     }
337 
338     @Override
339     public Attribute touch() {
340         attribute.touch();
341         return this;
342     }
343 
344     @Override
345     public Attribute touch(Object hint) {
346         attribute.touch(hint);
347         return this;
348     }
349 
350     @Override
351     public boolean release() {
352         return attribute.release();
353     }
354 
355     @Override
356     public boolean release(int decrement) {
357         return attribute.release(decrement);
358     }
359 }