All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.gravitee.common.http.HttpHeaders Maven / Gradle / Ivy

There is a newer version: 4.6.0
Show newest version
/**
 * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
 *
 * Licensed 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 io.gravitee.common.http;

import io.gravitee.common.util.LinkedCaseInsensitiveMap;
import io.gravitee.common.util.MultiValueMap;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author David BRASSELY (brasseld at gmail.com)
 */
public class HttpHeaders implements MultiValueMap {

    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String ACCEPT = "Accept";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String ACCEPT_CHARSET = "Accept-Charset";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String ACCEPT_ENCODING = "Accept-Encoding";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String ACCEPT_LANGUAGE = "Accept-Language";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String ACCEPT_RANGES = "Accept-Ranges";
    /**
     * See {@link CORS documentation}.
     */
    public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
    /**
     * See {@link CORS documentation}.
     */
    public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
    /**
     * See {@link CORS documentation}.
     */
    public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
    /**
     * See {@link CORS documentation}.
     */
    public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
    /**
     * See {@link CORS documentation}.
     */
    public static final String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
    /**
     * See {@link CORS documentation}.
     */
    public static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age";
    /**
     * See {@link CORS documentation}.
     */
    public static final String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers";
    /**
     * See {@link CORS documentation}.
     */
    public static final String ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String AGE = "Age";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String ALLOW = "Allow";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String AUTHORIZATION = "Authorization";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String CACHE_CONTROL = "Cache-Control";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String CONNECTION = "Connection";
    /**
     * See {@link IETF RFC-2183}.
     */
    public static final String CONTENT_DISPOSITION = "Content-Disposition";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String CONTENT_ENCODING = "Content-Encoding";
    /**
     * See {@link IETF RFC-2392}.
     */
    public static final String CONTENT_ID = "Content-ID";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String CONTENT_LANGUAGE = "Content-Language";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String CONTENT_LENGTH = "Content-Length";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String CONTENT_LOCATION = "Content-Location";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String CONTENT_MD5 = "Content-MD5";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String CONTENT_RANGE = "Content-Range";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String CONTENT_TYPE = "Content-Type";
    /**
     * See {@link IETF RFC 2109}.
     */
    public static final String COOKIE = "Cookie";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String DATE = "Date";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String ETAG = "ETag";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String EXPIRES = "Expires";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String EXPECT = "Expect";
    /**
     * See {@link IETF RFC 7239}.
     */
    public static final String FORWARDED = "Forwarded";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String FROM = "From";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String HOST = "Host";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String IF_MATCH = "If-Match";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String IF_MODIFIED_SINCE = "If-Modified-Since";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String IF_NONE_MATCH = "If-None-Match";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String KEEP_ALIVE = "Keep-Alive";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String LAST_MODIFIED = "Last-Modified";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String LOCATION = "Location";
    /**
     * See {@link Web Linking (IETF RFC-5988) documentation}.
     */
    public static final String LINK = "Link";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String MAX_FORWARDS = "Max-Forwards";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String MIME_VERSION = "MIME-Version";
    /**
     * https://tools.ietf.org/id/draft-abarth-origin-03.html#rfc.section.2
     */
    public static final String ORIGIN = "Origin";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String PRAGMA = "Pragma";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String PROXY_AUTHENTICATE = "Proxy-Authenticate";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String PROXY_AUTHORIZATION = "Proxy-Authorization";
    public static final String PROXY_CONNECTION = "Proxy-Connection";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String RANGE = "Range";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String REFERER = "Referer";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String RETRY_AFTER = "Retry-After";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String SERVER = "Server";
    /**
     * See {@link IETF RFC 2109}.
     */
    public static final String SET_COOKIE = "Set-Cookie";
    /**
     * See {@link IETF RFC 2965}.
     */
    public static final String SET_COOKIE2 = "Set-Cookie2";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String TE = "TE";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String TRAILER = "Trailer";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String TRANSFER_ENCODING = "Transfer-Encoding";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String UPGRADE = "Upgrade";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String USER_AGENT = "User-Agent";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String VARY = "Vary";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String VIA = "Via";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String WARNING = "Warning";
    /**
     * See {@link HTTP/1.1 documentation}.
     */
    public static final String WWW_AUTHENTICATE = "WWW-Authenticate";

    public static final String X_FORWARDED_FOR = "X-Forwarded-For";
    public static final String X_FORWARDED_PROTO = "X-Forwarded-Proto";
    public static final String X_FORWARDED_SERVER = "X-Forwarded-Server";
    public static final String X_FORWARDED_HOST = "X-Forwarded-Host";
    public static final String X_FORWARDED_PORT = "X-Forwarded-Port";
    public static final String X_FORWARDED_PREFIX = "X-Forwarded-Prefix";

    private final Map> headers;

    /**
     * Constructs a new, empty instance of the {@code HttpHeaders} object.
     */
    public HttpHeaders() {
        this.headers = new LinkedCaseInsensitiveMap<>(8);
    }

    public HttpHeaders(int initialCapacity) {
        this.headers = new LinkedCaseInsensitiveMap<>(initialCapacity);
    }

    public HttpHeaders(HttpHeaders httpHeaders) {
        this(httpHeaders.size());
        httpHeaders.forEach((headerName, headerValues) -> put(headerName, new LinkedList(headerValues)));
    }

    @Override
    public int size() {
        return headers.size();
    }

    @Override
    public boolean isEmpty() {
        return headers.isEmpty();
    }

    @Override
    public boolean containsKey(Object key) {
        return headers.containsKey(key);
    }

    @Override
    public boolean containsValue(Object value) {
        return headers.containsValue(value);
    }

    @Override
    public List get(Object key) {
        return headers.get(key);
    }

    @Override
    public List put(String key, List value) {
        return headers.put(key, value);
    }

    @Override
    public List remove(Object key) {
        return headers.remove(key);
    }

    @Override
    public void putAll(Map> m) {
        headers.putAll(m);
    }

    @Override
    public void clear() {
        headers.clear();
    }

    @Override
    public Set keySet() {
        return headers.keySet();
    }

    @Override
    public Collection> values() {
        return headers.values();
    }

    @Override
    public Set>> entrySet() {
        return headers.entrySet();
    }

    @Override
    public boolean equals(Object o) {
        return headers.equals(o);
    }

    @Override
    public int hashCode() {
        return headers.hashCode();
    }

    @Override
    public List getOrDefault(Object key, List defaultValue) {
        return headers.getOrDefault(key, defaultValue);
    }

    @Override
    public void forEach(BiConsumer> action) {
        headers.forEach(action);
    }

    @Override
    public void replaceAll(BiFunction, ? extends List> function) {
        headers.replaceAll(function);
    }

    @Override
    public List putIfAbsent(String key, List value) {
        return headers.putIfAbsent(key, value);
    }

    @Override
    public boolean remove(Object key, Object value) {
        return headers.remove(key, value);
    }

    @Override
    public boolean replace(String key, List oldValue, List newValue) {
        return headers.replace(key, oldValue, newValue);
    }

    @Override
    public List replace(String key, List value) {
        return headers.replace(key, value);
    }

    @Override
    public List computeIfAbsent(String key, Function> mappingFunction) {
        return headers.computeIfAbsent(key, mappingFunction);
    }

    @Override
    public List computeIfPresent(
        String key,
        BiFunction, ? extends List> remappingFunction
    ) {
        return headers.computeIfPresent(key, remappingFunction);
    }

    @Override
    public List compute(String key, BiFunction, ? extends List> remappingFunction) {
        return headers.compute(key, remappingFunction);
    }

    @Override
    public List merge(
        String key,
        List value,
        BiFunction, ? super List, ? extends List> remappingFunction
    ) {
        return headers.merge(key, value, remappingFunction);
    }

    @Override
    public String getFirst(String headerName) {
        List headerValues = this.headers.get(headerName);
        return (headerValues != null ? headerValues.get(0) : null);
    }

    @Override
    public void add(String headerName, String headerValue) {
        List headerValues = this.headers.get(headerName);
        if (headerValues == null) {
            headerValues = new LinkedList<>();
            this.headers.put(headerName, headerValues);
        }
        headerValues.add(headerValue);
    }

    @Override
    public void set(String headerName, String headerValue) {
        List headerValues = new LinkedList();
        headerValues.add(headerValue);
        this.headers.put(headerName, headerValues);
    }

    @Override
    public void setAll(Map values) {
        for (Entry entry : values.entrySet()) {
            set(entry.getKey(), entry.getValue());
        }
    }

    @Override
    public Map toSingleValueMap() {
        LinkedHashMap singleValueMap = new LinkedHashMap(this.headers.size());
        for (Entry> entry : this.headers.entrySet()) {
            singleValueMap.put(entry.getKey(), entry.getValue().get(0));
        }
        return singleValueMap;
    }

    @Override
    public boolean containsAllKeys(Collection keys) {
        final LinkedCaseInsensitiveMap headers = (LinkedCaseInsensitiveMap) this.headers;
        final List lowercaseKeys = keys.stream().map(s -> s.toLowerCase(headers.getLocale())).collect(Collectors.toList());
        return headers.insensitiveKeySet().containsAll(lowercaseKeys);
    }

    /**
     * Return the length of the body in bytes, as specified by the
     * {@code Content-Length} header.
     * 

Returns -1 when the content-length is unknown. */ public long contentLength() { String value = getFirst(CONTENT_LENGTH); return (value != null ? Long.parseLong(value) : -1); } /** * Set the length of the body in bytes, as specified by the * {@code Content-Length} header. */ public void contentLength(long contentLength) { set(CONTENT_LENGTH, Long.toString(contentLength)); } /** * Return the type of the body, as specified * by the {@code Content-Type} header. *

Returns {@code null} when the content-type is unknown. */ public String contentType() { return getFirst(CONTENT_TYPE); } /** * Set the length of the body in bytes, as specified by the * {@code Content-Length} header. */ public void contentType(String contentType) { set(CONTENT_TYPE, contentType); } public List getAccept() { return MediaType.parseMediaTypes(this.get("Accept")); } }