1 /* 2 * Copyright (C) 2014 Square, Inc. 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 package com.squareup.okhttp; 17 18 import com.squareup.okhttp.internal.Util; 19 import java.io.Closeable; 20 import java.io.IOException; 21 import java.io.InputStream; 22 import java.io.InputStreamReader; 23 import java.io.Reader; 24 import java.nio.charset.Charset; 25 import okio.Buffer; 26 import okio.BufferedSource; 27 28 import static com.squareup.okhttp.internal.Util.UTF_8; 29 30 public abstract class ResponseBody implements Closeable { 31 /** Multiple calls to {@link #charStream()} must return the same instance. */ 32 private Reader reader; 33 contentType()34 public abstract MediaType contentType(); 35 36 /** 37 * Returns the number of bytes in that will returned by {@link #bytes}, or 38 * {@link #byteStream}, or -1 if unknown. 39 */ contentLength()40 public abstract long contentLength() throws IOException; 41 byteStream()42 public final InputStream byteStream() throws IOException { 43 return source().inputStream(); 44 } 45 source()46 public abstract BufferedSource source() throws IOException; 47 bytes()48 public final byte[] bytes() throws IOException { 49 long contentLength = contentLength(); 50 if (contentLength > Integer.MAX_VALUE) { 51 throw new IOException("Cannot buffer entire body for content length: " + contentLength); 52 } 53 54 BufferedSource source = source(); 55 byte[] bytes; 56 try { 57 bytes = source.readByteArray(); 58 } finally { 59 Util.closeQuietly(source); 60 } 61 if (contentLength != -1 && contentLength != bytes.length) { 62 throw new IOException("Content-Length and stream length disagree"); 63 } 64 return bytes; 65 } 66 67 /** 68 * Returns the response as a character stream decoded with the charset 69 * of the Content-Type header. If that header is either absent or lacks a 70 * charset, this will attempt to decode the response body as UTF-8. 71 */ charStream()72 public final Reader charStream() throws IOException { 73 Reader r = reader; 74 return r != null ? r : (reader = new InputStreamReader(byteStream(), charset())); 75 } 76 77 /** 78 * Returns the response as a string decoded with the charset of the 79 * Content-Type header. If that header is either absent or lacks a charset, 80 * this will attempt to decode the response body as UTF-8. 81 */ string()82 public final String string() throws IOException { 83 return new String(bytes(), charset().name()); 84 } 85 charset()86 private Charset charset() { 87 MediaType contentType = contentType(); 88 return contentType != null ? contentType.charset(UTF_8) : UTF_8; 89 } 90 close()91 @Override public void close() throws IOException { 92 source().close(); 93 } 94 95 /** 96 * Returns a new response body that transmits {@code content}. If {@code 97 * contentType} is non-null and lacks a charset, this will use UTF-8. 98 */ create(MediaType contentType, String content)99 public static ResponseBody create(MediaType contentType, String content) { 100 Charset charset = Util.UTF_8; 101 if (contentType != null) { 102 charset = contentType.charset(); 103 if (charset == null) { 104 charset = Util.UTF_8; 105 contentType = MediaType.parse(contentType + "; charset=utf-8"); 106 } 107 } 108 Buffer buffer = new Buffer().writeString(content, charset); 109 return create(contentType, buffer.size(), buffer); 110 } 111 112 /** Returns a new response body that transmits {@code content}. */ create(final MediaType contentType, byte[] content)113 public static ResponseBody create(final MediaType contentType, byte[] content) { 114 Buffer buffer = new Buffer().write(content); 115 return create(contentType, content.length, buffer); 116 } 117 118 /** Returns a new response body that transmits {@code content}. */ create( final MediaType contentType, final long contentLength, final BufferedSource content)119 public static ResponseBody create( 120 final MediaType contentType, final long contentLength, final BufferedSource content) { 121 if (content == null) throw new NullPointerException("source == null"); 122 return new ResponseBody() { 123 @Override public MediaType contentType() { 124 return contentType; 125 } 126 127 @Override public long contentLength() { 128 return contentLength; 129 } 130 131 @Override public BufferedSource source() { 132 return content; 133 } 134 }; 135 } 136 } 137