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 */
16package com.squareup.okhttp;
17
18import com.squareup.okhttp.internal.Util;
19import java.io.File;
20import java.io.IOException;
21import java.nio.charset.Charset;
22import okio.BufferedSink;
23import okio.ByteString;
24import okio.Okio;
25import okio.Source;
26
27public abstract class RequestBody {
28  /** Returns the Content-Type header for this body. */
29  public abstract MediaType contentType();
30
31  /**
32   * Returns the number of bytes that will be written to {@code out} in a call
33   * to {@link #writeTo}, or -1 if that count is unknown.
34   */
35  public long contentLength() throws IOException {
36    return -1;
37  }
38
39  /** Writes the content of this request to {@code out}. */
40  public abstract void writeTo(BufferedSink sink) throws IOException;
41
42  /**
43   * Returns a new request body that transmits {@code content}. If {@code
44   * contentType} is non-null and lacks a charset, this will use UTF-8.
45   */
46  public static RequestBody create(MediaType contentType, String content) {
47    Charset charset = Util.UTF_8;
48    if (contentType != null) {
49      charset = contentType.charset();
50      if (charset == null) {
51        charset = Util.UTF_8;
52        contentType = MediaType.parse(contentType + "; charset=utf-8");
53      }
54    }
55    byte[] bytes = content.getBytes(charset);
56    return create(contentType, bytes);
57  }
58
59  /** Returns a new request body that transmits {@code content}. */
60  public static RequestBody create(final MediaType contentType, final ByteString content) {
61    return new RequestBody() {
62      @Override public MediaType contentType() {
63        return contentType;
64      }
65
66      @Override public long contentLength() throws IOException {
67        return content.size();
68      }
69
70      @Override public void writeTo(BufferedSink sink) throws IOException {
71        sink.write(content);
72      }
73    };
74  }
75
76  /** Returns a new request body that transmits {@code content}. */
77  public static RequestBody create(final MediaType contentType, final byte[] content) {
78    return create(contentType, content, 0, content.length);
79  }
80
81  /** Returns a new request body that transmits {@code content}. */
82  public static RequestBody create(final MediaType contentType, final byte[] content,
83      final int offset, final int byteCount) {
84    if (content == null) throw new NullPointerException("content == null");
85    Util.checkOffsetAndCount(content.length, offset, byteCount);
86    return new RequestBody() {
87      @Override public MediaType contentType() {
88        return contentType;
89      }
90
91      @Override public long contentLength() {
92        return byteCount;
93      }
94
95      @Override public void writeTo(BufferedSink sink) throws IOException {
96        sink.write(content, offset, byteCount);
97      }
98    };
99  }
100
101  /** Returns a new request body that transmits the content of {@code file}. */
102  public static RequestBody create(final MediaType contentType, final File file) {
103    if (file == null) throw new NullPointerException("content == null");
104
105    return new RequestBody() {
106      @Override public MediaType contentType() {
107        return contentType;
108      }
109
110      @Override public long contentLength() {
111        return file.length();
112      }
113
114      @Override public void writeTo(BufferedSink sink) throws IOException {
115        Source source = null;
116        try {
117          source = Okio.source(file);
118          sink.writeAll(source);
119        } finally {
120          Util.closeQuietly(source);
121        }
122      }
123    };
124  }
125}
126