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
17c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathpackage libcore.net.http;
18c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
19c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.io.ByteArrayOutputStream;
20c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.io.IOException;
21c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.io.OutputStream;
22c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport libcore.util.Libcore;
23c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
24c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath/**
25c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * An HTTP request body that's completely buffered in memory. This allows
26c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * the post body to be transparently re-sent if the HTTP request must be
27c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * sent multiple times.
28c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath */
29c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathfinal class RetryableOutputStream extends AbstractHttpOutputStream {
30c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private final int limit;
31c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    private final ByteArrayOutputStream content;
32c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
33c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public RetryableOutputStream(int limit) {
34c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        this.limit = limit;
35c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        this.content = new ByteArrayOutputStream(limit);
36c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
37c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
38c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public RetryableOutputStream() {
39c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        this.limit = -1;
40c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        this.content = new ByteArrayOutputStream();
41c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
42c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
43c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    @Override public synchronized void close() {
44c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (closed) {
45c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            return;
46c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
47c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        closed = true;
48c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (content.size() < limit) {
49c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            throw new IllegalStateException("content-length promised "
50c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath                    + limit + " bytes, but received " + content.size());
51c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
52c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
53c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
54c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    @Override public synchronized void write(byte[] buffer, int offset, int count)
55c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            throws IOException {
56c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        checkNotClosed();
57c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        Libcore.checkOffsetAndCount(buffer.length, offset, count);
58c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        if (limit != -1 && content.size() > limit - count) {
59c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath            throw new IOException("exceeded content-length limit of " + limit + " bytes");
60c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        }
61c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        content.write(buffer, offset, count);
62c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
63c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
64c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public synchronized int contentLength() {
65c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        close();
66c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        return content.size();
67c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
68c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
69c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    public void writeToSocket(OutputStream socketOut) throws IOException  {
70c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        content.writeTo(socketOut);
71c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
72c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath}
73