1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.core5.http2.impl.io;
29
30 import java.io.IOException;
31 import java.io.OutputStream;
32 import java.nio.ByteBuffer;
33
34 import org.apache.hc.core5.http2.H2ConnectionException;
35 import org.apache.hc.core5.http2.H2Error;
36 import org.apache.hc.core5.http2.H2TransportMetrics;
37 import org.apache.hc.core5.http2.frame.FrameConsts;
38 import org.apache.hc.core5.http2.frame.FrameFlag;
39 import org.apache.hc.core5.http2.frame.RawFrame;
40 import org.apache.hc.core5.http2.impl.BasicH2TransportMetrics;
41 import org.apache.hc.core5.util.Args;
42
43
44
45
46
47
48 public final class FrameOutputBuffer {
49
50 private final BasicH2TransportMetrics metrics;
51 private final int maxFramePayloadSize;
52 private final byte[] buffer;
53
54 public FrameOutputBuffer(final BasicH2TransportMetrics metrics, final int maxFramePayloadSize) {
55 super();
56 Args.notNull(metrics, "HTTP2 transport metrics");
57 Args.positive(maxFramePayloadSize, "Maximum payload size");
58 this.metrics = metrics;
59 this.maxFramePayloadSize = maxFramePayloadSize;
60 this.buffer = new byte[FrameConsts.HEAD_LEN + maxFramePayloadSize + FrameConsts.MAX_PADDING + 1];
61 }
62
63 public FrameOutputBuffer(final int maxFramePayloadSize) {
64 this(new BasicH2TransportMetrics(), maxFramePayloadSize);
65 }
66
67 public void write(final RawFrame frame, final OutputStream outStream) throws IOException {
68 if (frame == null) {
69 return;
70 }
71 final int type = frame.getType();
72 final long streamId = frame.getStreamId();
73 final int flags = frame.getFlags();
74 final ByteBuffer payload = frame.getPayload();
75 final int payloadLen = payload != null ? payload.remaining() : 0;
76 if (payload != null && payload.remaining() > maxFramePayloadSize) {
77 throw new H2ConnectionException(H2Error.FRAME_SIZE_ERROR, "Frame size exceeds maximum");
78 }
79 buffer[0] = (byte) (payloadLen >> 16 & 0xff);
80 buffer[1] = (byte) (payloadLen >> 8 & 0xff);
81 buffer[2] = (byte) (payloadLen & 0xff);
82
83 buffer[3] = (byte) (type & 0xff);
84 buffer[4] = (byte) (flags & 0xff);
85
86 buffer[5] = (byte) (streamId >> 24 & 0xff);
87 buffer[6] = (byte) (streamId >> 16 & 0xff);
88 buffer[7] = (byte) (streamId >> 8 & 0xff);
89 buffer[8] = (byte) (streamId & 0xff);
90
91 int frameLen = FrameConsts.HEAD_LEN;
92 int padding = 0;
93 if ((flags & FrameFlag.PADDED.getValue()) > 0) {
94 padding = 16;
95 buffer[9] = (byte) (padding & 0xff);
96 frameLen++;
97 }
98 if (payload != null) {
99 payload.get(buffer, frameLen, payload.remaining());
100 frameLen += payloadLen;
101 }
102 for (int i = 0; i < padding; i++) {
103 buffer[frameLen++] = 0;
104 }
105 outStream.write(buffer, 0, frameLen);
106
107 metrics.incrementFramesTransferred();
108 metrics.incrementBytesTransferred(frameLen);
109 }
110
111 public H2TransportMetrics getMetrics() {
112 return metrics;
113 }
114
115 }