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