Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/net/httpserver/Headers.java
38922 views
/*1* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.net.httpserver;2627import java.util.*;2829/**30* HTTP request and response headers are represented by this class which implements31* the interface {@link java.util.Map}<32* {@link java.lang.String},{@link java.util.List}<{@link java.lang.String}>>.33* The keys are case-insensitive Strings representing the header names and34* the value associated with each key is a {@link List}<{@link String}> with one35* element for each occurrence of the header name in the request or response.36* <p>37* For example, if a response header instance contains one key "HeaderName" with two values "value1 and value2"38* then this object is output as two header lines:39* <blockquote><pre>40* HeaderName: value141* HeaderName: value242* </blockquote></pre>43* <p>44* All the normal {@link java.util.Map} methods are provided, but the following45* additional convenience methods are most likely to be used:46* <ul>47* <li>{@link #getFirst(String)} returns a single valued header or the first value of48* a multi-valued header.</li>49* <li>{@link #add(String,String)} adds the given header value to the list for the given key</li>50* <li>{@link #set(String,String)} sets the given header field to the single value given51* overwriting any existing values in the value list.52* </ul><p>53* All methods in this class accept <code>null</code> values for keys and values. However, null54* keys will never will be present in HTTP request headers, and will not be output/sent in response headers.55* Null values can be represented as either a null entry for the key (i.e. the list is null) or56* where the key has a list, but one (or more) of the list's values is null. Null values are output57* as a header line containing the key but no associated value.58* @since 1.659*/60@jdk.Exported61public class Headers implements Map<String,List<String>> {6263HashMap<String,List<String>> map;6465public Headers () {map = new HashMap<String,List<String>>(32);}6667/* Normalize the key by converting to following form.68* First char upper case, rest lower case.69* key is presumed to be ASCII70*/71private String normalize (String key) {72if (key == null) {73return null;74}75int len = key.length();76if (len == 0) {77return key;78}79char[] b = key.toCharArray();80if (b[0] >= 'a' && b[0] <= 'z') {81b[0] = (char)(b[0] - ('a' - 'A'));82} else if (b[0] == '\r' || b[0] == '\n')83throw new IllegalArgumentException("illegal character in key");8485for (int i=1; i<len; i++) {86if (b[i] >= 'A' && b[i] <= 'Z') {87b[i] = (char) (b[i] + ('a' - 'A'));88} else if (b[i] == '\r' || b[i] == '\n')89throw new IllegalArgumentException("illegal character in key");90}91return new String(b);92}9394public int size() {return map.size();}9596public boolean isEmpty() {return map.isEmpty();}9798public boolean containsKey(Object key) {99if (key == null) {100return false;101}102if (!(key instanceof String)) {103return false;104}105return map.containsKey (normalize((String)key));106}107108public boolean containsValue(Object value) {109return map.containsValue(value);110}111112public List<String> get(Object key) {113return map.get(normalize((String)key));114}115116/**117* returns the first value from the List of String values118* for the given key (if at least one exists).119* @param key the key to search for120* @return the first string value associated with the key121*/122public String getFirst (String key) {123List<String> l = map.get(normalize(key));124if (l == null) {125return null;126}127return l.get(0);128}129130public List<String> put(String key, List<String> value) {131for (String v : value)132checkValue(v);133return map.put (normalize(key), value);134}135136/**137* adds the given value to the list of headers138* for the given key. If the mapping does not139* already exist, then it is created140* @param key the header name141* @param value the header value to add to the header142*/143public void add (String key, String value) {144checkValue(value);145String k = normalize(key);146List<String> l = map.get(k);147if (l == null) {148l = new LinkedList<String>();149map.put(k,l);150}151l.add (value);152}153154private static void checkValue(String value) {155int len = value.length();156for (int i=0; i<len; i++) {157char c = value.charAt(i);158if (c == '\r') {159// is allowed if it is followed by \n and a whitespace char160if (i >= len - 2) {161throw new IllegalArgumentException("Illegal CR found in header");162}163char c1 = value.charAt(i+1);164char c2 = value.charAt(i+2);165if (c1 != '\n') {166throw new IllegalArgumentException("Illegal char found after CR in header");167}168if (c2 != ' ' && c2 != '\t') {169throw new IllegalArgumentException("No whitespace found after CRLF in header");170}171i+=2;172} else if (c == '\n') {173throw new IllegalArgumentException("Illegal LF found in header");174}175}176}177178/**179* sets the given value as the sole header value180* for the given key. If the mapping does not181* already exist, then it is created182* @param key the header name183* @param value the header value to set.184*/185public void set (String key, String value) {186LinkedList<String> l = new LinkedList<String>();187l.add (value);188put (key, l);189}190191192public List<String> remove(Object key) {193return map.remove(normalize((String)key));194}195196public void putAll(Map<? extends String,? extends List<String>> t) {197map.putAll (t);198}199200public void clear() {map.clear();}201202public Set<String> keySet() {return map.keySet();}203204public Collection<List<String>> values() {return map.values();}205206public Set<Map.Entry<String, List<String>>> entrySet() {207return map.entrySet();208}209210public boolean equals(Object o) {return map.equals(o);}211212public int hashCode() {return map.hashCode();}213}214215216