1 //
2 // ========================================================================
3 // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
8 //
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
11 //
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
14 //
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
17 //
18
19 package org.eclipse.jetty.util;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.Closeable;
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.InputStreamReader;
29 import java.io.OutputStream;
30 import java.io.PrintWriter;
31 import java.io.Reader;
32 import java.io.StringWriter;
33 import java.io.Writer;
34 import java.nio.ByteBuffer;
35 import java.nio.channels.GatheringByteChannel;
36 import java.nio.charset.Charset;
37
38 import org.eclipse.jetty.util.log.Log;
39 import org.eclipse.jetty.util.log.Logger;
40
41 /* ======================================================================== */
42 /** IO Utilities.
43 * Provides stream handling utilities in
44 * singleton Threadpool implementation accessed by static members.
45 */
46 public class IO
47 {
48 private static final Logger LOG = Log.getLogger(IO.class);
49
50 /* ------------------------------------------------------------------- */
51 public final static String
52 CRLF = "\015\012";
53
54 /* ------------------------------------------------------------------- */
55 public final static byte[]
56 CRLF_BYTES = {(byte)'\015',(byte)'\012'};
57
58 /* ------------------------------------------------------------------- */
59 public static final int bufferSize = 64*1024;
60
61 /* ------------------------------------------------------------------- */
62 static class Job implements Runnable
63 {
64 InputStream in;
65 OutputStream out;
66 Reader read;
67 Writer write;
68
69 Job(InputStream in,OutputStream out)
70 {
71 this.in=in;
72 this.out=out;
73 this.read=null;
74 this.write=null;
75 }
76 Job(Reader read,Writer write)
77 {
78 this.in=null;
79 this.out=null;
80 this.read=read;
81 this.write=write;
82 }
83
84 /* ------------------------------------------------------------ */
85 /*
86 * @see java.lang.Runnable#run()
87 */
88 public void run()
89 {
90 try {
91 if (in!=null)
92 copy(in,out,-1);
93 else
94 copy(read,write,-1);
95 }
96 catch(IOException e)
97 {
98 LOG.ignore(e);
99 try{
100 if (out!=null)
101 out.close();
102 if (write!=null)
103 write.close();
104 }
105 catch(IOException e2)
106 {
107 LOG.ignore(e2);
108 }
109 }
110 }
111 }
112
113 /* ------------------------------------------------------------------- */
114 /** Copy Stream in to Stream out until EOF or exception.
115 * @param in the input stream to read from (until EOF)
116 * @param out the output stream to write to
117 * @throws IOException if unable to copy streams
118 */
119 public static void copy(InputStream in, OutputStream out)
120 throws IOException
121 {
122 copy(in,out,-1);
123 }
124
125 /* ------------------------------------------------------------------- */
126 /** Copy Reader to Writer out until EOF or exception.
127 * @param in the read to read from (until EOF)
128 * @param out the writer to write to
129 * @throws IOException if unable to copy the streams
130 */
131 public static void copy(Reader in, Writer out)
132 throws IOException
133 {
134 copy(in,out,-1);
135 }
136
137 /* ------------------------------------------------------------------- */
138 /** Copy Stream in to Stream for byteCount bytes or until EOF or exception.
139 * @param in the stream to read from
140 * @param out the stream to write to
141 * @param byteCount the number of bytes to copy
142 * @throws IOException if unable to copy the streams
143 */
144 public static void copy(InputStream in,
145 OutputStream out,
146 long byteCount)
147 throws IOException
148 {
149 byte buffer[] = new byte[bufferSize];
150 int len=bufferSize;
151
152 if (byteCount>=0)
153 {
154 while (byteCount>0)
155 {
156 int max = byteCount<bufferSize?(int)byteCount:bufferSize;
157 len=in.read(buffer,0,max);
158
159 if (len==-1)
160 break;
161
162 byteCount -= len;
163 out.write(buffer,0,len);
164 }
165 }
166 else
167 {
168 while (true)
169 {
170 len=in.read(buffer,0,bufferSize);
171 if (len<0 )
172 break;
173 out.write(buffer,0,len);
174 }
175 }
176 }
177
178 /* ------------------------------------------------------------------- */
179 /** Copy Reader to Writer for byteCount bytes or until EOF or exception.
180 * @param in the Reader to read from
181 * @param out the Writer to write to
182 * @param byteCount the number of bytes to copy
183 * @throws IOException if unable to copy streams
184 */
185 public static void copy(Reader in,
186 Writer out,
187 long byteCount)
188 throws IOException
189 {
190 char buffer[] = new char[bufferSize];
191 int len=bufferSize;
192
193 if (byteCount>=0)
194 {
195 while (byteCount>0)
196 {
197 if (byteCount<bufferSize)
198 len=in.read(buffer,0,(int)byteCount);
199 else
200 len=in.read(buffer,0,bufferSize);
201
202 if (len==-1)
203 break;
204
205 byteCount -= len;
206 out.write(buffer,0,len);
207 }
208 }
209 else if (out instanceof PrintWriter)
210 {
211 PrintWriter pout=(PrintWriter)out;
212 while (!pout.checkError())
213 {
214 len=in.read(buffer,0,bufferSize);
215 if (len==-1)
216 break;
217 out.write(buffer,0,len);
218 }
219 }
220 else
221 {
222 while (true)
223 {
224 len=in.read(buffer,0,bufferSize);
225 if (len==-1)
226 break;
227 out.write(buffer,0,len);
228 }
229 }
230 }
231
232 /* ------------------------------------------------------------ */
233 /** Copy files or directories
234 * @param from the file to copy
235 * @param to the destination to copy to
236 * @throws IOException if unable to copy
237 */
238 public static void copy(File from,File to) throws IOException
239 {
240 if (from.isDirectory())
241 copyDir(from,to);
242 else
243 copyFile(from,to);
244 }
245
246 /* ------------------------------------------------------------ */
247 public static void copyDir(File from,File to) throws IOException
248 {
249 if (to.exists())
250 {
251 if (!to.isDirectory())
252 throw new IllegalArgumentException(to.toString());
253 }
254 else
255 to.mkdirs();
256
257 File[] files = from.listFiles();
258 if (files!=null)
259 {
260 for (int i=0;i<files.length;i++)
261 {
262 String name = files[i].getName();
263 if (".".equals(name) || "..".equals(name))
264 continue;
265 copy(files[i],new File(to,name));
266 }
267 }
268 }
269
270 /* ------------------------------------------------------------ */
271 public static void copyFile(File from,File to) throws IOException
272 {
273 try (InputStream in=new FileInputStream(from);
274 OutputStream out=new FileOutputStream(to))
275 {
276 copy(in,out);
277 }
278 }
279
280 /* ------------------------------------------------------------ */
281 /** Read input stream to string.
282 * @param in the stream to read from (until EOF)
283 * @return the String parsed from stream (default Charset)
284 * @throws IOException if unable to read the stream (or handle the charset)
285 */
286 public static String toString(InputStream in)
287 throws IOException
288 {
289 return toString(in,(Charset)null);
290 }
291
292 /* ------------------------------------------------------------ */
293 /** Read input stream to string.
294 * @param in the stream to read from (until EOF)
295 * @param encoding the encoding to use (can be null to use default Charset)
296 * @return the String parsed from the stream
297 * @throws IOException if unable to read the stream (or handle the charset)
298 */
299 public static String toString(InputStream in,String encoding)
300 throws IOException
301 {
302 return toString(in, encoding==null?null:Charset.forName(encoding));
303 }
304
305 /** Read input stream to string.
306 * @param in the stream to read from (until EOF)
307 * @param encoding the Charset to use (can be null to use default Charset)
308 * @return the String parsed from the stream
309 * @throws IOException if unable to read the stream (or handle the charset)
310 */
311 public static String toString(InputStream in, Charset encoding)
312 throws IOException
313 {
314 StringWriter writer=new StringWriter();
315 InputStreamReader reader = encoding==null?new InputStreamReader(in):new InputStreamReader(in,encoding);
316
317 copy(reader,writer);
318 return writer.toString();
319 }
320
321 /* ------------------------------------------------------------ */
322 /** Read input stream to string.
323 * @param in the reader to read from (until EOF)
324 * @return the String parsed from the reader
325 * @throws IOException if unable to read the stream (or handle the charset)
326 */
327 public static String toString(Reader in)
328 throws IOException
329 {
330 StringWriter writer=new StringWriter();
331 copy(in,writer);
332 return writer.toString();
333 }
334
335
336 /* ------------------------------------------------------------ */
337 /** Delete File.
338 * This delete will recursively delete directories - BE CAREFULL
339 * @param file The file (or directory) to be deleted.
340 * @return true if anything was deleted. (note: this does not mean that all content in a directory was deleted)
341 */
342 public static boolean delete(File file)
343 {
344 if (!file.exists())
345 return false;
346 if (file.isDirectory())
347 {
348 File[] files = file.listFiles();
349 for (int i=0;files!=null && i<files.length;i++)
350 delete(files[i]);
351 }
352 return file.delete();
353 }
354
355 /**
356 * Closes an arbitrary closable, and logs exceptions at ignore level
357 *
358 * @param closeable the closeable to close
359 */
360 public static void close(Closeable closeable)
361 {
362 try
363 {
364 if (closeable != null)
365 closeable.close();
366 }
367 catch (IOException ignore)
368 {
369 LOG.ignore(ignore);
370 }
371 }
372
373 /**
374 * closes an input stream, and logs exceptions
375 *
376 * @param is the input stream to close
377 */
378 public static void close(InputStream is)
379 {
380 close((Closeable)is);
381 }
382
383 /**
384 * closes an output stream, and logs exceptions
385 *
386 * @param os the output stream to close
387 */
388 public static void close(OutputStream os)
389 {
390 close((Closeable)os);
391 }
392
393 /**
394 * closes a reader, and logs exceptions
395 *
396 * @param reader the reader to close
397 */
398 public static void close(Reader reader)
399 {
400 close((Closeable)reader);
401 }
402
403 /**
404 * closes a writer, and logs exceptions
405 *
406 * @param writer the writer to close
407 */
408 public static void close(Writer writer)
409 {
410 close((Closeable)writer);
411 }
412
413 /* ------------------------------------------------------------ */
414 public static byte[] readBytes(InputStream in)
415 throws IOException
416 {
417 ByteArrayOutputStream bout = new ByteArrayOutputStream();
418 copy(in,bout);
419 return bout.toByteArray();
420 }
421
422 /* ------------------------------------------------------------ */
423 /**
424 * A gathering write utility wrapper.
425 * <p>
426 * This method wraps a gather write with a loop that handles the limitations of some operating systems that have a
427 * limit on the number of buffers written. The method loops on the write until either all the content is written or
428 * no progress is made.
429 *
430 * @param out
431 * The GatheringByteChannel to write to
432 * @param buffers
433 * The buffers to write
434 * @param offset
435 * The offset into the buffers array
436 * @param length
437 * The length in buffers to write
438 * @return The total bytes written
439 * @throws IOException
440 * if unable write to the GatheringByteChannel
441 */
442 public static long write(GatheringByteChannel out, ByteBuffer[] buffers, int offset, int length) throws IOException
443 {
444 long total=0;
445 write: while (length>0)
446 {
447 // Write as much as we can
448 long wrote=out.write(buffers,offset,length);
449
450 // If we can't write any more, give up
451 if (wrote==0)
452 break;
453
454 // count the total
455 total+=wrote;
456
457 // Look for unwritten content
458 for (int i=offset;i<buffers.length;i++)
459 {
460 if (buffers[i].hasRemaining())
461 {
462 // loop with new offset and length;
463 length=length-(i-offset);
464 offset=i;
465 continue write;
466 }
467 }
468 length=0;
469 }
470
471 return total;
472 }
473
474 /* ------------------------------------------------------------ */
475 /**
476 * @return An outputstream to nowhere
477 */
478 public static OutputStream getNullStream()
479 {
480 return __nullStream;
481 }
482
483 /* ------------------------------------------------------------ */
484 /**
485 * @return An outputstream to nowhere
486 */
487 public static InputStream getClosedStream()
488 {
489 return __closedStream;
490 }
491
492 /* ------------------------------------------------------------ */
493 /* ------------------------------------------------------------ */
494 private static class NullOS extends OutputStream
495 {
496 @Override
497 public void close(){}
498 @Override
499 public void flush(){}
500 @Override
501 public void write(byte[]b){}
502 @Override
503 public void write(byte[]b,int i,int l){}
504 @Override
505 public void write(int b){}
506 }
507 private static NullOS __nullStream = new NullOS();
508
509
510 /* ------------------------------------------------------------ */
511 /* ------------------------------------------------------------ */
512 private static class ClosedIS extends InputStream
513 {
514 @Override
515 public int read() throws IOException
516 {
517 return -1;
518 }
519 }
520 private static ClosedIS __closedStream = new ClosedIS();
521
522 /* ------------------------------------------------------------ */
523 /**
524 * @return An writer to nowhere
525 */
526 public static Writer getNullWriter()
527 {
528 return __nullWriter;
529 }
530
531 /* ------------------------------------------------------------ */
532 /**
533 * @return An writer to nowhere
534 */
535 public static PrintWriter getNullPrintWriter()
536 {
537 return __nullPrintWriter;
538 }
539
540 /* ------------------------------------------------------------ */
541 /* ------------------------------------------------------------ */
542 private static class NullWrite extends Writer
543 {
544 @Override
545 public void close(){}
546 @Override
547 public void flush(){}
548 @Override
549 public void write(char[]b){}
550 @Override
551 public void write(char[]b,int o,int l){}
552 @Override
553 public void write(int b){}
554 @Override
555 public void write(String s){}
556 @Override
557 public void write(String s,int o,int l){}
558 }
559 private static NullWrite __nullWriter = new NullWrite();
560 private static PrintWriter __nullPrintWriter = new PrintWriter(__nullWriter);
561
562 }
563
564
565
566
567
568
569
570
571