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.impl.entity; 029 030import org.apache.http.Header; 031import org.apache.http.HeaderElement; 032import org.apache.http.HttpException; 033import org.apache.http.HttpMessage; 034import org.apache.http.ParseException; 035import org.apache.http.ProtocolException; 036import org.apache.http.annotation.ThreadingBehavior; 037import org.apache.http.annotation.Contract; 038import org.apache.http.entity.ContentLengthStrategy; 039import org.apache.http.protocol.HTTP; 040import org.apache.http.util.Args; 041 042/** 043 * The lax implementation of the content length strategy. This class will ignore 044 * unrecognized transfer encodings and malformed {@code Content-Length} 045 * header values. 046 * <p> 047 * This class recognizes "chunked" and "identitiy" transfer-coding only. 048 * 049 * @since 4.0 050 */ 051@Contract(threading = ThreadingBehavior.IMMUTABLE) 052public class LaxContentLengthStrategy implements ContentLengthStrategy { 053 054 public static final LaxContentLengthStrategy INSTANCE = new LaxContentLengthStrategy(); 055 056 private final int implicitLen; 057 058 /** 059 * Creates {@code LaxContentLengthStrategy} instance with the given length used per default 060 * when content length is not explicitly specified in the message. 061 * 062 * @param implicitLen implicit content length. 063 * 064 * @since 4.2 065 */ 066 public LaxContentLengthStrategy(final int implicitLen) { 067 super(); 068 this.implicitLen = implicitLen; 069 } 070 071 /** 072 * Creates {@code LaxContentLengthStrategy} instance. {@link ContentLengthStrategy#IDENTITY} 073 * is used per default when content length is not explicitly specified in the message. 074 */ 075 public LaxContentLengthStrategy() { 076 this(IDENTITY); 077 } 078 079 @Override 080 public long determineLength(final HttpMessage message) throws HttpException { 081 Args.notNull(message, "HTTP message"); 082 083 final Header transferEncodingHeader = message.getFirstHeader(HTTP.TRANSFER_ENCODING); 084 // We use Transfer-Encoding if present and ignore Content-Length. 085 // RFC2616, 4.4 item number 3 086 if (transferEncodingHeader != null) { 087 final HeaderElement[] encodings; 088 try { 089 encodings = transferEncodingHeader.getElements(); 090 } catch (final ParseException px) { 091 throw new ProtocolException 092 ("Invalid Transfer-Encoding header value: " + 093 transferEncodingHeader, px); 094 } 095 // The chunked encoding must be the last one applied RFC2616, 14.41 096 final int len = encodings.length; 097 if (HTTP.IDENTITY_CODING.equalsIgnoreCase(transferEncodingHeader.getValue())) { 098 return IDENTITY; 099 } else if ((len > 0) && (HTTP.CHUNK_CODING.equalsIgnoreCase( 100 encodings[len - 1].getName()))) { 101 return CHUNKED; 102 } else { 103 return IDENTITY; 104 } 105 } 106 final Header contentLengthHeader = message.getFirstHeader(HTTP.CONTENT_LEN); 107 if (contentLengthHeader != null) { 108 long contentlen = -1; 109 final Header[] headers = message.getHeaders(HTTP.CONTENT_LEN); 110 for (int i = headers.length - 1; i >= 0; i--) { 111 final Header header = headers[i]; 112 try { 113 contentlen = Long.parseLong(header.getValue()); 114 break; 115 } catch (final NumberFormatException ignore) { 116 } 117 // See if we can have better luck with another header, if present 118 } 119 if (contentlen >= 0) { 120 return contentlen; 121 } else { 122 return IDENTITY; 123 } 124 } 125 return this.implicitLen; 126 } 127 128}