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.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.frames.PriorityFrame;
29  import org.eclipse.jetty.http2.hpack.HpackEncoder;
30  import org.eclipse.jetty.io.ByteBufferPool;
31  import org.eclipse.jetty.util.BufferUtil;
32  
33  public class HeadersGenerator extends FrameGenerator
34  {
35      private final HpackEncoder encoder;
36      private final int maxHeaderBlockFragment;
37      private final PriorityGenerator priorityGenerator;
38  
39      public HeadersGenerator(HeaderGenerator headerGenerator, HpackEncoder encoder)
40      {
41          this(headerGenerator, encoder, 0);
42      }
43  
44      public HeadersGenerator(HeaderGenerator headerGenerator, HpackEncoder encoder, int maxHeaderBlockFragment)
45      {
46          super(headerGenerator);
47          this.encoder = encoder;
48          this.maxHeaderBlockFragment = maxHeaderBlockFragment;
49          this.priorityGenerator = new PriorityGenerator(headerGenerator);
50      }
51  
52      @Override
53      public void generate(ByteBufferPool.Lease lease, Frame frame)
54      {
55          HeadersFrame headersFrame = (HeadersFrame)frame;
56          generateHeaders(lease, headersFrame.getStreamId(), headersFrame.getMetaData(), headersFrame.getPriority(), headersFrame.isEndStream());
57      }
58  
59      public void generateHeaders(ByteBufferPool.Lease lease, int streamId, MetaData metaData, PriorityFrame priority, boolean endStream)
60      {
61          if (streamId < 0)
62              throw new IllegalArgumentException("Invalid stream id: " + streamId);
63  
64          int flags = Flags.NONE;
65  
66          if (priority != null)
67              flags = Flags.PRIORITY;
68  
69          int maxFrameSize = getMaxFrameSize();
70          ByteBuffer hpacked = lease.acquire(maxFrameSize, false);
71          BufferUtil.clearToFill(hpacked);
72          encoder.encode(hpacked, metaData);
73          int hpackedLength = hpacked.position();
74          BufferUtil.flipToFlush(hpacked, 0);
75  
76          // Split into CONTINUATION frames if necessary.
77          if (maxHeaderBlockFragment > 0 && hpackedLength > maxHeaderBlockFragment)
78          {
79              if (endStream)
80                  flags |= Flags.END_STREAM;
81  
82              int length = maxHeaderBlockFragment;
83              if (priority != null)
84                  length += PriorityFrame.PRIORITY_LENGTH;
85  
86              ByteBuffer header = generateHeader(lease, FrameType.HEADERS, length, flags, streamId);
87              generatePriority(header, priority);
88              BufferUtil.flipToFlush(header, 0);
89              lease.append(header, true);
90  
91              hpacked.limit(maxHeaderBlockFragment);
92              lease.append(hpacked.slice(), false);
93  
94              int position = maxHeaderBlockFragment;
95              int limit = position + maxHeaderBlockFragment;
96              while (limit < hpackedLength)
97              {
98                  hpacked.position(position).limit(limit);
99                  header = generateHeader(lease, FrameType.CONTINUATION, maxHeaderBlockFragment, Flags.NONE, streamId);
100                 BufferUtil.flipToFlush(header, 0);
101                 lease.append(header, true);
102                 lease.append(hpacked.slice(), false);
103                 position += maxHeaderBlockFragment;
104                 limit += maxHeaderBlockFragment;
105             }
106 
107             hpacked.position(position).limit(hpackedLength);
108             header = generateHeader(lease, FrameType.CONTINUATION, hpacked.remaining(), Flags.END_HEADERS, streamId);
109             BufferUtil.flipToFlush(header, 0);
110             lease.append(header, true);
111             lease.append(hpacked, true);
112         }
113         else
114         {
115             flags |= Flags.END_HEADERS;
116             if (endStream)
117                 flags |= Flags.END_STREAM;
118 
119             int length = hpackedLength;
120             if (priority != null)
121                 length += PriorityFrame.PRIORITY_LENGTH;
122 
123             ByteBuffer header = generateHeader(lease, FrameType.HEADERS, length, flags, streamId);
124             generatePriority(header, priority);
125             BufferUtil.flipToFlush(header, 0);
126             lease.append(header, true);
127             lease.append(hpacked, true);
128         }
129     }
130 
131     private void generatePriority(ByteBuffer header, PriorityFrame priority)
132     {
133         if (priority != null)
134         {
135             priorityGenerator.generatePriorityBody(header, priority.getStreamId(),
136                     priority.getParentStreamId(), priority.getWeight(), priority.isExclusive());
137         }
138     }
139 }