1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package io.netty.handler.codec.spdy;
17  
18  import io.netty.buffer.ByteBuf;
19  import io.netty.buffer.ByteBufAllocator;
20  
21  import java.nio.ByteOrder;
22  import java.util.Set;
23  
24  import static io.netty.handler.codec.spdy.SpdyCodecUtil.*;
25  
26  
27  
28  
29  public class SpdyFrameEncoder {
30  
31      private final int version;
32  
33      
34  
35  
36      public SpdyFrameEncoder(SpdyVersion spdyVersion) {
37          if (spdyVersion == null) {
38              throw new NullPointerException("spdyVersion");
39          }
40          version = spdyVersion.getVersion();
41      }
42  
43      private void writeControlFrameHeader(ByteBuf buffer, int type, byte flags, int length) {
44          buffer.writeShort(version | 0x8000);
45          buffer.writeShort(type);
46          buffer.writeByte(flags);
47          buffer.writeMedium(length);
48      }
49  
50      public ByteBuf encodeDataFrame(ByteBufAllocator allocator, int streamId, boolean last, ByteBuf data) {
51          byte flags = last ? SPDY_DATA_FLAG_FIN : 0;
52          int length = data.readableBytes();
53          ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
54          frame.writeInt(streamId & 0x7FFFFFFF);
55          frame.writeByte(flags);
56          frame.writeMedium(length);
57          frame.writeBytes(data, data.readerIndex(), length);
58          return frame;
59      }
60  
61      public ByteBuf encodeSynStreamFrame(ByteBufAllocator allocator,  int streamId, int associatedToStreamId,
62              byte priority, boolean last, boolean unidirectional, ByteBuf headerBlock) {
63          int headerBlockLength = headerBlock.readableBytes();
64          byte flags = last ? SPDY_FLAG_FIN : 0;
65          if (unidirectional) {
66              flags |= SPDY_FLAG_UNIDIRECTIONAL;
67          }
68          int length = 10 + headerBlockLength;
69          ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
70          writeControlFrameHeader(frame, SPDY_SYN_STREAM_FRAME, flags, length);
71          frame.writeInt(streamId);
72          frame.writeInt(associatedToStreamId);
73          frame.writeShort((priority & 0xFF) << 13);
74          frame.writeBytes(headerBlock, headerBlock.readerIndex(), headerBlockLength);
75          return frame;
76      }
77  
78      public ByteBuf encodeSynReplyFrame(ByteBufAllocator allocator, int streamId, boolean last, ByteBuf headerBlock) {
79          int headerBlockLength = headerBlock.readableBytes();
80          byte flags = last ? SPDY_FLAG_FIN : 0;
81          int length = 4 + headerBlockLength;
82          ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
83          writeControlFrameHeader(frame, SPDY_SYN_REPLY_FRAME, flags, length);
84          frame.writeInt(streamId);
85          frame.writeBytes(headerBlock, headerBlock.readerIndex(), headerBlockLength);
86          return frame;
87      }
88  
89      public ByteBuf encodeRstStreamFrame(ByteBufAllocator allocator, int streamId, int statusCode) {
90          byte flags = 0;
91          int length = 8;
92          ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
93          writeControlFrameHeader(frame, SPDY_RST_STREAM_FRAME, flags, length);
94          frame.writeInt(streamId);
95          frame.writeInt(statusCode);
96          return frame;
97      }
98  
99      public ByteBuf encodeSettingsFrame(ByteBufAllocator allocator, SpdySettingsFrame spdySettingsFrame) {
100         Set<Integer> ids = spdySettingsFrame.ids();
101         int numSettings = ids.size();
102 
103         byte flags = spdySettingsFrame.clearPreviouslyPersistedSettings() ?
104                 SPDY_SETTINGS_CLEAR : 0;
105         int length = 4 + 8 * numSettings;
106         ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
107         writeControlFrameHeader(frame, SPDY_SETTINGS_FRAME, flags, length);
108         frame.writeInt(numSettings);
109         for (Integer id : ids) {
110             flags = 0;
111             if (spdySettingsFrame.isPersistValue(id)) {
112                 flags |= SPDY_SETTINGS_PERSIST_VALUE;
113             }
114             if (spdySettingsFrame.isPersisted(id)) {
115                 flags |= SPDY_SETTINGS_PERSISTED;
116             }
117             frame.writeByte(flags);
118             frame.writeMedium(id);
119             frame.writeInt(spdySettingsFrame.getValue(id));
120         }
121         return frame;
122     }
123 
124     public ByteBuf encodePingFrame(ByteBufAllocator allocator, int id) {
125         byte flags = 0;
126         int length = 4;
127         ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
128         writeControlFrameHeader(frame, SPDY_PING_FRAME, flags, length);
129         frame.writeInt(id);
130         return frame;
131     }
132 
133     public ByteBuf encodeGoAwayFrame(ByteBufAllocator allocator, int lastGoodStreamId, int statusCode) {
134         byte flags = 0;
135         int length = 8;
136         ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
137         writeControlFrameHeader(frame, SPDY_GOAWAY_FRAME, flags, length);
138         frame.writeInt(lastGoodStreamId);
139         frame.writeInt(statusCode);
140         return frame;
141     }
142 
143     public ByteBuf encodeHeadersFrame(ByteBufAllocator allocator, int streamId, boolean last, ByteBuf headerBlock) {
144         int headerBlockLength = headerBlock.readableBytes();
145         byte flags = last ? SPDY_FLAG_FIN : 0;
146         int length = 4 + headerBlockLength;
147         ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
148         writeControlFrameHeader(frame, SPDY_HEADERS_FRAME, flags, length);
149         frame.writeInt(streamId);
150         frame.writeBytes(headerBlock, headerBlock.readerIndex(), headerBlockLength);
151         return frame;
152     }
153 
154     public ByteBuf encodeWindowUpdateFrame(ByteBufAllocator allocator, int streamId, int deltaWindowSize) {
155         byte flags = 0;
156         int length = 8;
157         ByteBuf frame = allocator.ioBuffer(SPDY_HEADER_SIZE + length).order(ByteOrder.BIG_ENDIAN);
158         writeControlFrameHeader(frame, SPDY_WINDOW_UPDATE_FRAME, flags, length);
159         frame.writeInt(streamId);
160         frame.writeInt(deltaWindowSize);
161         return frame;
162     }
163 }