Home | History | Annotate | Download | only in internal
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * 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,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.squareup.okhttp.internal;
     18 
     19 import java.io.Closeable;
     20 import java.io.EOFException;
     21 import java.io.File;
     22 import java.io.IOException;
     23 import java.io.InputStream;
     24 import java.io.OutputStream;
     25 import java.io.Reader;
     26 import java.io.StringWriter;
     27 import java.net.Socket;
     28 import java.net.URI;
     29 import java.net.URL;
     30 import java.nio.ByteOrder;
     31 import java.nio.charset.Charset;
     32 import java.util.ArrayList;
     33 import java.util.Collections;
     34 import java.util.List;
     35 import java.util.concurrent.ThreadFactory;
     36 import java.util.concurrent.atomic.AtomicReference;
     37 
     38 /** Junk drawer of utility methods. */
     39 public final class Util {
     40   public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
     41   public static final String[] EMPTY_STRING_ARRAY = new String[0];
     42 
     43   /** A cheap and type-safe constant for the ISO-8859-1 Charset. */
     44   public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
     45 
     46   /** A cheap and type-safe constant for the US-ASCII Charset. */
     47   public static final Charset US_ASCII = Charset.forName("US-ASCII");
     48 
     49   /** A cheap and type-safe constant for the UTF-8 Charset. */
     50   public static final Charset UTF_8 = Charset.forName("UTF-8");
     51   private static AtomicReference<byte[]> skipBuffer = new AtomicReference<byte[]>();
     52 
     53   private Util() {
     54   }
     55 
     56   public static int getEffectivePort(URI uri) {
     57     return getEffectivePort(uri.getScheme(), uri.getPort());
     58   }
     59 
     60   public static int getEffectivePort(URL url) {
     61     return getEffectivePort(url.getProtocol(), url.getPort());
     62   }
     63 
     64   private static int getEffectivePort(String scheme, int specifiedPort) {
     65     return specifiedPort != -1 ? specifiedPort : getDefaultPort(scheme);
     66   }
     67 
     68   public static int getDefaultPort(String scheme) {
     69     if ("http".equalsIgnoreCase(scheme)) {
     70       return 80;
     71     } else if ("https".equalsIgnoreCase(scheme)) {
     72       return 443;
     73     } else {
     74       return -1;
     75     }
     76   }
     77 
     78   public static void checkOffsetAndCount(int arrayLength, int offset, int count) {
     79     if ((offset | count) < 0 || offset > arrayLength || arrayLength - offset < count) {
     80       throw new ArrayIndexOutOfBoundsException();
     81     }
     82   }
     83 
     84   public static void pokeInt(byte[] dst, int offset, int value, ByteOrder order) {
     85     if (order == ByteOrder.BIG_ENDIAN) {
     86       dst[offset++] = (byte) ((value >> 24) & 0xff);
     87       dst[offset++] = (byte) ((value >> 16) & 0xff);
     88       dst[offset++] = (byte) ((value >> 8) & 0xff);
     89       dst[offset] = (byte) ((value >> 0) & 0xff);
     90     } else {
     91       dst[offset++] = (byte) ((value >> 0) & 0xff);
     92       dst[offset++] = (byte) ((value >> 8) & 0xff);
     93       dst[offset++] = (byte) ((value >> 16) & 0xff);
     94       dst[offset] = (byte) ((value >> 24) & 0xff);
     95     }
     96   }
     97 
     98   /** Returns true if two possibly-null objects are equal. */
     99   public static boolean equal(Object a, Object b) {
    100     return a == b || (a != null && a.equals(b));
    101   }
    102 
    103   /**
    104    * Closes {@code closeable}, ignoring any checked exceptions. Does nothing
    105    * if {@code closeable} is null.
    106    */
    107   public static void closeQuietly(Closeable closeable) {
    108     if (closeable != null) {
    109       try {
    110         closeable.close();
    111       } catch (RuntimeException rethrown) {
    112         throw rethrown;
    113       } catch (Exception ignored) {
    114       }
    115     }
    116   }
    117 
    118   /**
    119    * Closes {@code socket}, ignoring any checked exceptions. Does nothing if
    120    * {@code socket} is null.
    121    */
    122   public static void closeQuietly(Socket socket) {
    123     if (socket != null) {
    124       try {
    125         socket.close();
    126       } catch (RuntimeException rethrown) {
    127         throw rethrown;
    128       } catch (Exception ignored) {
    129       }
    130     }
    131   }
    132 
    133   /**
    134    * Closes {@code a} and {@code b}. If either close fails, this completes
    135    * the other close and rethrows the first encountered exception.
    136    */
    137   public static void closeAll(Closeable a, Closeable b) throws IOException {
    138     Throwable thrown = null;
    139     try {
    140       a.close();
    141     } catch (Throwable e) {
    142       thrown = e;
    143     }
    144     try {
    145       b.close();
    146     } catch (Throwable e) {
    147       if (thrown == null) thrown = e;
    148     }
    149     if (thrown == null) return;
    150     if (thrown instanceof IOException) throw (IOException) thrown;
    151     if (thrown instanceof RuntimeException) throw (RuntimeException) thrown;
    152     if (thrown instanceof Error) throw (Error) thrown;
    153     throw new AssertionError(thrown);
    154   }
    155 
    156   /**
    157    * Deletes the contents of {@code dir}. Throws an IOException if any file
    158    * could not be deleted, or if {@code dir} is not a readable directory.
    159    */
    160   public static void deleteContents(File dir) throws IOException {
    161     File[] files = dir.listFiles();
    162     if (files == null) {
    163       throw new IOException("not a readable directory: " + dir);
    164     }
    165     for (File file : files) {
    166       if (file.isDirectory()) {
    167         deleteContents(file);
    168       }
    169       if (!file.delete()) {
    170         throw new IOException("failed to delete file: " + file);
    171       }
    172     }
    173   }
    174 
    175   /**
    176    * Implements InputStream.read(int) in terms of InputStream.read(byte[], int, int).
    177    * InputStream assumes that you implement InputStream.read(int) and provides default
    178    * implementations of the others, but often the opposite is more efficient.
    179    */
    180   public static int readSingleByte(InputStream in) throws IOException {
    181     byte[] buffer = new byte[1];
    182     int result = in.read(buffer, 0, 1);
    183     return (result != -1) ? buffer[0] & 0xff : -1;
    184   }
    185 
    186   /**
    187    * Implements OutputStream.write(int) in terms of OutputStream.write(byte[], int, int).
    188    * OutputStream assumes that you implement OutputStream.write(int) and provides default
    189    * implementations of the others, but often the opposite is more efficient.
    190    */
    191   public static void writeSingleByte(OutputStream out, int b) throws IOException {
    192     byte[] buffer = new byte[1];
    193     buffer[0] = (byte) (b & 0xff);
    194     out.write(buffer);
    195   }
    196 
    197   /**
    198    * Fills 'dst' with bytes from 'in', throwing EOFException if insufficient bytes are available.
    199    */
    200   public static void readFully(InputStream in, byte[] dst) throws IOException {
    201     readFully(in, dst, 0, dst.length);
    202   }
    203 
    204   /**
    205    * Reads exactly 'byteCount' bytes from 'in' (into 'dst' at offset 'offset'), and throws
    206    * EOFException if insufficient bytes are available.
    207    *
    208    * Used to implement {@link java.io.DataInputStream#readFully(byte[], int, int)}.
    209    */
    210   public static void readFully(InputStream in, byte[] dst, int offset, int byteCount)
    211       throws IOException {
    212     if (byteCount == 0) {
    213       return;
    214     }
    215     if (in == null) {
    216       throw new NullPointerException("in == null");
    217     }
    218     if (dst == null) {
    219       throw new NullPointerException("dst == null");
    220     }
    221     checkOffsetAndCount(dst.length, offset, byteCount);
    222     while (byteCount > 0) {
    223       int bytesRead = in.read(dst, offset, byteCount);
    224       if (bytesRead < 0) {
    225         throw new EOFException();
    226       }
    227       offset += bytesRead;
    228       byteCount -= bytesRead;
    229     }
    230   }
    231 
    232   /** Returns the remainder of 'reader' as a string, closing it when done. */
    233   public static String readFully(Reader reader) throws IOException {
    234     try {
    235       StringWriter writer = new StringWriter();
    236       char[] buffer = new char[1024];
    237       int count;
    238       while ((count = reader.read(buffer)) != -1) {
    239         writer.write(buffer, 0, count);
    240       }
    241       return writer.toString();
    242     } finally {
    243       reader.close();
    244     }
    245   }
    246 
    247   public static void skipAll(InputStream in) throws IOException {
    248     do {
    249       in.skip(Long.MAX_VALUE);
    250     } while (in.read() != -1);
    251   }
    252 
    253   /**
    254    * Call {@code in.read()} repeatedly until either the stream is exhausted or
    255    * {@code byteCount} bytes have been read.
    256    *
    257    * <p>This method reuses the skip buffer but is careful to never use it at
    258    * the same time that another stream is using it. Otherwise streams that use
    259    * the caller's buffer for consistency checks like CRC could be clobbered by
    260    * other threads. A thread-local buffer is also insufficient because some
    261    * streams may call other streams in their skip() method, also clobbering the
    262    * buffer.
    263    */
    264   public static long skipByReading(InputStream in, long byteCount) throws IOException {
    265     // acquire the shared skip buffer.
    266     byte[] buffer = skipBuffer.getAndSet(null);
    267     if (buffer == null) {
    268       buffer = new byte[4096];
    269     }
    270 
    271     long skipped = 0;
    272     while (skipped < byteCount) {
    273       int toRead = (int) Math.min(byteCount - skipped, buffer.length);
    274       int read = in.read(buffer, 0, toRead);
    275       if (read == -1) {
    276         break;
    277       }
    278       skipped += read;
    279       if (read < toRead) {
    280         break;
    281       }
    282     }
    283 
    284     // release the shared skip buffer.
    285     skipBuffer.set(buffer);
    286 
    287     return skipped;
    288   }
    289 
    290   /**
    291    * Copies all of the bytes from {@code in} to {@code out}. Neither stream is closed.
    292    * Returns the total number of bytes transferred.
    293    */
    294   public static int copy(InputStream in, OutputStream out) throws IOException {
    295     int total = 0;
    296     byte[] buffer = new byte[8192];
    297     int c;
    298     while ((c = in.read(buffer)) != -1) {
    299       total += c;
    300       out.write(buffer, 0, c);
    301     }
    302     return total;
    303   }
    304 
    305   /**
    306    * Returns the ASCII characters up to but not including the next "\r\n", or
    307    * "\n".
    308    *
    309    * @throws java.io.EOFException if the stream is exhausted before the next newline
    310    * character.
    311    */
    312   public static String readAsciiLine(InputStream in) throws IOException {
    313     // TODO: support UTF-8 here instead
    314     StringBuilder result = new StringBuilder(80);
    315     while (true) {
    316       int c = in.read();
    317       if (c == -1) {
    318         throw new EOFException();
    319       } else if (c == '\n') {
    320         break;
    321       }
    322 
    323       result.append((char) c);
    324     }
    325     int length = result.length();
    326     if (length > 0 && result.charAt(length - 1) == '\r') {
    327       result.setLength(length - 1);
    328     }
    329     return result.toString();
    330   }
    331 
    332   /** Returns an immutable copy of {@code list}. */
    333   public static <T> List<T> immutableList(List<T> list) {
    334     return Collections.unmodifiableList(new ArrayList<T>(list));
    335   }
    336 
    337   public static ThreadFactory daemonThreadFactory(final String name) {
    338     return new ThreadFactory() {
    339       @Override public Thread newThread(Runnable runnable) {
    340         Thread result = new Thread(runnable, name);
    341         result.setDaemon(true);
    342         return result;
    343       }
    344     };
    345   }
    346 }
    347