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.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          // Split into CONTINUATION frames if necessary.
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 }