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.util.internal.UnstableApi;
18
19 /**
20 * Provides utility methods for accessing specific flags as defined by the HTTP/2 spec.
21 */
22 @UnstableApi
23 public final class Http2Flags {
24 public static final short END_STREAM = 0x1;
25 public static final short END_HEADERS = 0x4;
26 public static final short ACK = 0x1;
27 public static final short PADDED = 0x8;
28 public static final short PRIORITY = 0x20;
29
30 private short value;
31
32 public Http2Flags() {
33 }
34
35 public Http2Flags(short value) {
36 this.value = value;
37 }
38
39 /**
40 * Gets the underlying flags value.
41 */
42 public short value() {
43 return value;
44 }
45
46 /**
47 * Determines whether the {@link #END_STREAM} flag is set. Only applies to DATA and HEADERS
48 * frames.
49 */
50 public boolean endOfStream() {
51 return isFlagSet(END_STREAM);
52 }
53
54 /**
55 * Determines whether the {@link #END_HEADERS} flag is set. Only applies for HEADERS,
56 * PUSH_PROMISE, and CONTINUATION frames.
57 */
58 public boolean endOfHeaders() {
59 return isFlagSet(END_HEADERS);
60 }
61
62 /**
63 * Determines whether the flag is set indicating the presence of the exclusive, stream
64 * dependency, and weight fields in a HEADERS frame.
65 */
66 public boolean priorityPresent() {
67 return isFlagSet(PRIORITY);
68 }
69
70 /**
71 * Determines whether the flag is set indicating that this frame is an ACK. Only applies for
72 * SETTINGS and PING frames.
73 */
74 public boolean ack() {
75 return isFlagSet(ACK);
76 }
77
78 /**
79 * For frames that include padding, indicates if the {@link #PADDED} field is present. Only
80 * applies to DATA, HEADERS, PUSH_PROMISE and CONTINUATION frames.
81 */
82 public boolean paddingPresent() {
83 return isFlagSet(PADDED);
84 }
85
86 /**
87 * Gets the number of bytes expected for the priority fields of the payload. This is determined
88 * by the {@link #priorityPresent()} flag.
89 */
90 public int getNumPriorityBytes() {
91 return priorityPresent() ? 5 : 0;
92 }
93
94 /**
95 * Gets the length in bytes of the padding presence field expected in the payload. This is
96 * determined by the {@link #paddingPresent()} flag.
97 */
98 public int getPaddingPresenceFieldLength() {
99 return paddingPresent() ? 1 : 0;
100 }
101
102 /**
103 * Sets the {@link #END_STREAM} flag.
104 */
105 public Http2Flags endOfStream(boolean endOfStream) {
106 return setFlag(endOfStream, END_STREAM);
107 }
108
109 /**
110 * Sets the {@link #END_HEADERS} flag.
111 */
112 public Http2Flags endOfHeaders(boolean endOfHeaders) {
113 return setFlag(endOfHeaders, END_HEADERS);
114 }
115
116 /**
117 * Sets the {@link #PRIORITY} flag.
118 */
119 public Http2Flags priorityPresent(boolean priorityPresent) {
120 return setFlag(priorityPresent, PRIORITY);
121 }
122
123 /**
124 * Sets the {@link #PADDED} flag.
125 */
126 public Http2Flags paddingPresent(boolean paddingPresent) {
127 return setFlag(paddingPresent, PADDED);
128 }
129
130 /**
131 * Sets the {@link #ACK} flag.
132 */
133 public Http2Flags ack(boolean ack) {
134 return setFlag(ack, ACK);
135 }
136
137 /**
138 * Generic method to set any flag.
139 * @param on if the flag should be enabled or disabled.
140 * @param mask the mask that identifies the bit for the flag.
141 * @return this instance.
142 */
143 public Http2Flags setFlag(boolean on, short mask) {
144 if (on) {
145 value |= mask;
146 } else {
147 value &= ~mask;
148 }
149 return this;
150 }
151
152 /**
153 * Indicates whether or not a particular flag is set.
154 * @param mask the mask identifying the bit for the particular flag being tested
155 * @return {@code true} if the flag is set
156 */
157 public boolean isFlagSet(short mask) {
158 return (value & mask) != 0;
159 }
160
161 @Override
162 public int hashCode() {
163 final int prime = 31;
164 int result = 1;
165 result = prime * result + value;
166 return result;
167 }
168
169 @Override
170 public boolean equals(Object obj) {
171 if (this == obj) {
172 return true;
173 }
174 if (obj == null) {
175 return false;
176 }
177 if (getClass() != obj.getClass()) {
178 return false;
179 }
180
181 return value == ((Http2Flags) obj).value;
182 }
183
184 @Override
185 public String toString() {
186 StringBuilder builder = new StringBuilder();
187 builder.append("value = ").append(value).append(" (");
188 if (ack()) {
189 builder.append("ACK,");
190 }
191 if (endOfHeaders()) {
192 builder.append("END_OF_HEADERS,");
193 }
194 if (endOfStream()) {
195 builder.append("END_OF_STREAM,");
196 }
197 if (priorityPresent()) {
198 builder.append("PRIORITY_PRESENT,");
199 }
200 if (paddingPresent()) {
201 builder.append("PADDING_PRESENT,");
202 }
203 builder.append(')');
204 return builder.toString();
205 }
206 }