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.http.MetaData;
24  import org.eclipse.jetty.http2.ErrorCode;
25  import org.eclipse.jetty.http2.Flags;
26  import org.eclipse.jetty.http2.frames.HeadersFrame;
27  
28  public class ContinuationBodyParser extends BodyParser
29  {
30      private final HeaderBlockParser headerBlockParser;
31      private final HeaderBlockFragments headerBlockFragments;
32      private State state = State.PREPARE;
33      private int length;
34  
35      public ContinuationBodyParser(HeaderParser headerParser, Parser.Listener listener, HeaderBlockParser headerBlockParser, HeaderBlockFragments headerBlockFragments)
36      {
37          super(headerParser, listener);
38          this.headerBlockParser = headerBlockParser;
39          this.headerBlockFragments = headerBlockFragments;
40      }
41  
42      @Override
43      protected void emptyBody(ByteBuffer buffer)
44      {
45          if (hasFlag(Flags.END_HEADERS))
46              onHeaders();
47      }
48  
49      @Override
50      public boolean parse(ByteBuffer buffer)
51      {
52          while (buffer.hasRemaining())
53          {
54              switch (state)
55              {
56                  case PREPARE:
57                  {
58                      // SPEC: wrong streamId is treated as connection error.
59                      if (getStreamId() == 0)
60                          return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_continuation_frame");
61  
62                      if (getStreamId() != headerBlockFragments.getStreamId())
63                          return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_continuation_stream");
64  
65                      length = getBodyLength();
66                      state = State.FRAGMENT;
67                      break;
68                  }
69                  case FRAGMENT:
70                  {
71                      int remaining = buffer.remaining();
72                      if (remaining < length)
73                      {
74                          headerBlockFragments.storeFragment(buffer, remaining, false);
75                          length -= remaining;
76                          break;
77                      }
78                      else
79                      {
80                          boolean last = hasFlag(Flags.END_HEADERS);
81                          headerBlockFragments.storeFragment(buffer, length, last);
82                          reset();
83                          if (last)
84                              onHeaders();
85                          return true;
86                      }
87                  }
88                  default:
89                  {
90                      throw new IllegalStateException();
91                  }
92              }
93          }
94          return false;
95      }
96  
97      private void onHeaders()
98      {
99          ByteBuffer headerBlock = headerBlockFragments.complete();
100         MetaData metaData = headerBlockParser.parse(headerBlock, headerBlock.remaining());
101         HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, headerBlockFragments.getPriorityFrame(), headerBlockFragments.isEndStream());
102         notifyHeaders(frame);
103     }
104 
105     private void reset()
106     {
107         state = State.PREPARE;
108         length = 0;
109     }
110 
111     private enum State
112     {
113         PREPARE, FRAGMENT
114     }
115 }