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.handler.codec.http.HttpConstants;
19  import io.netty.handler.codec.http.HttpRequest;
20  import io.netty.util.internal.PlatformDependent;
21  
22  import java.io.IOException;
23  import java.nio.charset.Charset;
24  import java.util.ArrayList;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Map.Entry;
29  
30  /**
31   * Default factory giving Attribute and FileUpload according to constructor
32   *
33   * Attribute and FileUpload could be :<br>
34   * - MemoryAttribute, DiskAttribute or MixedAttribute<br>
35   * - MemoryFileUpload, DiskFileUpload or MixedFileUpload<br>
36   * according to the constructor.
37   */
38  public class DefaultHttpDataFactory implements HttpDataFactory {
39  
40      /**
41       * Proposed default MINSIZE as 16 KB.
42       */
43      public static final long MINSIZE = 0x4000;
44      /**
45       * Proposed default MAXSIZE = -1 as UNLIMITED
46       */
47      public static final long MAXSIZE = -1;
48  
49      private final boolean useDisk;
50  
51      private final boolean checkSize;
52  
53      private long minSize;
54  
55      private long maxSize = MAXSIZE;
56  
57      private Charset charset = HttpConstants.DEFAULT_CHARSET;
58  
59      /**
60       * Keep all HttpDatas until cleanAllHttpData() is called.
61       */
62      private final Map<HttpRequest, List<HttpData>> requestFileDeleteMap = PlatformDependent.newConcurrentHashMap();
63  
64      /**
65       * HttpData will be in memory if less than default size (16KB).
66       * The type will be Mixed.
67       */
68      public DefaultHttpDataFactory() {
69          useDisk = false;
70          checkSize = true;
71          minSize = MINSIZE;
72      }
73  
74      public DefaultHttpDataFactory(Charset charset) {
75          this();
76          this.charset = charset;
77      }
78  
79      /**
80       * HttpData will be always on Disk if useDisk is True, else always in Memory if False
81       */
82      public DefaultHttpDataFactory(boolean useDisk) {
83          this.useDisk = useDisk;
84          checkSize = false;
85      }
86  
87      public DefaultHttpDataFactory(boolean useDisk, Charset charset) {
88          this(useDisk);
89          this.charset = charset;
90      }
91      /**
92       * HttpData will be on Disk if the size of the file is greater than minSize, else it
93       * will be in memory. The type will be Mixed.
94       */
95      public DefaultHttpDataFactory(long minSize) {
96          useDisk = false;
97          checkSize = true;
98          this.minSize = minSize;
99      }
100 
101     public DefaultHttpDataFactory(long minSize, Charset charset) {
102         this(minSize);
103         this.charset = charset;
104     }
105 
106     @Override
107     public void setMaxLimit(long maxSize) {
108         this.maxSize = maxSize;
109     }
110 
111     /**
112      * @return the associated list of Files for the request
113      */
114     private List<HttpData> getList(HttpRequest request) {
115         List<HttpData> list = requestFileDeleteMap.get(request);
116         if (list == null) {
117             list = new ArrayList<HttpData>();
118             requestFileDeleteMap.put(request, list);
119         }
120         return list;
121     }
122 
123     @Override
124     public Attribute createAttribute(HttpRequest request, String name) {
125         if (useDisk) {
126             Attribute attribute = new DiskAttribute(name, charset);
127             attribute.setMaxSize(maxSize);
128             List<HttpData> fileToDelete = getList(request);
129             fileToDelete.add(attribute);
130             return attribute;
131         }
132         if (checkSize) {
133             Attribute attribute = new MixedAttribute(name, minSize, charset);
134             attribute.setMaxSize(maxSize);
135             List<HttpData> fileToDelete = getList(request);
136             fileToDelete.add(attribute);
137             return attribute;
138         }
139         MemoryAttribute attribute = new MemoryAttribute(name);
140         attribute.setMaxSize(maxSize);
141         return attribute;
142     }
143 
144     @Override
145     public Attribute createAttribute(HttpRequest request, String name, long definedSize) {
146         if (useDisk) {
147             Attribute attribute = new DiskAttribute(name, definedSize, charset);
148             attribute.setMaxSize(maxSize);
149             List<HttpData> fileToDelete = getList(request);
150             fileToDelete.add(attribute);
151             return attribute;
152         }
153         if (checkSize) {
154             Attribute attribute = new MixedAttribute(name, definedSize, minSize, charset);
155             attribute.setMaxSize(maxSize);
156             List<HttpData> fileToDelete = getList(request);
157             fileToDelete.add(attribute);
158             return attribute;
159         }
160         MemoryAttribute attribute = new MemoryAttribute(name, definedSize);
161         attribute.setMaxSize(maxSize);
162         return attribute;
163     }
164 
165     /**
166      * Utility method
167      */
168     private static void checkHttpDataSize(HttpData data) {
169         try {
170             data.checkSize(data.length());
171         } catch (IOException ignored) {
172             throw new IllegalArgumentException("Attribute bigger than maxSize allowed");
173         }
174     }
175 
176     @Override
177     public Attribute createAttribute(HttpRequest request, String name, String value) {
178         if (useDisk) {
179             Attribute attribute;
180             try {
181                 attribute = new DiskAttribute(name, value, charset);
182                 attribute.setMaxSize(maxSize);
183             } catch (IOException e) {
184                 // revert to Mixed mode
185                 attribute = new MixedAttribute(name, value, minSize, charset);
186                 attribute.setMaxSize(maxSize);
187             }
188             checkHttpDataSize(attribute);
189             List<HttpData> fileToDelete = getList(request);
190             fileToDelete.add(attribute);
191             return attribute;
192         }
193         if (checkSize) {
194             Attribute attribute = new MixedAttribute(name, value, minSize, charset);
195             attribute.setMaxSize(maxSize);
196             checkHttpDataSize(attribute);
197             List<HttpData> fileToDelete = getList(request);
198             fileToDelete.add(attribute);
199             return attribute;
200         }
201         try {
202             MemoryAttribute attribute = new MemoryAttribute(name, value, charset);
203             attribute.setMaxSize(maxSize);
204             checkHttpDataSize(attribute);
205             return attribute;
206         } catch (IOException e) {
207             throw new IllegalArgumentException(e);
208         }
209     }
210 
211     @Override
212     public FileUpload createFileUpload(HttpRequest request, String name, String filename,
213             String contentType, String contentTransferEncoding, Charset charset,
214             long size) {
215         if (useDisk) {
216             FileUpload fileUpload = new DiskFileUpload(name, filename, contentType,
217                     contentTransferEncoding, charset, size);
218             fileUpload.setMaxSize(maxSize);
219             checkHttpDataSize(fileUpload);
220             List<HttpData> fileToDelete = getList(request);
221             fileToDelete.add(fileUpload);
222             return fileUpload;
223         }
224         if (checkSize) {
225             FileUpload fileUpload = new MixedFileUpload(name, filename, contentType,
226                     contentTransferEncoding, charset, size, minSize);
227             fileUpload.setMaxSize(maxSize);
228             checkHttpDataSize(fileUpload);
229             List<HttpData> fileToDelete = getList(request);
230             fileToDelete.add(fileUpload);
231             return fileUpload;
232         }
233         MemoryFileUpload fileUpload = new MemoryFileUpload(name, filename, contentType,
234                 contentTransferEncoding, charset, size);
235         fileUpload.setMaxSize(maxSize);
236         checkHttpDataSize(fileUpload);
237         return fileUpload;
238     }
239 
240     @Override
241     public void removeHttpDataFromClean(HttpRequest request, InterfaceHttpData data) {
242         if (data instanceof HttpData) {
243             List<HttpData> fileToDelete = getList(request);
244             fileToDelete.remove(data);
245         }
246     }
247 
248     @Override
249     public void cleanRequestHttpData(HttpRequest request) {
250         List<HttpData> fileToDelete = requestFileDeleteMap.remove(request);
251         if (fileToDelete != null) {
252             for (HttpData data: fileToDelete) {
253                 data.delete();
254             }
255             fileToDelete.clear();
256         }
257     }
258 
259     @Override
260     public void cleanAllHttpData() {
261         Iterator<Entry<HttpRequest, List<HttpData>>> i = requestFileDeleteMap.entrySet().iterator();
262         while (i.hasNext()) {
263             Entry<HttpRequest, List<HttpData>> e = i.next();
264             i.remove();
265 
266             List<HttpData> fileToDelete = e.getValue();
267             if (fileToDelete != null) {
268                 for (HttpData data : fileToDelete) {
269                     data.delete();
270                 }
271                 fileToDelete.clear();
272             }
273         }
274     }
275 
276     @Override
277     public void cleanRequestHttpDatas(HttpRequest request) {
278         cleanRequestHttpData(request);
279     }
280 
281     @Override
282     public void cleanAllHttpDatas() {
283         cleanAllHttpData();
284     }
285 }