
org.apache.cxf.transport.http.Headers Maven / Gradle / Ivy
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cxf.transport.http;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.common.util.PropertyUtils;
import org.apache.cxf.helpers.CastUtils;
import org.apache.cxf.helpers.HttpHeaderHelper;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageUtils;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.apache.cxf.transports.http.configuration.HTTPServerPolicy;
import org.apache.cxf.version.Version;
public class Headers {
/**
* This constant is the Message(Map) key for the HttpURLConnection that
* is used to get the response.
*/
public static final String KEY_HTTP_CONNECTION = "http.connection";
/**
* Each header value is added as a separate HTTP header, example, given A header with 'a' and 'b'
* values, two A headers will be added as opposed to a single A header with the "a,b" value.
*/
public static final String ADD_HEADERS_PROPERTY = "org.apache.cxf.http.add-headers";
public static final String PROTOCOL_HEADERS_CONTENT_TYPE = Message.CONTENT_TYPE.toLowerCase();
public static final String HTTP_HEADERS_SETCOOKIE = "Set-Cookie";
public static final String HTTP_HEADERS_LINK = "Link";
public static final String EMPTY_REQUEST_PROPERTY = "org.apache.cxf.empty.request";
private static final String SET_EMPTY_REQUEST_CT_PROPERTY = "set.content.type.for.empty.request";
private static final TimeZone TIME_ZONE_GMT = TimeZone.getTimeZone("GMT");
private static final Logger LOG = LogUtils.getL7dLogger(Headers.class);
private static final List SENSITIVE_HEADERS = Arrays.asList("Authorization", "Proxy-Authorization");
private static final List SENSITIVE_HEADER_MARKER = Arrays.asList("***");
private static final String ALLOW_LOGGING_SENSITIVE_HEADERS = "allow.logging.sensitive.headers";
/**
* Known HTTP headers whose values have to be represented as individual HTTP headers
*/
private static final Set HTTP_HEADERS_SINGLE_VALUE_ONLY;
private static final String USER_AGENT;
static {
HTTP_HEADERS_SINGLE_VALUE_ONLY = new HashSet();
HTTP_HEADERS_SINGLE_VALUE_ONLY.add(HTTP_HEADERS_SETCOOKIE);
HTTP_HEADERS_SINGLE_VALUE_ONLY.add(HTTP_HEADERS_LINK);
USER_AGENT = initUserAgent();
}
private final Message message;
private final Map> headers;
public Headers(Message message) {
this.message = message;
this.headers = getSetProtocolHeaders(message);
}
public Headers() {
this.headers = new TreeMap>(String.CASE_INSENSITIVE_ORDER);
this.message = null;
}
public static String getUserAgent() {
return USER_AGENT;
}
private static String initUserAgent() {
String name = Version.getName();
if ("Apache CXF".equals(name)) {
name = "Apache-CXF";
}
String version = Version.getCurrentVersion();
return name + "/" + version;
}
/**
* Returns a traceable string representation of the passed-in headers map.
* The value for any keys in the map that are in the SENSITIVE_HEADERS
* array will be filtered out of the returned string.
* Note that this method is expensive as it will copy the map (except for the
* filtered keys), so it should be used sparingly - i.e. only when debug is
* enabled.
*/
static String toString(Map> headers, boolean logSensitiveHeaders) {
Map> filteredHeaders = new TreeMap>(String.CASE_INSENSITIVE_ORDER);
filteredHeaders.putAll(headers);
if (!logSensitiveHeaders) {
for (String filteredKey : SENSITIVE_HEADERS) {
filteredHeaders.put(filteredKey, SENSITIVE_HEADER_MARKER);
}
}
return filteredHeaders.toString();
}
public Map> headerMap() {
return headers;
}
/**
* Write cookie header from given session cookies
*
* @param sessionCookies
*/
public void writeSessionCookies(Map sessionCookies) {
List cookies = null;
for (String s : headers.keySet()) {
if (HttpHeaderHelper.COOKIE.equalsIgnoreCase(s)) {
cookies = headers.remove(s);
break;
}
}
if (cookies == null) {
cookies = new ArrayList();
} else {
cookies = new ArrayList(cookies);
}
headers.put(HttpHeaderHelper.COOKIE, cookies);
for (Cookie c : sessionCookies.values()) {
cookies.add(c.requestCookieHeader());
}
}
/**
* This call places HTTP Header strings into the headers that are relevant
* to the ClientPolicy that is set on this conduit by configuration.
*
* REVISIT: A cookie is set statically from configuration?
*/
void setFromClientPolicy(HTTPClientPolicy policy) {
if (policy == null) {
return;
}
if (policy.isSetCacheControl()) {
headers.put("Cache-Control",
createMutableList(policy.getCacheControl()));
}
if (policy.isSetHost()) {
headers.put("Host",
createMutableList(policy.getHost()));
}
if (policy.isSetConnection()) {
headers.put("Connection",
createMutableList(policy.getConnection().value()));
}
if (policy.isSetAccept()) {
headers.put("Accept",
createMutableList(policy.getAccept()));
} else if (!headers.containsKey("Accept")) {
headers.put("Accept", createMutableList("*/*"));
}
if (policy.isSetAcceptEncoding()) {
headers.put("Accept-Encoding",
createMutableList(policy.getAcceptEncoding()));
}
if (policy.isSetAcceptLanguage()) {
headers.put("Accept-Language",
createMutableList(policy.getAcceptLanguage()));
}
if (policy.isSetContentType()) {
message.put(Message.CONTENT_TYPE, policy.getContentType());
}
if (policy.isSetCookie()) {
headers.put("Cookie",
createMutableList(policy.getCookie()));
}
if (policy.isSetBrowserType()) {
headers.put("User-Agent",
createMutableList(policy.getBrowserType()));
}
if (policy.isSetReferer()) {
headers.put("Referer",
createMutableList(policy.getReferer()));
}
}
void setFromServerPolicy(HTTPServerPolicy policy) {
if (policy.isSetCacheControl()) {
headers.put("Cache-Control",
createMutableList(policy.getCacheControl()));
}
if (policy.isSetContentLocation()) {
headers.put("Content-Location",
createMutableList(policy.getContentLocation()));
}
if (policy.isSetContentEncoding()) {
headers.put("Content-Encoding",
createMutableList(policy.getContentEncoding()));
}
if (policy.isSetContentType()) {
headers.put(HttpHeaderHelper.CONTENT_TYPE,
createMutableList(policy.getContentType()));
}
if (policy.isSetServerType()) {
headers.put("Server",
createMutableList(policy.getServerType()));
}
if (policy.isSetHonorKeepAlive() && !policy.isHonorKeepAlive()) {
headers.put("Connection",
createMutableList("close"));
} else if (policy.isSetKeepAliveParameters()) {
headers.put("Keep-Alive", createMutableList(policy.getKeepAliveParameters()));
}
/*
* TODO - hook up these policies
*/
}
public void removeAuthorizationHeaders() {
headers.remove("Authorization");
headers.remove("Proxy-Authorization");
}
public void setAuthorization(String authorization) {
headers.put("Authorization",
createMutableList(authorization));
}
public void setProxyAuthorization(String authorization) {
headers.put("Proxy-Authorization",
createMutableList(authorization));
}
/**
* While extracting the Message.PROTOCOL_HEADERS property from the Message,
* this call ensures that the Message.PROTOCOL_HEADERS property is
* set on the Message. If it is not set, an empty map is placed there, and
* then returned.
*
* @param message The outbound message
* @return The PROTOCOL_HEADERS map
*/
public static Map> getSetProtocolHeaders(final Message message) {
Map> headers =
CastUtils.cast((Map, ?>)message.get(Message.PROTOCOL_HEADERS));
if (null == headers) {
headers = new TreeMap>(String.CASE_INSENSITIVE_ORDER);
} else if (headers instanceof HashMap) {
Map> headers2
= new TreeMap>(String.CASE_INSENSITIVE_ORDER);
headers2.putAll(headers);
headers = headers2;
}
message.put(Message.PROTOCOL_HEADERS, headers);
return headers;
}
public void readFromConnection(HttpURLConnection connection) {
Map> origHeaders = connection.getHeaderFields();
headers.clear();
for (String key : connection.getHeaderFields().keySet()) {
if (key != null) {
headers.put(HttpHeaderHelper.getHeaderKey(key),
origHeaders.get(key));
}
}
}
private static List createMutableList(String val) {
return new ArrayList(Arrays.asList(new String[] {val}));
}
/**
* This procedure logs the PROTOCOL_HEADERS from the
* Message at the specified logging level.
*
* @param logger The Logger to log to.
* @param level The Logging Level.
* @param headers The Message protocol headers.
*/
static void logProtocolHeaders(Logger logger, Level level,
Map> headersMap,
boolean logSensitiveHeaders) {
if (logger.isLoggable(level)) {
for (Map.Entry> entry : headersMap.entrySet()) {
String key = entry.getKey();
boolean sensitive = !logSensitiveHeaders && SENSITIVE_HEADERS.contains(key);
List headerList = sensitive ? SENSITIVE_HEADER_MARKER : entry.getValue();
for (String value : headerList) {
logger.log(level, key + ": "
+ (value == null ? "" : value.toString()));
}
}
}
}
/**
* Set content type and protocol headers (Message.PROTOCOL_HEADERS) headers into the URL
* connection.
* Note, this does not mean they immediately get written to the output
* stream or the wire. They just just get set on the HTTP request.
*
* @param connection
* @throws IOException
*/
public void setProtocolHeadersInConnection(HttpURLConnection connection) throws IOException {
// If no Content-Type is set for empty requests then HttpUrlConnection:
// - sets a form Content-Type for empty POST
// - replaces custom Accept value with */* if HTTP proxy is used
boolean contentTypeSet = headers.containsKey(Message.CONTENT_TYPE);
if (!contentTypeSet) {
// if CT is not set then assume it has to be set by default
boolean dropContentType = false;
boolean getRequest = "GET".equals(message.get(Message.HTTP_REQUEST_METHOD));
boolean emptyRequest = getRequest || PropertyUtils.isTrue(message.get(EMPTY_REQUEST_PROPERTY));
// If it is an empty request (without a request body) then check further if CT still needs be set
if (emptyRequest) {
Object setCtForEmptyRequestProp = message.getContextualProperty(SET_EMPTY_REQUEST_CT_PROPERTY);
if (setCtForEmptyRequestProp != null) {
// If SET_EMPTY_REQUEST_CT_PROPERTY is set then do as a user prefers.
// CT will be dropped if setting CT for empty requests was explicitly disabled
dropContentType = PropertyUtils.isFalse(setCtForEmptyRequestProp);
} else if (getRequest) {
// otherwise if it is GET then just drop it
dropContentType = true;
}
}
if (!dropContentType) {
String ct = emptyRequest && !contentTypeSet ? "*/*" : determineContentType();
connection.setRequestProperty(HttpHeaderHelper.CONTENT_TYPE, ct);
}
} else {
connection.setRequestProperty(HttpHeaderHelper.CONTENT_TYPE, determineContentType());
}
transferProtocolHeadersToURLConnection(connection);
logProtocolHeaders(LOG, Level.FINE, headers, logSensitiveHeaders());
}
public String determineContentType() {
String ct = null;
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy