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