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