1 /* 2 * ==================================================================== 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * ==================================================================== 20 * 21 * This software consists of voluntary contributions made by many 22 * individuals on behalf of the Apache Software Foundation. For more 23 * information on the Apache Software Foundation, please see 24 * <http://www.apache.org/>. 25 * 26 */ 27 28 package org.apache.http.entity; 29 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.io.OutputStream; 33 34 import org.apache.http.util.Args; 35 36 /** 37 * A streamed, non-repeatable entity that obtains its content from 38 * an {@link InputStream}. 39 * 40 * @since 4.0 41 */ 42 public class InputStreamEntity extends AbstractHttpEntity { 43 44 private final InputStream content; 45 private final long length; 46 47 /** 48 * Creates an entity with an unknown length. 49 * Equivalent to {@code new InputStreamEntity(inStream, -1)}. 50 * 51 * @param inStream input stream 52 * @throws IllegalArgumentException if {@code inStream} is {@code null} 53 * @since 4.3 54 */ 55 public InputStreamEntity(final InputStream inStream) { 56 this(inStream, -1); 57 } 58 59 /** 60 * Creates an entity with a specified content length. 61 * 62 * @param inStream input stream 63 * @param length of the input stream, {@code -1} if unknown 64 * @throws IllegalArgumentException if {@code inStream} is {@code null} 65 */ 66 public InputStreamEntity(final InputStream inStream, final long length) { 67 this(inStream, length, null); 68 } 69 70 /** 71 * Creates an entity with a content type and unknown length. 72 * Equivalent to {@code new InputStreamEntity(inStream, -1, contentType)}. 73 * 74 * @param inStream input stream 75 * @param contentType content type 76 * @throws IllegalArgumentException if {@code inStream} is {@code null} 77 * @since 4.3 78 */ 79 public InputStreamEntity(final InputStream inStream, final ContentType contentType) { 80 this(inStream, -1, contentType); 81 } 82 83 /** 84 * @param inStream input stream 85 * @param length of the input stream, {@code -1} if unknown 86 * @param contentType for specifying the {@code Content-Type} header, may be {@code null} 87 * @throws IllegalArgumentException if {@code inStream} is {@code null} 88 * @since 4.2 89 */ 90 public InputStreamEntity(final InputStream inStream, final long length, final ContentType contentType) { 91 super(); 92 this.content = Args.notNull(inStream, "Source input stream"); 93 this.length = length; 94 if (contentType != null) { 95 setContentType(contentType.toString()); 96 } 97 } 98 99 @Override 100 public boolean isRepeatable() { 101 return false; 102 } 103 104 /** 105 * @return the content length or {@code -1} if unknown 106 */ 107 @Override 108 public long getContentLength() { 109 return this.length; 110 } 111 112 @Override 113 public InputStream getContent() throws IOException { 114 return this.content; 115 } 116 117 /** 118 * Writes bytes from the {@code InputStream} this entity was constructed 119 * with to an {@code OutputStream}. The content length 120 * determines how many bytes are written. If the length is unknown ({@code -1}), the 121 * stream will be completely consumed (to the end of the stream). 122 * 123 */ 124 @Override 125 public void writeTo(final OutputStream outStream) throws IOException { 126 Args.notNull(outStream, "Output stream"); 127 final InputStream inStream = this.content; 128 try { 129 final byte[] buffer = new byte[OUTPUT_BUFFER_SIZE]; 130 int readLen; 131 if (this.length < 0) { 132 // consume until EOF 133 while ((readLen = inStream.read(buffer)) != -1) { 134 outStream.write(buffer, 0, readLen); 135 } 136 } else { 137 // consume no more than length 138 long remaining = this.length; 139 while (remaining > 0) { 140 readLen = inStream.read(buffer, 0, (int)Math.min(OUTPUT_BUFFER_SIZE, remaining)); 141 if (readLen == -1) { 142 break; 143 } 144 outStream.write(buffer, 0, readLen); 145 remaining -= readLen; 146 } 147 } 148 } finally { 149 inStream.close(); 150 } 151 } 152 153 @Override 154 public boolean isStreaming() { 155 return true; 156 } 157 158 }