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.ErrorCode;
24  import org.eclipse.jetty.http2.Flags;
25  import org.eclipse.jetty.http2.frames.PingFrame;
26  
27  public class PingBodyParser extends BodyParser
28  {
29      private State state = State.PREPARE;
30      private int cursor;
31      private byte[] payload;
32  
33      public PingBodyParser(HeaderParser headerParser, Parser.Listener listener)
34      {
35          super(headerParser, listener);
36      }
37  
38      private void reset()
39      {
40          state = State.PREPARE;
41          cursor = 0;
42          payload = null;
43      }
44  
45      @Override
46      public boolean parse(ByteBuffer buffer)
47      {
48          while (buffer.hasRemaining())
49          {
50              switch (state)
51              {
52                  case PREPARE:
53                  {
54                      // SPEC: wrong streamId is treated as connection error.
55                      if (getStreamId() != 0)
56                          return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_ping_frame");
57                      // SPEC: wrong body length is treated as connection error.
58                      if (getBodyLength() != 8)
59                          return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_ping_frame");
60                      state = State.PAYLOAD;
61                      break;
62                  }
63                  case PAYLOAD:
64                  {
65                      payload = new byte[8];
66                      if (buffer.remaining() >= 8)
67                      {
68                          buffer.get(payload);
69                          return onPing(payload);
70                      }
71                      else
72                      {
73                          state = State.PAYLOAD_BYTES;
74                          cursor = 8;
75                      }
76                      break;
77                  }
78                  case PAYLOAD_BYTES:
79                  {
80                      payload[8 - cursor] = buffer.get();
81                      --cursor;
82                      if (cursor == 0)
83                          return onPing(payload);
84                      break;
85                  }
86                  default:
87                  {
88                      throw new IllegalStateException();
89                  }
90              }
91          }
92          return false;
93      }
94  
95      private boolean onPing(byte[] payload)
96      {
97          PingFrame frame = new PingFrame(payload, hasFlag(Flags.ACK));
98          reset();
99          notifyPing(frame);
100         return true;
101     }
102 
103     private enum State
104     {
105         PREPARE, PAYLOAD, PAYLOAD_BYTES
106     }
107 }