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.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 void generate(ByteBufferPool.Lease lease, DataFrame frame, int maxLength)
40      {
41          generateData(lease, frame.getStreamId(), frame.getData(), frame.isEndStream(), maxLength);
42      }
43  
44      public void 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              // Single frame.
54              generateFrame(lease, streamId, data, last);
55              return;
56          }
57  
58          // Other cases, we need to slice the original buffer into multiple frames.
59  
60          int length = Math.min(maxLength, dataLength);
61          int frames = length / maxFrameSize;
62          if (frames * maxFrameSize != length)
63              ++frames;
64  
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              generateFrame(lease, streamId, slice, i == frames && last && limit == end);
74          }
75          data.limit(end);
76      }
77  
78      private void generateFrame(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last)
79      {
80          int length = data.remaining();
81  
82          int flags = Flags.NONE;
83          if (last)
84              flags |= Flags.END_STREAM;
85  
86          ByteBuffer header = headerGenerator.generate(lease, FrameType.DATA, Frame.HEADER_LENGTH + length, length, flags, streamId);
87  
88          BufferUtil.flipToFlush(header, 0);
89          lease.append(header, true);
90  
91          lease.append(data, false);
92      }
93  }