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.http.MetaData;
24 import org.eclipse.jetty.http2.Flags;
25 import org.eclipse.jetty.http2.frames.Frame;
26 import org.eclipse.jetty.http2.frames.FrameType;
27 import org.eclipse.jetty.http2.frames.HeadersFrame;
28 import org.eclipse.jetty.http2.hpack.HpackEncoder;
29 import org.eclipse.jetty.io.ByteBufferPool;
30 import org.eclipse.jetty.util.BufferUtil;
31
32 public class HeadersGenerator extends FrameGenerator
33 {
34 private final HpackEncoder encoder;
35 private final int maxHeaderBlockFragment;
36
37 public HeadersGenerator(HeaderGenerator headerGenerator, HpackEncoder encoder)
38 {
39 this(headerGenerator, encoder, 0);
40 }
41
42 public HeadersGenerator(HeaderGenerator headerGenerator, HpackEncoder encoder, int maxHeaderBlockFragment)
43 {
44 super(headerGenerator);
45 this.encoder = encoder;
46 this.maxHeaderBlockFragment = maxHeaderBlockFragment;
47 }
48
49 @Override
50 public void generate(ByteBufferPool.Lease lease, Frame frame)
51 {
52 HeadersFrame headersFrame = (HeadersFrame)frame;
53 generateHeaders(lease, headersFrame.getStreamId(), headersFrame.getMetaData(), !headersFrame.isEndStream());
54 }
55
56 public void generateHeaders(ByteBufferPool.Lease lease, int streamId, MetaData metaData, boolean contentFollows)
57 {
58 if (streamId < 0)
59 throw new IllegalArgumentException("Invalid stream id: " + streamId);
60
61 int maxFrameSize = getMaxFrameSize();
62
63 ByteBuffer hpacked = lease.acquire(maxFrameSize, false);
64 BufferUtil.clearToFill(hpacked);
65 encoder.encode(hpacked, metaData);
66 int hpackedLength = hpacked.position();
67 BufferUtil.flipToFlush(hpacked, 0);
68
69
70 if (maxHeaderBlockFragment > 0 && hpackedLength > maxHeaderBlockFragment)
71 {
72 int flags = contentFollows ? Flags.NONE : Flags.END_STREAM;
73 ByteBuffer header = generateHeader(lease, FrameType.HEADERS, maxHeaderBlockFragment, flags, streamId);
74 BufferUtil.flipToFlush(header, 0);
75 lease.append(header, true);
76 hpacked.limit(maxHeaderBlockFragment);
77 lease.append(hpacked.slice(), false);
78
79 int position = maxHeaderBlockFragment;
80 int limit = position + maxHeaderBlockFragment;
81 while (limit < hpackedLength)
82 {
83 hpacked.position(position).limit(limit);
84 header = generateHeader(lease, FrameType.CONTINUATION, maxHeaderBlockFragment, Flags.NONE, streamId);
85 BufferUtil.flipToFlush(header, 0);
86 lease.append(header, true);
87 lease.append(hpacked.slice(), false);
88 position += maxHeaderBlockFragment;
89 limit += maxHeaderBlockFragment;
90 }
91
92 hpacked.position(position).limit(hpackedLength);
93 header = generateHeader(lease, FrameType.CONTINUATION, hpacked.remaining(), Flags.END_HEADERS, streamId);
94 BufferUtil.flipToFlush(header, 0);
95 lease.append(header, true);
96 lease.append(hpacked, true);
97 }
98 else
99 {
100 int flags = Flags.END_HEADERS;
101 if (!contentFollows)
102 flags |= Flags.END_STREAM;
103 ByteBuffer header = generateHeader(lease, FrameType.HEADERS, hpackedLength, flags, streamId);
104 BufferUtil.flipToFlush(header, 0);
105 lease.append(header, true);
106 lease.append(hpacked, true);
107 }
108 }
109 }