View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.http2.parser;
20  
21  import java.nio.ByteBuffer;
22  
23  import org.eclipse.jetty.http2.frames.Frame;
24  
25  /**
26   * <p>The parser for the frame header of HTTP/2 frames.</p>
27   *
28   * @see Parser
29   */
30  public class HeaderParser
31  {
32      private State state = State.LENGTH;
33      private int cursor;
34  
35      private int length;
36      private int type;
37      private int flags;
38      private int streamId;
39  
40      protected void reset()
41      {
42          state = State.LENGTH;
43          cursor = 0;
44  
45          length = 0;
46          type = 0;
47          flags = 0;
48          streamId = 0;
49      }
50  
51      /**
52       * <p>Parses the header bytes in the given {@code buffer}; only the header
53       * bytes are consumed, therefore when this method returns, the buffer may
54       * contain unconsumed bytes.</p>
55       *
56       * @param buffer the buffer to parse
57       * @return true if the whole header bytes were parsed, false if not enough
58       * header bytes were present in the buffer
59       */
60      public boolean parse(ByteBuffer buffer)
61      {
62          while (buffer.hasRemaining())
63          {
64              switch (state)
65              {
66                  case LENGTH:
67                  {
68                      int octet = buffer.get() & 0xFF;
69                      length = (length << 8) + octet;
70                      if (++cursor == 3)
71                      {
72                          length &= Frame.MAX_MAX_LENGTH;
73                          state = State.TYPE;
74                      }
75                      break;
76                  }
77                  case TYPE:
78                  {
79                      type = buffer.get() & 0xFF;
80                      state = State.FLAGS;
81                      break;
82                  }
83                  case FLAGS:
84                  {
85                      flags = buffer.get() & 0xFF;
86                      state = State.STREAM_ID;
87                      break;
88                  }
89                  case STREAM_ID:
90                  {
91                      if (buffer.remaining() >= 4)
92                      {
93                          streamId = buffer.getInt();
94                          // Most significant bit MUST be ignored as per specification.
95                          streamId &= 0x7F_FF_FF_FF;
96                          return true;
97                      }
98                      else
99                      {
100                         state = State.STREAM_ID_BYTES;
101                         cursor = 4;
102                     }
103                     break;
104                 }
105                 case STREAM_ID_BYTES:
106                 {
107                     int currByte = buffer.get() & 0xFF;
108                     --cursor;
109                     streamId += currByte << (8 * cursor);
110                     if (cursor == 0)
111                     {
112                         // Most significant bit MUST be ignored as per specification.
113                         streamId &= 0x7F_FF_FF_FF;
114                         return true;
115                     }
116                     break;
117                 }
118                 default:
119                 {
120                     throw new IllegalStateException();
121                 }
122             }
123         }
124         return false;
125     }
126 
127     public int getLength()
128     {
129         return length;
130     }
131 
132     public int getFrameType()
133     {
134         return type;
135     }
136 
137     public boolean hasFlag(int bit)
138     {
139         return (flags & bit) == bit;
140     }
141 
142     public int getStreamId()
143     {
144         return streamId;
145     }
146 
147     private enum State
148     {
149         LENGTH, TYPE, FLAGS, STREAM_ID, STREAM_ID_BYTES
150     }
151 }