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