1 /* 2 * Copyright 2014 The Netty Project 3 * 4 * The Netty Project licenses this file to you under the Apache License, version 2.0 (the 5 * "License"); you may not use this file except in compliance with the License. You may obtain a 6 * copy of the License at: 7 * 8 * https://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software distributed under the License 11 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 12 * or implied. See the License for the specific language governing permissions and limitations under 13 * the License. 14 */ 15 16 package io.netty.handler.codec.http2; 17 18 import io.netty.handler.codec.Headers; 19 import io.netty.util.AsciiString; 20 import io.netty.util.internal.UnstableApi; 21 22 import java.util.Iterator; 23 import java.util.Map.Entry; 24 25 /** 26 * A collection of headers sent or received via HTTP/2. 27 */ 28 @UnstableApi 29 public interface Http2Headers extends Headers<CharSequence, CharSequence, Http2Headers> { 30 31 /** 32 * HTTP/2 pseudo-headers names. 33 */ 34 enum PseudoHeaderName { 35 /** 36 * {@code :method}. 37 */ 38 METHOD(":method", true), 39 40 /** 41 * {@code :scheme}. 42 */ 43 SCHEME(":scheme", true), 44 45 /** 46 * {@code :authority}. 47 */ 48 AUTHORITY(":authority", true), 49 50 /** 51 * {@code :path}. 52 */ 53 PATH(":path", true), 54 55 /** 56 * {@code :status}. 57 */ 58 STATUS(":status", false), 59 60 /** 61 * {@code :protocol}, as defined in <a href="https://datatracker.ietf.org/doc/rfc8441/">RFC 8441, 62 * Bootstrapping WebSockets with HTTP/2</a>. 63 */ 64 PROTOCOL(":protocol", true); 65 66 private static final char PSEUDO_HEADER_PREFIX = ':'; 67 private static final byte PSEUDO_HEADER_PREFIX_BYTE = (byte) PSEUDO_HEADER_PREFIX; 68 69 private final AsciiString value; 70 private final boolean requestOnly; 71 private static final CharSequenceMap<PseudoHeaderName> PSEUDO_HEADERS = new CharSequenceMap<PseudoHeaderName>(); 72 73 static { 74 for (PseudoHeaderName pseudoHeader : values()) { 75 PSEUDO_HEADERS.add(pseudoHeader.value(), pseudoHeader); 76 } 77 } 78 79 PseudoHeaderName(String value, boolean requestOnly) { 80 this.value = AsciiString.cached(value); 81 this.requestOnly = requestOnly; 82 } 83 84 public AsciiString value() { 85 // Return a slice so that the buffer gets its own reader index. 86 return value; 87 } 88 89 /** 90 * Indicates whether the specified header follows the pseudo-header format (begins with ':' character) 91 * 92 * @return {@code true} if the header follow the pseudo-header format 93 */ 94 public static boolean hasPseudoHeaderFormat(CharSequence headerName) { 95 if (headerName instanceof AsciiString) { 96 final AsciiString asciiHeaderName = (AsciiString) headerName; 97 return asciiHeaderName.length() > 0 && asciiHeaderName.byteAt(0) == PSEUDO_HEADER_PREFIX_BYTE; 98 } else { 99 return headerName.length() > 0 && headerName.charAt(0) == PSEUDO_HEADER_PREFIX; 100 } 101 } 102 103 /** 104 * Indicates whether the given header name is a valid HTTP/2 pseudo header. 105 */ 106 public static boolean isPseudoHeader(CharSequence header) { 107 return PSEUDO_HEADERS.contains(header); 108 } 109 110 /** 111 * Returns the {@link PseudoHeaderName} corresponding to the specified header name. 112 * 113 * @return corresponding {@link PseudoHeaderName} if any, {@code null} otherwise. 114 */ 115 public static PseudoHeaderName getPseudoHeader(CharSequence header) { 116 return PSEUDO_HEADERS.get(header); 117 } 118 119 /** 120 * Indicates whether the pseudo-header is to be used in a request context. 121 * 122 * @return {@code true} if the pseudo-header is to be used in a request context 123 */ 124 public boolean isRequestOnly() { 125 return requestOnly; 126 } 127 } 128 129 /** 130 * Returns an iterator over all HTTP/2 headers. The iteration order is as follows: 131 * 1. All pseudo headers (order not specified). 132 * 2. All non-pseudo headers (in insertion order). 133 */ 134 @Override 135 Iterator<Entry<CharSequence, CharSequence>> iterator(); 136 137 /** 138 * Equivalent to {@link #getAll(Object)} but no intermediate list is generated. 139 * @param name the name of the header to retrieve 140 * @return an {@link Iterator} of header values corresponding to {@code name}. 141 */ 142 Iterator<CharSequence> valueIterator(CharSequence name); 143 144 /** 145 * Sets the {@link PseudoHeaderName#METHOD} header 146 */ 147 Http2Headers method(CharSequence value); 148 149 /** 150 * Sets the {@link PseudoHeaderName#SCHEME} header 151 */ 152 Http2Headers scheme(CharSequence value); 153 154 /** 155 * Sets the {@link PseudoHeaderName#AUTHORITY} header 156 */ 157 Http2Headers authority(CharSequence value); 158 159 /** 160 * Sets the {@link PseudoHeaderName#PATH} header 161 */ 162 Http2Headers path(CharSequence value); 163 164 /** 165 * Sets the {@link PseudoHeaderName#STATUS} header 166 */ 167 Http2Headers status(CharSequence value); 168 169 /** 170 * Gets the {@link PseudoHeaderName#METHOD} header or {@code null} if there is no such header 171 */ 172 CharSequence method(); 173 174 /** 175 * Gets the {@link PseudoHeaderName#SCHEME} header or {@code null} if there is no such header 176 */ 177 CharSequence scheme(); 178 179 /** 180 * Gets the {@link PseudoHeaderName#AUTHORITY} header or {@code null} if there is no such header 181 */ 182 CharSequence authority(); 183 184 /** 185 * Gets the {@link PseudoHeaderName#PATH} header or {@code null} if there is no such header 186 */ 187 CharSequence path(); 188 189 /** 190 * Gets the {@link PseudoHeaderName#STATUS} header or {@code null} if there is no such header 191 */ 192 CharSequence status(); 193 194 /** 195 * Returns {@code true} if a header with the {@code name} and {@code value} exists, {@code false} otherwise. 196 * <p> 197 * If {@code caseInsensitive} is {@code true} then a case insensitive compare is done on the value. 198 * 199 * @param name the name of the header to find 200 * @param value the value of the header to find 201 * @param caseInsensitive {@code true} then a case insensitive compare is run to compare values. 202 * otherwise a case sensitive compare is run to compare values. 203 */ 204 boolean contains(CharSequence name, CharSequence value, boolean caseInsensitive); 205 }