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 okhttp3;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.nio.charset.Charset;
21 import javax.annotation.Nullable;
22 import okhttp3.internal.Util;
23 import okio.BufferedSink;
24 import okio.ByteString;
25 import okio.Okio;
26 import okio.Source;
27
28 import static java.nio.charset.StandardCharsets.UTF_8;
29
30 public abstract class RequestBody {
31   /** Returns the Content-Type header for this body. */
32   public abstract @Nullable MediaType contentType();
33
34   /**
35    * Returns the number of bytes that will be written to {@code sink} in a call to {@link #writeTo},
36    * or -1 if that count is unknown.
37    */

38   public long contentLength() throws IOException {
39     return -1;
40   }
41
42   /** Writes the content of this request to {@code sink}. */
43   public abstract void writeTo(BufferedSink sink) throws IOException;
44
45   /**
46    * A duplex request body is special in how it is <strong>transmitted</strong> on the network and
47    * in the <strong>API contract</strong> between OkHttp and the application.
48    *
49    * <p>This method returns false unless it is overridden by a subclass.
50    *
51    * <h3>Duplex Transmission</h3>
52    *
53    * <p>With regular HTTP calls the request always completes sending before the response may begin
54    * receiving. With duplex the request and response may be interleaved! That is, request body bytes
55    * may be sent after response headers or body bytes have been received.
56    *
57    * <p>Though any call may be initiated as a duplex call, only web servers that are specially
58    * designed for this nonstandard interaction will use it. As of 2019-01, the only widely-used
59    * implementation of this pattern is <a
60    * href="https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md">gRPC</a>.
61    *
62    * <p>Because the encoding of interleaved data is not well-defined for HTTP/1, duplex request
63    * bodies may only be used with HTTP/2. Calls to HTTP/1 servers will fail before the HTTP request
64    * is transmitted. If you cannot ensure that your client and server both support HTTP/2, do not
65    * use this feature.
66    *
67    * <p>Duplex APIs</p>
68    *
69    * <p>With regular request bodies it is not legal to write bytes to the sink passed to {@link
70    * RequestBody#writeTo} after that method returns. For duplex requests bodies that condition is
71    * lifted. Such writes occur on an application-provided thread and may occur concurrently with
72    * reads of the {@link ResponseBody}. For duplex request bodies, {@link #writeTo} should return
73    * quickly, possibly by handing off the provided request body to another thread to perform
74    * writing.
75    */

76   public boolean isDuplex() {
77     return false;
78   }
79
80   /**
81    * Returns true if this body expects at most one call to {@link #writeTo} and can be transmitted
82    * at most once. This is typically used when writing the request body is destructive and it is not
83    * possible to recreate the request body after it has been sent.
84    *
85    * <p>This method returns false unless it is overridden by a subclass.
86    *
87    * <p>By default OkHttp will attempt to retransmit request bodies when the original request fails
88    * due to a stale connection, a client timeout (HTTP 408), a satisfied authorization challenge
89    * (HTTP 401 and 407), or a retryable server failure (HTTP 503 with a {@code Retry-After: 0}
90    * header).
91    */

92   public boolean isOneShot() {
93     return false;
94   }
95
96   /**
97    * Returns a new request body that transmits {@code content}. If {@code contentType} is non-null
98    * and lacks a charset, this will use UTF-8.
99    */

100   public static RequestBody create(@Nullable MediaType contentType, String content) {
101     Charset charset = UTF_8;
102     if (contentType != null) {
103       charset = contentType.charset();
104       if (charset == null) {
105         charset = UTF_8;
106         contentType = MediaType.parse(contentType + "; charset=utf-8");
107       }
108     }
109     byte[] bytes = content.getBytes(charset);
110     return create(contentType, bytes);
111   }
112
113   /** Returns a new request body that transmits {@code content}. */
114   public static RequestBody create(
115       final @Nullable MediaType contentType, final ByteString content) {
116     return new RequestBody() {
117       @Override public @Nullable MediaType contentType() {
118         return contentType;
119       }
120
121       @Override public long contentLength() throws IOException {
122         return content.size();
123       }
124
125       @Override public void writeTo(BufferedSink sink) throws IOException {
126         sink.write(content);
127       }
128     };
129   }
130
131   /** Returns a new request body that transmits {@code content}. */
132   public static RequestBody create(final @Nullable MediaType contentType, final byte[] content) {
133     return create(contentType, content, 0, content.length);
134   }
135
136   /** Returns a new request body that transmits {@code content}. */
137   public static RequestBody create(final @Nullable MediaType contentType, final byte[] content,
138       final int offset, final int byteCount) {
139     if (content == nullthrow new NullPointerException("content == null");
140     Util.checkOffsetAndCount(content.length, offset, byteCount);
141     return new RequestBody() {
142       @Override public @Nullable MediaType contentType() {
143         return contentType;
144       }
145
146       @Override public long contentLength() {
147         return byteCount;
148       }
149
150       @Override public void writeTo(BufferedSink sink) throws IOException {
151         sink.write(content, offset, byteCount);
152       }
153     };
154   }
155
156   /** Returns a new request body that transmits the content of {@code file}. */
157   public static RequestBody create(final @Nullable MediaType contentType, final File file) {
158     if (file == nullthrow new NullPointerException("file == null");
159
160     return new RequestBody() {
161       @Override public @Nullable MediaType contentType() {
162         return contentType;
163       }
164
165       @Override public long contentLength() {
166         return file.length();
167       }
168
169       @Override public void writeTo(BufferedSink sink) throws IOException {
170         try (Source source = Okio.source(file)) {
171           sink.writeAll(source);
172         }
173       }
174     };
175   }
176 }
177