/* * 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.wicket.request; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import org.apache.wicket.util.lang.Args; import org.apache.wicket.util.time.Time; /** * A multivalue map of headers names and header values suitable for processing http request and * response headers. * * @author Peter Ertl * * @since 1.5 */ public class HttpHeaderCollection { private final Map<HeaderKey, List<Object>> headers; /** returned in case no header values were found */ private static final String[] NO_VALUES = new String[0]; /** * Constructor. */ public HttpHeaderCollection() { headers = new HashMap<>(); } /** * internally add new object to header values * * @param name * header name * @param object * header value (can be a string or a {@link Time} object */ private void internalAdd(String name, Object object) { final HeaderKey key = new HeaderKey(name); List<Object> values = headers.get(key); if (values == null) { values = new ArrayList<>(); headers.put(key, values); } values.add(object); } /** * set header value (and remove previous values) * * @param name * header name * @param value * header value */ public void setHeader(String name, String value) { // remove previous values removeHeader(name); // add new values addHeader(name, value); } /** * add header value * * @param name * header name * @param value * header value */ public void addHeader(String name, String value) { // be lenient and strip leading / trailing blanks value = Args.notNull(value, "value").trim(); internalAdd(name, value); } /** * add date header value * * @param name * header name * @param time * timestamp */ public void addDateHeader(String name, Time time) { internalAdd(name, time); } /** * add date header value * * @param name * header name * @param time * timestamp */ public void setDateHeader(String name, Time time) { // remove previous values removeHeader(name); // add time object to values addDateHeader(name, time); } /** * remove header values for header name * * @param name * header name */ public void removeHeader(String name) { final HeaderKey key = new HeaderKey(name); final Iterator<Map.Entry<HeaderKey, List<Object>>> it = headers.entrySet().iterator(); while (it.hasNext()) { final Map.Entry<HeaderKey, List<Object>> header = it.next(); if (header.getKey().equals(key)) { it.remove(); } } } private String valueToString(Object value) { if (value instanceof Time) { return ((Time)value).toRfc1123TimestampString(); } else { return value.toString(); } } /** * check if header is defined * * @param name * header name * @return <code>true</code> if header has one or more values */ public boolean containsHeader(String name) { final HeaderKey searchKey = new HeaderKey(name); // get the header value (case might differ) for (HeaderKey key : headers.keySet()) { if (key.equals(searchKey)) { return true; } } return false; } /** * returns names of headers * * @return set of header names */ public Set<String> getHeaderNames() { if (headers.isEmpty()) { return Collections.emptySet(); } final Set<String> names = new HashSet<>(headers.size()); for (HeaderKey key : headers.keySet()) { names.add(key.getName()); } return names; } /** * get header values (dates will be converted into strings) * * @param name * header name * * @return array of header values or empty array if not found */ public String[] getHeaderValues(String name) { final List<Object> objects = headers.get(new HeaderKey(name)); if (objects == null) { return NO_VALUES; } final String[] values = new String[objects.size()]; for (int i = 0; i < values.length; i++) { values[i] = valueToString(objects.get(i)); } return values; } /** * Gets the header identified with the name as a String. * @param name * @return {@code null} when the header was not found */ public String getHeader(String name) { final List<Object> objects = headers.get(new HeaderKey(name)); if (objects == null || objects.isEmpty()) { return null; } return valueToString(objects.get(0)); } /** * Gets the header identified with the name as a Time * @param name * @return {@code null} when the header was not found */ public Time getDateHeader(String name) { final List<Object> objects = headers.get(new HeaderKey(name)); if (objects.isEmpty()) { return null; } Object object = objects.get(0); if ((object instanceof Time) == false) { throw new IllegalStateException("header value is not of type date"); } return (Time)object; } /** * Check if collection is empty * * @return <code>true</code> if collection is empty, <code>false</code> otherwise */ public boolean isEmpty() { return headers.isEmpty(); } /** * get number of headers * * @return count */ public int getCount() { return headers.size(); } /** * clear all headers */ public void clear() { headers.clear(); } /** * key for header collection */ private static class HeaderKey { private final String key; private final String name; private HeaderKey(String name) { this.name = Args.notEmpty(name, "name").trim(); key = this.name.toLowerCase(Locale.US); } public String getName() { return name; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof HeaderKey)) return false; HeaderKey that = (HeaderKey)o; if (!key.equals(that.key)) return false; return true; } @Override public int hashCode() { return key.hashCode(); } } }