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     /**
145      * Utility method
146      */
147     private static void checkHttpDataSize(HttpData data) {
148         try {
149             data.checkSize(data.length());
150         } catch (IOException ignored) {
151             throw new IllegalArgumentException("Attribute bigger than maxSize allowed");
152         }
153     }
154 
155     @Override
156     public Attribute createAttribute(HttpRequest request, String name, String value) {
157         if (useDisk) {
158             Attribute attribute;
159             try {
160                 attribute = new DiskAttribute(name, value, charset);
161                 attribute.setMaxSize(maxSize);
162             } catch (IOException e) {
163                 // revert to Mixed mode
164                 attribute = new MixedAttribute(name, value, minSize, charset);
165                 attribute.setMaxSize(maxSize);
166             }
167             checkHttpDataSize(attribute);
168             List<HttpData> fileToDelete = getList(request);
169             fileToDelete.add(attribute);
170             return attribute;
171         }
172         if (checkSize) {
173             Attribute attribute = new MixedAttribute(name, value, minSize, charset);
174             attribute.setMaxSize(maxSize);
175             checkHttpDataSize(attribute);
176             List<HttpData> fileToDelete = getList(request);
177             fileToDelete.add(attribute);
178             return attribute;
179         }
180         try {
181             MemoryAttribute attribute = new MemoryAttribute(name, value, charset);
182             attribute.setMaxSize(maxSize);
183             checkHttpDataSize(attribute);
184             return attribute;
185         } catch (IOException e) {
186             throw new IllegalArgumentException(e);
187         }
188     }
189 
190     @Override
191     public FileUpload createFileUpload(HttpRequest request, String name, String filename,
192             String contentType, String contentTransferEncoding, Charset charset,
193             long size) {
194         if (useDisk) {
195             FileUpload fileUpload = new DiskFileUpload(name, filename, contentType,
196                     contentTransferEncoding, charset, size);
197             fileUpload.setMaxSize(maxSize);
198             checkHttpDataSize(fileUpload);
199             List<HttpData> fileToDelete = getList(request);
200             fileToDelete.add(fileUpload);
201             return fileUpload;
202         }
203         if (checkSize) {
204             FileUpload fileUpload = new MixedFileUpload(name, filename, contentType,
205                     contentTransferEncoding, charset, size, minSize);
206             fileUpload.setMaxSize(maxSize);
207             checkHttpDataSize(fileUpload);
208             List<HttpData> fileToDelete = getList(request);
209             fileToDelete.add(fileUpload);
210             return fileUpload;
211         }
212         MemoryFileUpload fileUpload = new MemoryFileUpload(name, filename, contentType,
213                 contentTransferEncoding, charset, size);
214         fileUpload.setMaxSize(maxSize);
215         checkHttpDataSize(fileUpload);
216         return fileUpload;
217     }
218 
219     @Override
220     public void removeHttpDataFromClean(HttpRequest request, InterfaceHttpData data) {
221         if (data instanceof HttpData) {
222             List<HttpData> fileToDelete = getList(request);
223             fileToDelete.remove(data);
224         }
225     }
226 
227     @Override
228     public void cleanRequestHttpData(HttpRequest request) {
229         List<HttpData> fileToDelete = requestFileDeleteMap.remove(request);
230         if (fileToDelete != null) {
231             for (HttpData data: fileToDelete) {
232                 data.delete();
233             }
234             fileToDelete.clear();
235         }
236     }
237 
238     @Override
239     public void cleanAllHttpData() {
240         Iterator<Entry<HttpRequest, List<HttpData>>> i = requestFileDeleteMap.entrySet().iterator();
241         while (i.hasNext()) {
242             Entry<HttpRequest, List<HttpData>> e = i.next();
243             i.remove();
244 
245             List<HttpData> fileToDelete = e.getValue();
246             if (fileToDelete != null) {
247                 for (HttpData data : fileToDelete) {
248                     data.delete();
249                 }
250                 fileToDelete.clear();
251             }
252         }
253     }
254 }