< prev index next >

src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/internal/frame/FramesEncoder.java

Print this page


   1 /*
   2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.incubator.http.internal.frame;
  27 
  28 import jdk.incubator.http.internal.common.ByteBufferReference;
  29 import jdk.incubator.http.internal.common.Utils;
  30 
  31 import java.nio.ByteBuffer;
  32 import java.util.ArrayList;
  33 import java.util.Arrays;
  34 import java.util.List;
  35 
  36 /**
  37  * Frames Encoder
  38  *
  39  * Encode framed into ByteBuffers.
  40  * The class is stateless.
  41  */
  42 public class FramesEncoder {
  43 
  44 
  45     public FramesEncoder() {
  46     }
  47 
  48     public ByteBufferReference[] encodeFrames(List<HeaderFrame> frames) {
  49         List<ByteBufferReference> refs = new ArrayList<>(frames.size() * 2);
  50         for (HeaderFrame f : frames) {
  51             refs.addAll(Arrays.asList(encodeFrame(f)));
  52         }
  53         return refs.toArray(new ByteBufferReference[0]);
  54     }
  55 
  56     public ByteBufferReference encodeConnectionPreface(byte[] preface, SettingsFrame frame) {
  57         final int length = frame.length();
  58         ByteBufferReference ref = getBuffer(Http2Frame.FRAME_HEADER_SIZE + length + preface.length);
  59         ByteBuffer buf = ref.get();
  60         buf.put(preface);
  61         putSettingsFrame(buf, frame, length);
  62         buf.flip();
  63         return ref;
  64     }
  65 
  66     public ByteBufferReference[] encodeFrame(Http2Frame frame) {
  67         switch (frame.type()) {
  68             case DataFrame.TYPE:
  69                 return encodeDataFrame((DataFrame) frame);
  70             case HeadersFrame.TYPE:
  71                 return encodeHeadersFrame((HeadersFrame) frame);
  72             case PriorityFrame.TYPE:
  73                 return encodePriorityFrame((PriorityFrame) frame);
  74             case ResetFrame.TYPE:
  75                 return encodeResetFrame((ResetFrame) frame);
  76             case SettingsFrame.TYPE:
  77                 return encodeSettingsFrame((SettingsFrame) frame);
  78             case PushPromiseFrame.TYPE:
  79                 return encodePushPromiseFrame((PushPromiseFrame) frame);
  80             case PingFrame.TYPE:
  81                 return encodePingFrame((PingFrame) frame);
  82             case GoAwayFrame.TYPE:
  83                 return encodeGoAwayFrame((GoAwayFrame) frame);
  84             case WindowUpdateFrame.TYPE:
  85                 return encodeWindowUpdateFrame((WindowUpdateFrame) frame);
  86             case ContinuationFrame.TYPE:
  87                 return encodeContinuationFrame((ContinuationFrame) frame);
  88             default:
  89                 throw new UnsupportedOperationException("Not supported frame "+frame.type()+" ("+frame.getClass().getName()+")");
  90         }
  91     }
  92 
  93     private static final int NO_FLAGS = 0;
  94     private static final int ZERO_STREAM = 0;
  95 
  96     private ByteBufferReference[] encodeDataFrame(DataFrame frame) {
  97         // non-zero stream
  98         assert frame.streamid() != 0;
  99         ByteBufferReference ref = encodeDataFrameStart(frame);
 100         if (frame.getFlag(DataFrame.PADDED)) {
 101             return joinWithPadding(ref, frame.getData(), frame.getPadLength());
 102         } else {
 103             return join(ref, frame.getData());
 104         }
 105     }
 106 
 107     private ByteBufferReference encodeDataFrameStart(DataFrame frame) {
 108         boolean isPadded = frame.getFlag(DataFrame.PADDED);
 109         final int length = frame.getDataLength() + (isPadded ? (frame.getPadLength() + 1) : 0);
 110         ByteBufferReference ref = getBuffer(Http2Frame.FRAME_HEADER_SIZE + (isPadded ? 1 : 0));
 111         ByteBuffer buf = ref.get();
 112         putHeader(buf, length, DataFrame.TYPE, frame.getFlags(), frame.streamid());
 113         if (isPadded) {
 114             buf.put((byte) frame.getPadLength());
 115         }
 116         buf.flip();
 117         return ref;
 118     }
 119 
 120     private ByteBufferReference[] encodeHeadersFrame(HeadersFrame frame) {
 121         // non-zero stream
 122         assert frame.streamid() != 0;
 123         ByteBufferReference ref = encodeHeadersFrameStart(frame);
 124         if (frame.getFlag(HeadersFrame.PADDED)) {
 125             return joinWithPadding(ref, frame.getHeaderBlock(), frame.getPadLength());
 126         } else {
 127             return join(ref, frame.getHeaderBlock());
 128         }
 129     }
 130 
 131     private ByteBufferReference encodeHeadersFrameStart(HeadersFrame frame) {
 132         boolean isPadded = frame.getFlag(HeadersFrame.PADDED);
 133         boolean hasPriority = frame.getFlag(HeadersFrame.PRIORITY);
 134         final int length = frame.getHeaderLength() + (isPadded ? (frame.getPadLength() + 1) : 0) + (hasPriority ? 5 : 0);
 135         ByteBufferReference ref = getBuffer(Http2Frame.FRAME_HEADER_SIZE + (isPadded ? 1 : 0) + (hasPriority ? 5 : 0));
 136         ByteBuffer buf = ref.get();
 137         putHeader(buf, length, HeadersFrame.TYPE, frame.getFlags(), frame.streamid());
 138         if (isPadded) {
 139             buf.put((byte) frame.getPadLength());
 140         }
 141         if (hasPriority) {
 142             putPriority(buf, frame.getExclusive(), frame.getStreamDependency(), frame.getWeight());
 143         }
 144         buf.flip();
 145         return ref;
 146     }
 147 
 148     private ByteBufferReference[] encodePriorityFrame(PriorityFrame frame) {
 149         // non-zero stream; no flags
 150         assert frame.streamid() != 0;
 151         final int length = 5;
 152         ByteBufferReference ref = getBuffer(Http2Frame.FRAME_HEADER_SIZE + length);
 153         ByteBuffer buf = ref.get();
 154         putHeader(buf, length, PriorityFrame.TYPE, NO_FLAGS, frame.streamid());
 155         putPriority(buf, frame.exclusive(), frame.streamDependency(), frame.weight());
 156         buf.flip();
 157         return new ByteBufferReference[]{ref};
 158     }
 159 
 160     private ByteBufferReference[] encodeResetFrame(ResetFrame frame) {
 161         // non-zero stream; no flags
 162         assert frame.streamid() != 0;
 163         final int length = 4;
 164         ByteBufferReference ref = getBuffer(Http2Frame.FRAME_HEADER_SIZE + length);
 165         ByteBuffer buf = ref.get();
 166         putHeader(buf, length, ResetFrame.TYPE, NO_FLAGS, frame.streamid());
 167         buf.putInt(frame.getErrorCode());
 168         buf.flip();
 169         return new ByteBufferReference[]{ref};
 170     }
 171 
 172     private ByteBufferReference[] encodeSettingsFrame(SettingsFrame frame) {
 173         // only zero stream
 174         assert frame.streamid() == 0;
 175         final int length = frame.length();
 176         ByteBufferReference ref = getBuffer(Http2Frame.FRAME_HEADER_SIZE + length);
 177         ByteBuffer buf = ref.get();
 178         putSettingsFrame(buf, frame, length);
 179         buf.flip();
 180         return new ByteBufferReference[]{ref};
 181     }
 182 
 183     private ByteBufferReference[] encodePushPromiseFrame(PushPromiseFrame frame) {
 184         // non-zero stream
 185         assert frame.streamid() != 0;
 186         boolean isPadded = frame.getFlag(PushPromiseFrame.PADDED);
 187         final int length = frame.getHeaderLength() + (isPadded ? 5 : 4);
 188         ByteBufferReference ref = getBuffer(Http2Frame.FRAME_HEADER_SIZE + (isPadded ? 5 : 4));
 189         ByteBuffer buf = ref.get();
 190         putHeader(buf, length, PushPromiseFrame.TYPE, frame.getFlags(), frame.streamid());
 191         if (isPadded) {
 192             buf.put((byte) frame.getPadLength());
 193         }
 194         buf.putInt(frame.getPromisedStream());
 195         buf.flip();
 196 
 197         if (frame.getFlag(PushPromiseFrame.PADDED)) {
 198             return joinWithPadding(ref, frame.getHeaderBlock(), frame.getPadLength());
 199         } else {
 200             return join(ref, frame.getHeaderBlock());
 201         }
 202     }
 203 
 204     private ByteBufferReference[] encodePingFrame(PingFrame frame) {
 205         // only zero stream
 206         assert frame.streamid() == 0;
 207         final int length = 8;
 208         ByteBufferReference ref = getBuffer(Http2Frame.FRAME_HEADER_SIZE + length);
 209         ByteBuffer buf = ref.get();
 210         putHeader(buf, length, PingFrame.TYPE, frame.getFlags(), ZERO_STREAM);
 211         buf.put(frame.getData());
 212         buf.flip();
 213         return new ByteBufferReference[]{ref};
 214     }
 215 
 216     private ByteBufferReference[] encodeGoAwayFrame(GoAwayFrame frame) {
 217         // only zero stream; no flags
 218         assert frame.streamid() == 0;
 219         byte[] debugData = frame.getDebugData();
 220         final int length = 8 + debugData.length;
 221         ByteBufferReference ref = getBuffer(Http2Frame.FRAME_HEADER_SIZE + length);
 222         ByteBuffer buf = ref.get();
 223         putHeader(buf, length, GoAwayFrame.TYPE, NO_FLAGS, ZERO_STREAM);
 224         buf.putInt(frame.getLastStream());
 225         buf.putInt(frame.getErrorCode());
 226         if (debugData.length > 0) {
 227             buf.put(debugData);
 228         }
 229         buf.flip();
 230         return new ByteBufferReference[]{ref};
 231     }
 232 
 233     private ByteBufferReference[] encodeWindowUpdateFrame(WindowUpdateFrame frame) {
 234         // any stream; no flags
 235         final int length = 4;
 236         ByteBufferReference ref = getBuffer(Http2Frame.FRAME_HEADER_SIZE + length);
 237         ByteBuffer buf = ref.get();
 238         putHeader(buf, length, WindowUpdateFrame.TYPE, NO_FLAGS, frame.streamid);
 239         buf.putInt(frame.getUpdate());
 240         buf.flip();
 241         return new ByteBufferReference[]{ref};
 242     }
 243 
 244     private ByteBufferReference[] encodeContinuationFrame(ContinuationFrame frame) {
 245         // non-zero stream;
 246         assert frame.streamid() != 0;
 247         final int length = frame.getHeaderLength();
 248         ByteBufferReference ref = getBuffer(Http2Frame.FRAME_HEADER_SIZE);
 249         ByteBuffer buf = ref.get();
 250         putHeader(buf, length, ContinuationFrame.TYPE, frame.getFlags(), frame.streamid());
 251         buf.flip();
 252         return join(ref, frame.getHeaderBlock());
 253     }
 254 
 255     private ByteBufferReference[] joinWithPadding(ByteBufferReference ref, ByteBufferReference[] data, int padLength) {
 256         ByteBufferReference[] references = new ByteBufferReference[2 + data.length];
 257         references[0] = ref;
 258         System.arraycopy(data, 0, references, 1, data.length);
 259         assert references[references.length - 1] == null;
 260         references[references.length - 1] = getPadding(padLength);
 261         return references;
 262     }
 263 
 264     private ByteBufferReference[] join(ByteBufferReference ref, ByteBufferReference[] data) {
 265         ByteBufferReference[] references = new ByteBufferReference[1 + data.length];
 266         references[0] = ref;
 267         System.arraycopy(data, 0, references, 1, data.length);
 268         return references;







 269     }
 270 
 271     private void putSettingsFrame(ByteBuffer buf, SettingsFrame frame, int length) {
 272         // only zero stream;
 273         assert frame.streamid() == 0;
 274         putHeader(buf, length, SettingsFrame.TYPE, frame.getFlags(), ZERO_STREAM);
 275         frame.toByteBuffer(buf);
 276     }
 277 
 278     private void putHeader(ByteBuffer buf, int length, int type, int flags, int streamId) {
 279         int x = (length << 8) + type;
 280         buf.putInt(x);
 281         buf.put((byte) flags);
 282         buf.putInt(streamId);
 283     }
 284 
 285     private void putPriority(ByteBuffer buf, boolean exclusive, int streamDependency, int weight) {
 286         buf.putInt(exclusive ? (1 << 31) + streamDependency : streamDependency);
 287         buf.put((byte) weight);
 288     }
 289 
 290     private ByteBufferReference getBuffer(int capacity) {
 291         return ByteBufferReference.of(ByteBuffer.allocate(capacity));
 292     }
 293 
 294     public ByteBufferReference getPadding(int length) {
 295         if (length > 255) {
 296             throw new IllegalArgumentException("Padding too big");
 297         }
 298         return ByteBufferReference.of(ByteBuffer.allocate(length)); // zeroed!
 299     }
 300 
 301 }
   1 /*
   2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.incubator.http.internal.frame;
  27 



  28 import java.nio.ByteBuffer;
  29 import java.util.ArrayList;

  30 import java.util.List;
  31 
  32 /**
  33  * Frames Encoder
  34  *
  35  * Encode framed into ByteBuffers.
  36  * The class is stateless.
  37  */
  38 public class FramesEncoder {
  39 
  40 
  41     public FramesEncoder() {
  42     }
  43 
  44     public List<ByteBuffer> encodeFrames(List<HeaderFrame> frames) {
  45         List<ByteBuffer> bufs = new ArrayList<>(frames.size() * 2);
  46         for (HeaderFrame f : frames) {
  47             bufs.addAll(encodeFrame(f));
  48         }
  49         return bufs;
  50     }
  51 
  52     public ByteBuffer encodeConnectionPreface(byte[] preface, SettingsFrame frame) {
  53         final int length = frame.length();
  54         ByteBuffer buf = getBuffer(Http2Frame.FRAME_HEADER_SIZE + length + preface.length);

  55         buf.put(preface);
  56         putSettingsFrame(buf, frame, length);
  57         buf.flip();
  58         return buf;
  59     }
  60 
  61     public List<ByteBuffer> encodeFrame(Http2Frame frame) {
  62         switch (frame.type()) {
  63             case DataFrame.TYPE:
  64                 return encodeDataFrame((DataFrame) frame);
  65             case HeadersFrame.TYPE:
  66                 return encodeHeadersFrame((HeadersFrame) frame);
  67             case PriorityFrame.TYPE:
  68                 return encodePriorityFrame((PriorityFrame) frame);
  69             case ResetFrame.TYPE:
  70                 return encodeResetFrame((ResetFrame) frame);
  71             case SettingsFrame.TYPE:
  72                 return encodeSettingsFrame((SettingsFrame) frame);
  73             case PushPromiseFrame.TYPE:
  74                 return encodePushPromiseFrame((PushPromiseFrame) frame);
  75             case PingFrame.TYPE:
  76                 return encodePingFrame((PingFrame) frame);
  77             case GoAwayFrame.TYPE:
  78                 return encodeGoAwayFrame((GoAwayFrame) frame);
  79             case WindowUpdateFrame.TYPE:
  80                 return encodeWindowUpdateFrame((WindowUpdateFrame) frame);
  81             case ContinuationFrame.TYPE:
  82                 return encodeContinuationFrame((ContinuationFrame) frame);
  83             default:
  84                 throw new UnsupportedOperationException("Not supported frame "+frame.type()+" ("+frame.getClass().getName()+")");
  85         }
  86     }
  87 
  88     private static final int NO_FLAGS = 0;
  89     private static final int ZERO_STREAM = 0;
  90 
  91     private List<ByteBuffer> encodeDataFrame(DataFrame frame) {
  92         // non-zero stream
  93         assert frame.streamid() != 0;
  94         ByteBuffer buf = encodeDataFrameStart(frame);
  95         if (frame.getFlag(DataFrame.PADDED)) {
  96             return joinWithPadding(buf, frame.getData(), frame.getPadLength());
  97         } else {
  98             return join(buf, frame.getData());
  99         }
 100     }
 101 
 102     private ByteBuffer encodeDataFrameStart(DataFrame frame) {
 103         boolean isPadded = frame.getFlag(DataFrame.PADDED);
 104         final int length = frame.getDataLength() + (isPadded ? (frame.getPadLength() + 1) : 0);
 105         ByteBuffer buf = getBuffer(Http2Frame.FRAME_HEADER_SIZE + (isPadded ? 1 : 0));

 106         putHeader(buf, length, DataFrame.TYPE, frame.getFlags(), frame.streamid());
 107         if (isPadded) {
 108             buf.put((byte) frame.getPadLength());
 109         }
 110         buf.flip();
 111         return buf;
 112     }
 113 
 114     private List<ByteBuffer> encodeHeadersFrame(HeadersFrame frame) {
 115         // non-zero stream
 116         assert frame.streamid() != 0;
 117         ByteBuffer buf = encodeHeadersFrameStart(frame);
 118         if (frame.getFlag(HeadersFrame.PADDED)) {
 119             return joinWithPadding(buf, frame.getHeaderBlock(), frame.getPadLength());
 120         } else {
 121             return join(buf, frame.getHeaderBlock());
 122         }
 123     }
 124 
 125     private ByteBuffer encodeHeadersFrameStart(HeadersFrame frame) {
 126         boolean isPadded = frame.getFlag(HeadersFrame.PADDED);
 127         boolean hasPriority = frame.getFlag(HeadersFrame.PRIORITY);
 128         final int length = frame.getHeaderLength() + (isPadded ? (frame.getPadLength() + 1) : 0) + (hasPriority ? 5 : 0);
 129         ByteBuffer buf = getBuffer(Http2Frame.FRAME_HEADER_SIZE + (isPadded ? 1 : 0) + (hasPriority ? 5 : 0));

 130         putHeader(buf, length, HeadersFrame.TYPE, frame.getFlags(), frame.streamid());
 131         if (isPadded) {
 132             buf.put((byte) frame.getPadLength());
 133         }
 134         if (hasPriority) {
 135             putPriority(buf, frame.getExclusive(), frame.getStreamDependency(), frame.getWeight());
 136         }
 137         buf.flip();
 138         return buf;
 139     }
 140 
 141     private List<ByteBuffer> encodePriorityFrame(PriorityFrame frame) {
 142         // non-zero stream; no flags
 143         assert frame.streamid() != 0;
 144         final int length = 5;
 145         ByteBuffer buf = getBuffer(Http2Frame.FRAME_HEADER_SIZE + length);

 146         putHeader(buf, length, PriorityFrame.TYPE, NO_FLAGS, frame.streamid());
 147         putPriority(buf, frame.exclusive(), frame.streamDependency(), frame.weight());
 148         buf.flip();
 149         return List.of(buf);
 150     }
 151 
 152     private List<ByteBuffer> encodeResetFrame(ResetFrame frame) {
 153         // non-zero stream; no flags
 154         assert frame.streamid() != 0;
 155         final int length = 4;
 156         ByteBuffer buf = getBuffer(Http2Frame.FRAME_HEADER_SIZE + length);

 157         putHeader(buf, length, ResetFrame.TYPE, NO_FLAGS, frame.streamid());
 158         buf.putInt(frame.getErrorCode());
 159         buf.flip();
 160         return List.of(buf);
 161     }
 162 
 163     private List<ByteBuffer> encodeSettingsFrame(SettingsFrame frame) {
 164         // only zero stream
 165         assert frame.streamid() == 0;
 166         final int length = frame.length();
 167         ByteBuffer buf = getBuffer(Http2Frame.FRAME_HEADER_SIZE + length);

 168         putSettingsFrame(buf, frame, length);
 169         buf.flip();
 170         return List.of(buf);
 171     }
 172 
 173     private List<ByteBuffer> encodePushPromiseFrame(PushPromiseFrame frame) {
 174         // non-zero stream
 175         assert frame.streamid() != 0;
 176         boolean isPadded = frame.getFlag(PushPromiseFrame.PADDED);
 177         final int length = frame.getHeaderLength() + (isPadded ? 5 : 4);
 178         ByteBuffer buf = getBuffer(Http2Frame.FRAME_HEADER_SIZE + (isPadded ? 5 : 4));

 179         putHeader(buf, length, PushPromiseFrame.TYPE, frame.getFlags(), frame.streamid());
 180         if (isPadded) {
 181             buf.put((byte) frame.getPadLength());
 182         }
 183         buf.putInt(frame.getPromisedStream());
 184         buf.flip();
 185 
 186         if (frame.getFlag(PushPromiseFrame.PADDED)) {
 187             return joinWithPadding(buf, frame.getHeaderBlock(), frame.getPadLength());
 188         } else {
 189             return join(buf, frame.getHeaderBlock());
 190         }
 191     }
 192 
 193     private List<ByteBuffer> encodePingFrame(PingFrame frame) {
 194         // only zero stream
 195         assert frame.streamid() == 0;
 196         final int length = 8;
 197         ByteBuffer buf = getBuffer(Http2Frame.FRAME_HEADER_SIZE + length);

 198         putHeader(buf, length, PingFrame.TYPE, frame.getFlags(), ZERO_STREAM);
 199         buf.put(frame.getData());
 200         buf.flip();
 201         return List.of(buf);
 202     }
 203 
 204     private List<ByteBuffer> encodeGoAwayFrame(GoAwayFrame frame) {
 205         // only zero stream; no flags
 206         assert frame.streamid() == 0;
 207         byte[] debugData = frame.getDebugData();
 208         final int length = 8 + debugData.length;
 209         ByteBuffer buf = getBuffer(Http2Frame.FRAME_HEADER_SIZE + length);

 210         putHeader(buf, length, GoAwayFrame.TYPE, NO_FLAGS, ZERO_STREAM);
 211         buf.putInt(frame.getLastStream());
 212         buf.putInt(frame.getErrorCode());
 213         if (debugData.length > 0) {
 214             buf.put(debugData);
 215         }
 216         buf.flip();
 217         return List.of(buf);
 218     }
 219 
 220     private List<ByteBuffer> encodeWindowUpdateFrame(WindowUpdateFrame frame) {
 221         // any stream; no flags
 222         final int length = 4;
 223         ByteBuffer buf = getBuffer(Http2Frame.FRAME_HEADER_SIZE + length);

 224         putHeader(buf, length, WindowUpdateFrame.TYPE, NO_FLAGS, frame.streamid);
 225         buf.putInt(frame.getUpdate());
 226         buf.flip();
 227         return List.of(buf);
 228     }
 229 
 230     private List<ByteBuffer> encodeContinuationFrame(ContinuationFrame frame) {
 231         // non-zero stream;
 232         assert frame.streamid() != 0;
 233         final int length = frame.getHeaderLength();
 234         ByteBuffer buf = getBuffer(Http2Frame.FRAME_HEADER_SIZE);

 235         putHeader(buf, length, ContinuationFrame.TYPE, frame.getFlags(), frame.streamid());
 236         buf.flip();
 237         return join(buf, frame.getHeaderBlock());
 238     }
 239 
 240     private List<ByteBuffer> joinWithPadding(ByteBuffer buf, List<ByteBuffer> data, int padLength) {
 241         int len = data.size();
 242         if (len == 0) return List.of(buf, getPadding(padLength));
 243         else if (len == 1) return List.of(buf, data.get(0), getPadding(padLength));
 244         else if (len == 2) return List.of(buf, data.get(0), data.get(1), getPadding(padLength));
 245         List<ByteBuffer> res = new ArrayList<>(len+2);
 246         res.add(buf);
 247         res.addAll(data);
 248         res.add(getPadding(padLength));
 249         return res;
 250     }
 251 
 252     private List<ByteBuffer> join(ByteBuffer buf, List<ByteBuffer> data) {
 253         int len = data.size();
 254         if (len == 0) return List.of(buf);
 255         else if (len == 1) return List.of(buf, data.get(0));
 256         else if (len == 2) return List.of(buf, data.get(0), data.get(1));
 257         List<ByteBuffer> joined = new ArrayList<>(len + 1);
 258         joined.add(buf);
 259         joined.addAll(data);
 260         return joined;
 261     }
 262 
 263     private void putSettingsFrame(ByteBuffer buf, SettingsFrame frame, int length) {
 264         // only zero stream;
 265         assert frame.streamid() == 0;
 266         putHeader(buf, length, SettingsFrame.TYPE, frame.getFlags(), ZERO_STREAM);
 267         frame.toByteBuffer(buf);
 268     }
 269 
 270     private void putHeader(ByteBuffer buf, int length, int type, int flags, int streamId) {
 271         int x = (length << 8) + type;
 272         buf.putInt(x);
 273         buf.put((byte) flags);
 274         buf.putInt(streamId);
 275     }
 276 
 277     private void putPriority(ByteBuffer buf, boolean exclusive, int streamDependency, int weight) {
 278         buf.putInt(exclusive ? (1 << 31) + streamDependency : streamDependency);
 279         buf.put((byte) weight);
 280     }
 281 
 282     private ByteBuffer getBuffer(int capacity) {
 283         return ByteBuffer.allocate(capacity);
 284     }
 285 
 286     public ByteBuffer getPadding(int length) {
 287         if (length > 255) {
 288             throw new IllegalArgumentException("Padding too big");
 289         }
 290         return ByteBuffer.allocate(length); // zeroed!
 291     }
 292 
 293 }
< prev index next >