1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.http2.generator;
20
21 import java.nio.ByteBuffer;
22
23 import org.eclipse.jetty.http2.Flags;
24 import org.eclipse.jetty.http2.frames.DataFrame;
25 import org.eclipse.jetty.http2.frames.Frame;
26 import org.eclipse.jetty.http2.frames.FrameType;
27 import org.eclipse.jetty.io.ByteBufferPool;
28 import org.eclipse.jetty.util.BufferUtil;
29
30 public class DataGenerator
31 {
32 private final HeaderGenerator headerGenerator;
33
34 public DataGenerator(HeaderGenerator headerGenerator)
35 {
36 this.headerGenerator = headerGenerator;
37 }
38
39 public int generate(ByteBufferPool.Lease lease, DataFrame frame, int maxLength)
40 {
41 return generateData(lease, frame.getStreamId(), frame.getData(), frame.isEndStream(), maxLength);
42 }
43
44 public int generateData(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last, int maxLength)
45 {
46 if (streamId < 0)
47 throw new IllegalArgumentException("Invalid stream id: " + streamId);
48
49 int dataLength = data.remaining();
50 int maxFrameSize = headerGenerator.getMaxFrameSize();
51 if (dataLength <= maxLength && dataLength <= maxFrameSize)
52 {
53
54 return generateFrame(lease, streamId, data, last);
55 }
56
57
58
59 int length = Math.min(maxLength, dataLength);
60 int frames = length / maxFrameSize;
61 if (frames * maxFrameSize != length)
62 ++frames;
63
64 int totalLength = 0;
65 int begin = data.position();
66 int end = data.limit();
67 for (int i = 1; i <= frames; ++i)
68 {
69 int limit = begin + Math.min(maxFrameSize * i, length);
70 data.limit(limit);
71 ByteBuffer slice = data.slice();
72 data.position(limit);
73 totalLength += generateFrame(lease, streamId, slice, i == frames && last && limit == end);
74 }
75 data.limit(end);
76
77 return totalLength;
78 }
79
80 private int generateFrame(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last)
81 {
82 int length = data.remaining();
83
84 int flags = Flags.NONE;
85 if (last)
86 flags |= Flags.END_STREAM;
87
88 ByteBuffer header = headerGenerator.generate(lease, FrameType.DATA, Frame.HEADER_LENGTH + length, length, flags, streamId);
89 BufferUtil.flipToFlush(header, 0);
90 lease.append(header, true);
91 lease.append(data, false);
92
93 return Frame.HEADER_LENGTH + length;
94 }
95 }