1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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.frames.DataFrame;
25 import org.eclipse.jetty.util.BufferUtil;
26
27 public class DataBodyParser extends BodyParser
28 {
29 private State state = State.PREPARE;
30 private int padding;
31 private int paddingLength;
32 private int length;
33
34 public DataBodyParser(HeaderParser headerParser, Parser.Listener listener)
35 {
36 super(headerParser, listener);
37 }
38
39 private void reset()
40 {
41 state = State.PREPARE;
42 padding = 0;
43 paddingLength = 0;
44 length = 0;
45 }
46
47 @Override
48 protected void emptyBody(ByteBuffer buffer)
49 {
50 if (isPadding())
51 connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_data_frame");
52 else
53 onData(BufferUtil.EMPTY_BUFFER, false, 0);
54 }
55
56 @Override
57 public boolean parse(ByteBuffer buffer)
58 {
59 boolean loop = false;
60 while (buffer.hasRemaining() || loop)
61 {
62 switch (state)
63 {
64 case PREPARE:
65 {
66
67 if (getStreamId() == 0)
68 return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_data_frame");
69
70 length = getBodyLength();
71 state = isPadding() ? State.PADDING_LENGTH : State.DATA;
72 break;
73 }
74 case PADDING_LENGTH:
75 {
76 padding = 1;
77 paddingLength = buffer.get() & 0xFF;
78 --length;
79 length -= paddingLength;
80 state = State.DATA;
81 loop = length == 0;
82 if (length < 0)
83 return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_data_frame_padding");
84 break;
85 }
86 case DATA:
87 {
88 int size = Math.min(buffer.remaining(), length);
89 int position = buffer.position();
90 int limit = buffer.limit();
91 buffer.limit(position + size);
92 ByteBuffer slice = buffer.slice();
93 buffer.limit(limit);
94 buffer.position(position + size);
95
96 length -= size;
97 if (length == 0)
98 {
99 state = State.PADDING;
100 loop = paddingLength == 0;
101
102
103 onData(slice, false, padding + paddingLength);
104 }
105 else
106 {
107
108
109
110 onData(slice, true, 0);
111 }
112 break;
113 }
114 case PADDING:
115 {
116 int size = Math.min(buffer.remaining(), paddingLength);
117 buffer.position(buffer.position() + size);
118 paddingLength -= size;
119 if (paddingLength == 0)
120 {
121 reset();
122 return true;
123 }
124 break;
125 }
126 default:
127 {
128 throw new IllegalStateException();
129 }
130 }
131 }
132 return false;
133 }
134
135 private void onData(ByteBuffer buffer, boolean fragment, int padding)
136 {
137 DataFrame frame = new DataFrame(getStreamId(), buffer, !fragment && isEndStream(), padding);
138 notifyData(frame);
139 }
140
141 private enum State
142 {
143 PREPARE, PADDING_LENGTH, DATA, PADDING
144 }
145 }