okhttp3.internal.huc.OutputStreamRequestBody Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of okhttp-urlconnection Show documentation
Show all versions of okhttp-urlconnection Show documentation
Square’s meticulous HTTP client for Java and Kotlin.
/*
* Copyright (C) 2016 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package okhttp3.internal.huc;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.net.ProtocolException;
import java.net.SocketTimeoutException;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okio.BufferedSink;
import okio.Timeout;
/**
* A request body that's populated by blocking writes to an output stream. The output data is either
* fully buffered (with {@link BufferedRequestBody}) or streamed (with {@link StreamedRequestBody}).
* In either case the bytes of the body aren't known until the caller writes them to the output
* stream.
*/
abstract class OutputStreamRequestBody extends RequestBody {
private Timeout timeout;
private long expectedContentLength;
private OutputStream outputStream;
boolean closed;
protected void initOutputStream(final BufferedSink sink, final long expectedContentLength) {
this.timeout = sink.timeout();
this.expectedContentLength = expectedContentLength;
// An output stream that writes to sink. If expectedContentLength is not -1, then this expects
// exactly that many bytes to be written.
this.outputStream = new OutputStream() {
private long bytesReceived;
@Override public void write(int b) throws IOException {
write(new byte[] {(byte) b}, 0, 1);
}
@Override public void write(byte[] source, int offset, int byteCount) throws IOException {
if (closed) throw new IOException("closed"); // Not IllegalStateException!
if (expectedContentLength != -1L && bytesReceived + byteCount > expectedContentLength) {
throw new ProtocolException("expected " + expectedContentLength
+ " bytes but received " + bytesReceived + byteCount);
}
bytesReceived += byteCount;
try {
sink.write(source, offset, byteCount);
} catch (InterruptedIOException e) {
throw new SocketTimeoutException(e.getMessage());
}
}
@Override public void flush() throws IOException {
if (closed) return; // Weird, but consistent with historical behavior.
sink.flush();
}
@Override public void close() throws IOException {
closed = true;
if (expectedContentLength != -1L && bytesReceived < expectedContentLength) {
throw new ProtocolException("expected " + expectedContentLength
+ " bytes but received " + bytesReceived);
}
sink.close();
}
};
}
public final OutputStream outputStream() {
return outputStream;
}
public final Timeout timeout() {
return timeout;
}
public final boolean isClosed() {
return closed;
}
@Override public long contentLength() throws IOException {
return expectedContentLength;
}
@Override public final MediaType contentType() {
return null; // Let the caller provide this in a regular header.
}
public Request prepareToSendRequest(Request request) throws IOException {
return request;
}
}