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