View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2015 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                      }
77                      else
78                      {
79                          boolean last = hasFlag(Flags.END_HEADERS);
80                          headerBlockFragments.storeFragment(buffer, length, last);
81                          reset();
82                          if (last)
83                              onHeaders();
84                          return true;
85                      }
86                  }
87                  default:
88                  {
89                      throw new IllegalStateException();
90                  }
91              }
92          }
93          return false;
94      }
95  
96      private void onHeaders()
97      {
98          ByteBuffer headerBlock = headerBlockFragments.complete();
99          MetaData metaData = headerBlockParser.parse(headerBlock, headerBlock.remaining());
100         HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, headerBlockFragments.getPriorityFrame(), headerBlockFragments.isEndStream());
101         notifyHeaders(frame);
102     }
103 
104     private void reset()
105     {
106         state = State.PREPARE;
107         length = 0;
108     }
109 
110     private enum State
111     {
112         PREPARE, FRAGMENT
113     }
114 }