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.protocol;
29
30 import java.io.IOException;
31
32 import org.apache.http.HttpEntity;
33 import org.apache.http.HttpException;
34 import org.apache.http.HttpResponse;
35 import org.apache.http.HttpResponseInterceptor;
36 import org.apache.http.HttpStatus;
37 import org.apache.http.HttpVersion;
38 import org.apache.http.ProtocolException;
39 import org.apache.http.ProtocolVersion;
40 import org.apache.http.annotation.Immutable;
41 import org.apache.http.util.Args;
42
43 /**
44 * ResponseContent is the most important interceptor for outgoing responses.
45 * It is responsible for delimiting content length by adding
46 * <code>Content-Length</code> or <code>Transfer-Content</code> headers based
47 * on the properties of the enclosed entity and the protocol version.
48 * This interceptor is required for correct functioning of server side protocol
49 * processors.
50 *
51 * @since 4.0
52 */
53 @Immutable
54 public class ResponseContent implements HttpResponseInterceptor {
55
56 private final boolean overwrite;
57
58 /**
59 * Default constructor. The <code>Content-Length</code> or <code>Transfer-Encoding</code>
60 * will cause the interceptor to throw {@link ProtocolException} if already present in the
61 * response message.
62 */
63 public ResponseContent() {
64 this(false);
65 }
66
67 /**
68 * Constructor that can be used to fine-tune behavior of this interceptor.
69 *
70 * @param overwrite If set to <code>true</code> the <code>Content-Length</code> and
71 * <code>Transfer-Encoding</code> headers will be created or updated if already present.
72 * If set to <code>false</code> the <code>Content-Length</code> and
73 * <code>Transfer-Encoding</code> headers will cause the interceptor to throw
74 * {@link ProtocolException} if already present in the response message.
75 *
76 * @since 4.2
77 */
78 public ResponseContent(final boolean overwrite) {
79 super();
80 this.overwrite = overwrite;
81 }
82
83 /**
84 * Processes the response (possibly updating or inserting) Content-Length and Transfer-Encoding headers.
85 * @param response The HttpResponse to modify.
86 * @param context Unused.
87 * @throws ProtocolException If either the Content-Length or Transfer-Encoding headers are found.
88 * @throws IllegalArgumentException If the response is null.
89 */
90 public void process(final HttpResponse response, final HttpContext context)
91 throws HttpException, IOException {
92 Args.notNull(response, "HTTP response");
93 if (this.overwrite) {
94 response.removeHeaders(HTTP.TRANSFER_ENCODING);
95 response.removeHeaders(HTTP.CONTENT_LEN);
96 } else {
97 if (response.containsHeader(HTTP.TRANSFER_ENCODING)) {
98 throw new ProtocolException("Transfer-encoding header already present");
99 }
100 if (response.containsHeader(HTTP.CONTENT_LEN)) {
101 throw new ProtocolException("Content-Length header already present");
102 }
103 }
104 final ProtocolVersion ver = response.getStatusLine().getProtocolVersion();
105 final HttpEntity entity = response.getEntity();
106 if (entity != null) {
107 final long len = entity.getContentLength();
108 if (entity.isChunked() && !ver.lessEquals(HttpVersion.HTTP_1_0)) {
109 response.addHeader(HTTP.TRANSFER_ENCODING, HTTP.CHUNK_CODING);
110 } else if (len >= 0) {
111 response.addHeader(HTTP.CONTENT_LEN, Long.toString(entity.getContentLength()));
112 }
113 // Specify a content type if known
114 if (entity.getContentType() != null && !response.containsHeader(
115 HTTP.CONTENT_TYPE )) {
116 response.addHeader(entity.getContentType());
117 }
118 // Specify a content encoding if known
119 if (entity.getContentEncoding() != null && !response.containsHeader(
120 HTTP.CONTENT_ENCODING)) {
121 response.addHeader(entity.getContentEncoding());
122 }
123 } else {
124 final int status = response.getStatusLine().getStatusCode();
125 if (status != HttpStatus.SC_NO_CONTENT
126 && status != HttpStatus.SC_NOT_MODIFIED
127 && status != HttpStatus.SC_RESET_CONTENT) {
128 response.addHeader(HTTP.CONTENT_LEN, "0");
129 }
130 }
131 }
132
133 }