View Javadoc
1   /*
2    * Copyright 2022 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.util.AbstractReferenceCounted;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.nio.charset.Charset;
25  
26  abstract class AbstractMixedHttpData<D extends HttpData> extends AbstractReferenceCounted implements HttpData {
27      final String baseDir;
28      final boolean deleteOnExit;
29      D wrapped;
30  
31      private final long limitSize;
32  
33      AbstractMixedHttpData(long limitSize, String baseDir, boolean deleteOnExit, D initial) {
34          this.limitSize = limitSize;
35          this.wrapped = initial;
36          this.baseDir = baseDir;
37          this.deleteOnExit = deleteOnExit;
38      }
39  
40      abstract D makeDiskData();
41  
42      @Override
43      public long getMaxSize() {
44          return wrapped.getMaxSize();
45      }
46  
47      @Override
48      public void setMaxSize(long maxSize) {
49          wrapped.setMaxSize(maxSize);
50      }
51  
52      @Override
53      public ByteBuf content() {
54          return wrapped.content();
55      }
56  
57      @Override
58      public void checkSize(long newSize) throws IOException {
59          wrapped.checkSize(newSize);
60      }
61  
62      @Override
63      public long definedLength() {
64          return wrapped.definedLength();
65      }
66  
67      @Override
68      public Charset getCharset() {
69          return wrapped.getCharset();
70      }
71  
72      @Override
73      public String getName() {
74          return wrapped.getName();
75      }
76  
77      @Override
78      public void addContent(ByteBuf buffer, boolean last) throws IOException {
79          if (wrapped instanceof AbstractMemoryHttpData) {
80              try {
81                  checkSize(wrapped.length() + buffer.readableBytes());
82                  if (wrapped.length() + buffer.readableBytes() > limitSize) {
83                      D diskData = makeDiskData();
84                      ByteBuf data = ((AbstractMemoryHttpData) wrapped).getByteBuf();
85                      if (data != null && data.isReadable()) {
86                          diskData.addContent(data.retain(), false);
87                      }
88                      wrapped.release();
89                      wrapped = diskData;
90                  }
91              } catch (IOException e) {
92                  buffer.release();
93                  throw e;
94              }
95          }
96          wrapped.addContent(buffer, last);
97      }
98  
99      @Override
100     protected void deallocate() {
101         delete();
102     }
103 
104     @Override
105     public void delete() {
106         wrapped.delete();
107     }
108 
109     @Override
110     public byte[] get() throws IOException {
111         return wrapped.get();
112     }
113 
114     @Override
115     public ByteBuf getByteBuf() throws IOException {
116         return wrapped.getByteBuf();
117     }
118 
119     @Override
120     public String getString() throws IOException {
121         return wrapped.getString();
122     }
123 
124     @Override
125     public String getString(Charset encoding) throws IOException {
126         return wrapped.getString(encoding);
127     }
128 
129     @Override
130     public boolean isInMemory() {
131         return wrapped.isInMemory();
132     }
133 
134     @Override
135     public long length() {
136         return wrapped.length();
137     }
138 
139     @Override
140     public boolean renameTo(File dest) throws IOException {
141         return wrapped.renameTo(dest);
142     }
143 
144     @Override
145     public void setCharset(Charset charset) {
146         wrapped.setCharset(charset);
147     }
148 
149     @Override
150     public void setContent(ByteBuf buffer) throws IOException {
151         try {
152             checkSize(buffer.readableBytes());
153         } catch (IOException e) {
154             buffer.release();
155             throw e;
156         }
157         if (buffer.readableBytes() > limitSize) {
158             if (wrapped instanceof AbstractMemoryHttpData) {
159                 // change to Disk
160                 wrapped.release();
161                 wrapped = makeDiskData();
162             }
163         }
164         wrapped.setContent(buffer);
165     }
166 
167     @Override
168     public void setContent(File file) throws IOException {
169         checkSize(file.length());
170         if (file.length() > limitSize) {
171             if (wrapped instanceof AbstractMemoryHttpData) {
172                 // change to Disk
173                 wrapped.release();
174                 wrapped = makeDiskData();
175             }
176         }
177         wrapped.setContent(file);
178     }
179 
180     @Override
181     public void setContent(InputStream inputStream) throws IOException {
182         if (wrapped instanceof AbstractMemoryHttpData) {
183             // change to Disk even if we don't know the size
184             wrapped.release();
185             wrapped = makeDiskData();
186         }
187         wrapped.setContent(inputStream);
188     }
189 
190     @Override
191     public boolean isCompleted() {
192         return wrapped.isCompleted();
193     }
194 
195     @Override
196     public HttpDataType getHttpDataType() {
197         return wrapped.getHttpDataType();
198     }
199 
200     @Override
201     public int hashCode() {
202         return wrapped.hashCode();
203     }
204 
205     @Override
206     public boolean equals(Object obj) {
207         return wrapped.equals(obj);
208     }
209 
210     @Override
211     public int compareTo(InterfaceHttpData o) {
212         return wrapped.compareTo(o);
213     }
214 
215     @Override
216     public String toString() {
217         return "Mixed: " + wrapped;
218     }
219 
220     @Override
221     public ByteBuf getChunk(int length) throws IOException {
222         return wrapped.getChunk(length);
223     }
224 
225     @Override
226     public File getFile() throws IOException {
227         return wrapped.getFile();
228     }
229 
230     @SuppressWarnings("unchecked")
231     @Override
232     public D copy() {
233         return (D) wrapped.copy();
234     }
235 
236     @SuppressWarnings("unchecked")
237     @Override
238     public D duplicate() {
239         return (D) wrapped.duplicate();
240     }
241 
242     @SuppressWarnings("unchecked")
243     @Override
244     public D retainedDuplicate() {
245         return (D) wrapped.retainedDuplicate();
246     }
247 
248     @SuppressWarnings("unchecked")
249     @Override
250     public D replace(ByteBuf content) {
251         return (D) wrapped.replace(content);
252     }
253 
254     @SuppressWarnings("unchecked")
255     @Override
256     public D touch() {
257         wrapped.touch();
258         return (D) this;
259     }
260 
261     @SuppressWarnings("unchecked")
262     @Override
263     public D touch(Object hint) {
264         wrapped.touch(hint);
265         return (D) this;
266     }
267 
268     @SuppressWarnings("unchecked")
269     @Override
270     public D retain() {
271         return (D) super.retain();
272     }
273 
274     @SuppressWarnings("unchecked")
275     @Override
276     public D retain(int increment) {
277         return (D) super.retain(increment);
278     }
279 }