001/* 002 * ==================================================================== 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 * ==================================================================== 020 * 021 * This software consists of voluntary contributions made by many 022 * individuals on behalf of the Apache Software Foundation. For more 023 * information on the Apache Software Foundation, please see 024 * <http://www.apache.org/>. 025 * 026 */ 027 028package org.apache.http.entity; 029 030import java.io.IOException; 031import java.io.InputStream; 032import java.io.OutputStream; 033 034import org.apache.http.util.Args; 035 036/** 037 * A streamed, non-repeatable entity that obtains its content from 038 * an {@link InputStream}. 039 * 040 * @since 4.0 041 */ 042public class InputStreamEntity extends AbstractHttpEntity { 043 044 private final InputStream content; 045 private final long length; 046 047 /** 048 * Creates an entity with an unknown length. 049 * Equivalent to {@code new InputStreamEntity(instream, -1)}. 050 * 051 * @param instream input stream 052 * @throws IllegalArgumentException if {@code instream} is {@code null} 053 * @since 4.3 054 */ 055 public InputStreamEntity(final InputStream instream) { 056 this(instream, -1); 057 } 058 059 /** 060 * Creates an entity with a specified content length. 061 * 062 * @param instream input stream 063 * @param length of the input stream, {@code -1} if unknown 064 * @throws IllegalArgumentException if {@code instream} is {@code null} 065 */ 066 public InputStreamEntity(final InputStream instream, final long length) { 067 this(instream, length, null); 068 } 069 070 /** 071 * Creates an entity with a content type and unknown length. 072 * Equivalent to {@code new InputStreamEntity(instream, -1, contentType)}. 073 * 074 * @param instream input stream 075 * @param contentType content type 076 * @throws IllegalArgumentException if {@code instream} is {@code null} 077 * @since 4.3 078 */ 079 public InputStreamEntity(final InputStream instream, final ContentType contentType) { 080 this(instream, -1, contentType); 081 } 082 083 /** 084 * @param instream input stream 085 * @param length of the input stream, {@code -1} if unknown 086 * @param contentType for specifying the {@code Content-Type} header, may be {@code null} 087 * @throws IllegalArgumentException if {@code instream} is {@code null} 088 * @since 4.2 089 */ 090 public InputStreamEntity(final InputStream instream, final long length, final ContentType contentType) { 091 super(); 092 this.content = Args.notNull(instream, "Source input stream"); 093 this.length = length; 094 if (contentType != null) { 095 setContentType(contentType.toString()); 096 } 097 } 098 099 @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 l; 131 if (this.length < 0) { 132 // consume until EOF 133 while ((l = instream.read(buffer)) != -1) { 134 outstream.write(buffer, 0, l); 135 } 136 } else { 137 // consume no more than length 138 long remaining = this.length; 139 while (remaining > 0) { 140 l = instream.read(buffer, 0, (int)Math.min(OUTPUT_BUFFER_SIZE, remaining)); 141 if (l == -1) { 142 break; 143 } 144 outstream.write(buffer, 0, l); 145 remaining -= l; 146 } 147 } 148 } finally { 149 instream.close(); 150 } 151 } 152 153 @Override 154 public boolean isStreaming() { 155 return true; 156 } 157 158}