View Javadoc
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 }