1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http.multipart;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.CompositeByteBuf;
20 import io.netty.handler.codec.http.HttpConstants;
21 import io.netty.util.internal.ObjectUtil;
22
23 import java.io.File;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.RandomAccessFile;
27 import java.nio.ByteBuffer;
28 import java.nio.channels.FileChannel;
29 import java.nio.charset.Charset;
30
31 import static io.netty.buffer.Unpooled.EMPTY_BUFFER;
32 import static io.netty.buffer.Unpooled.buffer;
33 import static io.netty.buffer.Unpooled.compositeBuffer;
34 import static io.netty.buffer.Unpooled.wrappedBuffer;
35
36
37
38
39 public abstract class AbstractMemoryHttpData extends AbstractHttpData {
40
41 private ByteBuf byteBuf;
42 private int chunkPosition;
43
44 protected AbstractMemoryHttpData(String name, Charset charset, long size) {
45 super(name, charset, size);
46 byteBuf = EMPTY_BUFFER;
47 }
48
49 @Override
50 public void setContent(ByteBuf buffer) throws IOException {
51 ObjectUtil.checkNotNull(buffer, "buffer");
52 long localsize = buffer.readableBytes();
53 try {
54 checkSize(localsize);
55 } catch (IOException e) {
56 buffer.release();
57 throw e;
58 }
59 if (definedSize > 0 && definedSize < localsize) {
60 buffer.release();
61 throw new IOException("Out of size: " + localsize + " > " +
62 definedSize);
63 }
64 if (byteBuf != null) {
65 byteBuf.release();
66 }
67 byteBuf = buffer;
68 size = localsize;
69 setCompleted();
70 }
71
72 @Override
73 public void setContent(InputStream inputStream) throws IOException {
74 ObjectUtil.checkNotNull(inputStream, "inputStream");
75
76 byte[] bytes = new byte[4096 * 4];
77 ByteBuf buffer = buffer();
78 int written = 0;
79 try {
80 int read = inputStream.read(bytes);
81 while (read > 0) {
82 buffer.writeBytes(bytes, 0, read);
83 written += read;
84 checkSize(written);
85 read = inputStream.read(bytes);
86 }
87 } catch (IOException e) {
88 buffer.release();
89 throw e;
90 }
91 size = written;
92 if (definedSize > 0 && definedSize < size) {
93 buffer.release();
94 throw new IOException("Out of size: " + size + " > " + definedSize);
95 }
96 if (byteBuf != null) {
97 byteBuf.release();
98 }
99 byteBuf = buffer;
100 setCompleted();
101 }
102
103 @Override
104 public void addContent(ByteBuf buffer, boolean last)
105 throws IOException {
106 if (buffer != null) {
107 long localsize = buffer.readableBytes();
108 try {
109 checkSize(size + localsize);
110 } catch (IOException e) {
111 buffer.release();
112 throw e;
113 }
114 if (definedSize > 0 && definedSize < size + localsize) {
115 buffer.release();
116 throw new IOException("Out of size: " + (size + localsize) +
117 " > " + definedSize);
118 }
119 size += localsize;
120 if (byteBuf == null) {
121 byteBuf = buffer;
122 } else if (localsize == 0) {
123
124 buffer.release();
125 } else if (byteBuf.readableBytes() == 0) {
126
127 byteBuf.release();
128 byteBuf = buffer;
129 } else if (byteBuf instanceof CompositeByteBuf) {
130 CompositeByteBuf cbb = (CompositeByteBuf) byteBuf;
131 cbb.addComponent(true, buffer);
132 } else {
133 CompositeByteBuf cbb = compositeBuffer(Integer.MAX_VALUE);
134 cbb.addComponents(true, byteBuf, buffer);
135 byteBuf = cbb;
136 }
137 }
138 if (last) {
139 setCompleted();
140 } else {
141 ObjectUtil.checkNotNull(buffer, "buffer");
142 }
143 }
144
145 @Override
146 public void setContent(File file) throws IOException {
147 ObjectUtil.checkNotNull(file, "file");
148
149 long newsize = file.length();
150 if (newsize > Integer.MAX_VALUE) {
151 throw new IllegalArgumentException("File too big to be loaded in memory");
152 }
153 checkSize(newsize);
154 RandomAccessFile accessFile = new RandomAccessFile(file, "r");
155 ByteBuffer byteBuffer;
156 try {
157 FileChannel fileChannel = accessFile.getChannel();
158 try {
159 byte[] array = new byte[(int) newsize];
160 byteBuffer = ByteBuffer.wrap(array);
161 int read = 0;
162 while (read < newsize) {
163 read += fileChannel.read(byteBuffer);
164 }
165 } finally {
166 fileChannel.close();
167 }
168 } finally {
169 accessFile.close();
170 }
171 byteBuffer.flip();
172 if (byteBuf != null) {
173 byteBuf.release();
174 }
175 byteBuf = wrappedBuffer(Integer.MAX_VALUE, byteBuffer);
176 size = newsize;
177 setCompleted();
178 }
179
180 @Override
181 public void delete() {
182 if (byteBuf != null) {
183 byteBuf.release();
184 byteBuf = null;
185 }
186 }
187
188 @Override
189 public byte[] get() {
190 if (byteBuf == null) {
191 return EMPTY_BUFFER.array();
192 }
193 byte[] array = new byte[byteBuf.readableBytes()];
194 byteBuf.getBytes(byteBuf.readerIndex(), array);
195 return array;
196 }
197
198 @Override
199 public String getString() {
200 return getString(HttpConstants.DEFAULT_CHARSET);
201 }
202
203 @Override
204 public String getString(Charset encoding) {
205 if (byteBuf == null) {
206 return "";
207 }
208 if (encoding == null) {
209 encoding = HttpConstants.DEFAULT_CHARSET;
210 }
211 return byteBuf.toString(encoding);
212 }
213
214
215
216
217
218
219 @Override
220 public ByteBuf getByteBuf() {
221 return byteBuf;
222 }
223
224 @Override
225 public ByteBuf getChunk(int length) throws IOException {
226 if (byteBuf == null || length == 0 || byteBuf.readableBytes() == 0) {
227 chunkPosition = 0;
228 return EMPTY_BUFFER;
229 }
230 int sizeLeft = byteBuf.readableBytes() - chunkPosition;
231 if (sizeLeft == 0) {
232 chunkPosition = 0;
233 return EMPTY_BUFFER;
234 }
235 int sliceLength = length;
236 if (sizeLeft < length) {
237 sliceLength = sizeLeft;
238 }
239 ByteBuf chunk = byteBuf.retainedSlice(chunkPosition, sliceLength);
240 chunkPosition += sliceLength;
241 return chunk;
242 }
243
244 @Override
245 public boolean isInMemory() {
246 return true;
247 }
248
249 @Override
250 public boolean renameTo(File dest) throws IOException {
251 ObjectUtil.checkNotNull(dest, "dest");
252 if (byteBuf == null) {
253
254 if (!dest.createNewFile()) {
255 throw new IOException("file exists already: " + dest);
256 }
257 return true;
258 }
259 int length = byteBuf.readableBytes();
260 long written = 0;
261 RandomAccessFile accessFile = new RandomAccessFile(dest, "rw");
262 try {
263 FileChannel fileChannel = accessFile.getChannel();
264 try {
265 if (byteBuf.nioBufferCount() == 1) {
266 ByteBuffer byteBuffer = byteBuf.nioBuffer();
267 while (written < length) {
268 written += fileChannel.write(byteBuffer);
269 }
270 } else {
271 ByteBuffer[] byteBuffers = byteBuf.nioBuffers();
272 while (written < length) {
273 written += fileChannel.write(byteBuffers);
274 }
275 }
276 fileChannel.force(false);
277 } finally {
278 fileChannel.close();
279 }
280 } finally {
281 accessFile.close();
282 }
283 return written == length;
284 }
285
286 @Override
287 public File getFile() throws IOException {
288 throw new IOException("Not represented by a file");
289 }
290
291 @Override
292 public HttpData touch() {
293 return touch(null);
294 }
295
296 @Override
297 public HttpData touch(Object hint) {
298 if (byteBuf != null) {
299 byteBuf.touch(hint);
300 }
301 return this;
302 }
303 }