1c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath/* 2c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * Copyright (C) 2010 The Android Open Source Project 3c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * 4c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * Licensed under the Apache License, Version 2.0 (the "License"); 5c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * you may not use this file except in compliance with the License. 6c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * You may obtain a copy of the License at 7c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * 8c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * http://www.apache.org/licenses/LICENSE-2.0 9c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * 10c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * Unless required by applicable law or agreed to in writing, software 11c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * distributed under the License is distributed on an "AS IS" BASIS, 12c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * See the License for the specific language governing permissions and 14c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * limitations under the License. 15c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath */ 16c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath 172231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonpackage com.squareup.okhttp.internal.http; 18c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath 19c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.io.IOException; 202231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.ProtocolException; 21e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport okio.Buffer; 223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport okio.Sink; 23e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport okio.Timeout; 24c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath 2554cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport static com.squareup.okhttp.internal.Util.checkOffsetAndCount; 2654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 27c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath/** 28c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * An HTTP request body that's completely buffered in memory. This allows 29c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * the post body to be transparently re-sent if the HTTP request must be 30c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * sent multiple times. 31c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath */ 32e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerpublic final class RetryableSink implements Sink { 333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private boolean closed; 3454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final int limit; 35e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private final Buffer content = new Buffer(); 36c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath 373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public RetryableSink(int limit) { 3854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson this.limit = limit; 3954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 40c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath 413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public RetryableSink() { 423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this(-1); 4354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 44c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath 453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void close() throws IOException { 463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (closed) return; 4754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson closed = true; 4854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (content.size() < limit) { 4954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new ProtocolException( 5054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson "content-length promised " + limit + " bytes, but received " + content.size()); 51c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath } 5254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 53c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath 54e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Override public void write(Buffer source, long byteCount) throws IOException { 553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (closed) throw new IllegalStateException("closed"); 563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller checkOffsetAndCount(source.size(), 0, byteCount); 573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (limit != -1 && content.size() > limit - byteCount) { 5854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new ProtocolException("exceeded content-length limit of " + limit + " bytes"); 59c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath } 603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller content.write(source, byteCount); 613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void flush() throws IOException { 643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 66e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Override public Timeout timeout() { 67e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return Timeout.NONE; 6854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 69c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath 703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public long contentLength() throws IOException { 7154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return content.size(); 7254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 7354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 74e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller public void writeToSocket(Sink socketOut) throws IOException { 75e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Copy the content; otherwise we won't have data to retry. 76e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Buffer buffer = new Buffer(); 77e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller content.copyTo(buffer, 0, content.size()); 78e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller socketOut.write(buffer, buffer.size()); 7954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 80c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath} 81