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.util; 029 030import java.io.IOException; 031import java.io.InputStream; 032import java.io.InputStreamReader; 033import java.io.Reader; 034import java.io.UnsupportedEncodingException; 035import java.nio.charset.Charset; 036import java.nio.charset.UnsupportedCharsetException; 037 038import org.apache.http.HeaderElement; 039import org.apache.http.HttpEntity; 040import org.apache.http.HttpResponse; 041import org.apache.http.NameValuePair; 042import org.apache.http.ParseException; 043import org.apache.http.entity.ContentType; 044import org.apache.http.protocol.HTTP; 045 046/** 047 * Static helpers for dealing with {@link HttpEntity}s. 048 * 049 * @since 4.0 050 */ 051public final class EntityUtils { 052 053 private static final int DEFAULT_BUFFER_SIZE = 4096; 054 055 private EntityUtils() { 056 } 057 058 /** 059 * Ensures that the entity content is fully consumed and the content stream, if exists, 060 * is closed. The process is done, <i>quietly</i> , without throwing any IOException. 061 * 062 * @param entity the entity to consume. 063 * 064 * 065 * @since 4.2 066 */ 067 public static void consumeQuietly(final HttpEntity entity) { 068 try { 069 consume(entity); 070 } catch (final IOException ignore) { 071 } 072 } 073 074 /** 075 * Ensures that the entity content is fully consumed and the content stream, if exists, 076 * is closed. 077 * 078 * @param entity the entity to consume. 079 * @throws IOException if an error occurs reading the input stream 080 * 081 * @since 4.1 082 */ 083 public static void consume(final HttpEntity entity) throws IOException { 084 if (entity == null) { 085 return; 086 } 087 if (entity.isStreaming()) { 088 final InputStream instream = entity.getContent(); 089 if (instream != null) { 090 instream.close(); 091 } 092 } 093 } 094 095 /** 096 * Updates an entity in a response by first consuming an existing entity, then setting the new one. 097 * 098 * @param response the response with an entity to update; must not be null. 099 * @param entity the entity to set in the response. 100 * @throws IOException if an error occurs while reading the input stream on the existing 101 * entity. 102 * @throws IllegalArgumentException if response is null. 103 * 104 * @since 4.3 105 */ 106 public static void updateEntity( 107 final HttpResponse response, final HttpEntity entity) throws IOException { 108 Args.notNull(response, "Response"); 109 consume(response.getEntity()); 110 response.setEntity(entity); 111 } 112 113 /** 114 * Read the contents of an entity and return it as a byte array. 115 * 116 * @param entity the entity to read from= 117 * @return byte array containing the entity content. May be null if 118 * {@link HttpEntity#getContent()} is null. 119 * @throws IOException if an error occurs reading the input stream 120 * @throws IllegalArgumentException if entity is null or if content length > Integer.MAX_VALUE 121 */ 122 public static byte[] toByteArray(final HttpEntity entity) throws IOException { 123 Args.notNull(entity, "Entity"); 124 final InputStream instream = entity.getContent(); 125 if (instream == null) { 126 return null; 127 } 128 try { 129 Args.check(entity.getContentLength() <= Integer.MAX_VALUE, 130 "HTTP entity too large to be buffered in memory"); 131 int capacity = (int)entity.getContentLength(); 132 if (capacity < 0) { 133 capacity = DEFAULT_BUFFER_SIZE; 134 } 135 final ByteArrayBuffer buffer = new ByteArrayBuffer(capacity); 136 final byte[] tmp = new byte[DEFAULT_BUFFER_SIZE]; 137 int l; 138 while((l = instream.read(tmp)) != -1) { 139 buffer.append(tmp, 0, l); 140 } 141 return buffer.toByteArray(); 142 } finally { 143 instream.close(); 144 } 145 } 146 147 /** 148 * Obtains character set of the entity, if known. 149 * 150 * @param entity must not be null 151 * @return the character set, or null if not found 152 * @throws ParseException if header elements cannot be parsed 153 * @throws IllegalArgumentException if entity is null 154 * 155 * @deprecated (4.1.3) use {@link ContentType#getOrDefault(HttpEntity)} 156 */ 157 @Deprecated 158 public static String getContentCharSet(final HttpEntity entity) throws ParseException { 159 Args.notNull(entity, "Entity"); 160 String charset = null; 161 if (entity.getContentType() != null) { 162 final HeaderElement values[] = entity.getContentType().getElements(); 163 if (values.length > 0) { 164 final NameValuePair param = values[0].getParameterByName("charset"); 165 if (param != null) { 166 charset = param.getValue(); 167 } 168 } 169 } 170 return charset; 171 } 172 173 /** 174 * Obtains MIME type of the entity, if known. 175 * 176 * @param entity must not be null 177 * @return the character set, or null if not found 178 * @throws ParseException if header elements cannot be parsed 179 * @throws IllegalArgumentException if entity is null 180 * 181 * @since 4.1 182 * 183 * @deprecated (4.1.3) use {@link ContentType#getOrDefault(HttpEntity)} 184 */ 185 @Deprecated 186 public static String getContentMimeType(final HttpEntity entity) throws ParseException { 187 Args.notNull(entity, "Entity"); 188 String mimeType = null; 189 if (entity.getContentType() != null) { 190 final HeaderElement values[] = entity.getContentType().getElements(); 191 if (values.length > 0) { 192 mimeType = values[0].getName(); 193 } 194 } 195 return mimeType; 196 } 197 198 private static String toString( 199 final HttpEntity entity, 200 final ContentType contentType) throws IOException { 201 final InputStream instream = entity.getContent(); 202 if (instream == null) { 203 return null; 204 } 205 try { 206 Args.check(entity.getContentLength() <= Integer.MAX_VALUE, 207 "HTTP entity too large to be buffered in memory"); 208 int capacity = (int)entity.getContentLength(); 209 if (capacity < 0) { 210 capacity = DEFAULT_BUFFER_SIZE; 211 } 212 Charset charset = null; 213 if (contentType != null) { 214 charset = contentType.getCharset(); 215 if (charset == null) { 216 final ContentType defaultContentType = ContentType.getByMimeType(contentType.getMimeType()); 217 charset = defaultContentType != null ? defaultContentType.getCharset() : null; 218 } 219 } 220 if (charset == null) { 221 charset = HTTP.DEF_CONTENT_CHARSET; 222 } 223 final Reader reader = new InputStreamReader(instream, charset); 224 final CharArrayBuffer buffer = new CharArrayBuffer(capacity); 225 final char[] tmp = new char[1024]; 226 int l; 227 while((l = reader.read(tmp)) != -1) { 228 buffer.append(tmp, 0, l); 229 } 230 return buffer.toString(); 231 } finally { 232 instream.close(); 233 } 234 } 235 236 /** 237 * Get the entity content as a String, using the provided default character set 238 * if none is found in the entity. 239 * If defaultCharset is null, the default "ISO-8859-1" is used. 240 * 241 * @param entity must not be null 242 * @param defaultCharset character set to be applied if none found in the entity, 243 * or if the entity provided charset is invalid or not available. 244 * @return the entity content as a String. May be null if 245 * {@link HttpEntity#getContent()} is null. 246 * @throws ParseException if header elements cannot be parsed 247 * @throws IllegalArgumentException if entity is null or if content length > Integer.MAX_VALUE 248 * @throws IOException if an error occurs reading the input stream 249 * @throws java.nio.charset.UnsupportedCharsetException Thrown when the named entity's charset is not available in 250 * this instance of the Java virtual machine and no defaultCharset is provided. 251 */ 252 public static String toString( 253 final HttpEntity entity, final Charset defaultCharset) throws IOException, ParseException { 254 Args.notNull(entity, "Entity"); 255 ContentType contentType = null; 256 try { 257 contentType = ContentType.get(entity); 258 } catch (final UnsupportedCharsetException ex) { 259 if (defaultCharset == null) { 260 throw new UnsupportedEncodingException(ex.getMessage()); 261 } 262 } 263 if (contentType != null) { 264 if (contentType.getCharset() == null) { 265 contentType = contentType.withCharset(defaultCharset); 266 } 267 } else { 268 contentType = ContentType.DEFAULT_TEXT.withCharset(defaultCharset); 269 } 270 return toString(entity, contentType); 271 } 272 273 /** 274 * Get the entity content as a String, using the provided default character set 275 * if none is found in the entity. 276 * If defaultCharset is null, the default "ISO-8859-1" is used. 277 * 278 * @param entity must not be null 279 * @param defaultCharset character set to be applied if none found in the entity 280 * @return the entity content as a String. May be null if 281 * {@link HttpEntity#getContent()} is null. 282 * @throws ParseException if header elements cannot be parsed 283 * @throws IllegalArgumentException if entity is null or if content length > Integer.MAX_VALUE 284 * @throws IOException if an error occurs reading the input stream 285 * @throws java.nio.charset.UnsupportedCharsetException Thrown when the named charset is not available in 286 * this instance of the Java virtual machine 287 */ 288 public static String toString( 289 final HttpEntity entity, final String defaultCharset) throws IOException, ParseException { 290 return toString(entity, defaultCharset != null ? Charset.forName(defaultCharset) : null); 291 } 292 293 /** 294 * Read the contents of an entity and return it as a String. 295 * The content is converted using the character set from the entity (if any), 296 * failing that, "ISO-8859-1" is used. 297 * 298 * @param entity the entity to convert to a string; must not be null 299 * @return String containing the content. 300 * @throws ParseException if header elements cannot be parsed 301 * @throws IllegalArgumentException if entity is null or if content length > Integer.MAX_VALUE 302 * @throws IOException if an error occurs reading the input stream 303 * @throws java.nio.charset.UnsupportedCharsetException Thrown when the named charset is not available in 304 * this instance of the Java virtual machine 305 */ 306 public static String toString(final HttpEntity entity) throws IOException, ParseException { 307 Args.notNull(entity, "Entity"); 308 return toString(entity, ContentType.get(entity)); 309 } 310 311}