View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package org.jboss.netty.handler.codec.spdy;
17  
18  import static org.jboss.netty.handler.codec.spdy.SpdyCodecUtil.*;
19  
20  import org.jboss.netty.buffer.ChannelBuffer;
21  import org.jboss.netty.buffer.ChannelBuffers;
22  
23  import java.nio.ByteOrder;
24  import java.util.Set;
25  
26  /**
27   * Encodes a SPDY Frame into a {@link ChannelBuffer}.
28   */
29  public class SpdyFrameEncoder {
30  
31      private final int version;
32  
33      /**
34       * Creates a new instance with the specified {@code spdyVersion}.
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(ChannelBuffer 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 ChannelBuffer encodeDataFrame(int streamId, boolean last, ChannelBuffer data) {
51          byte flags = last ? SPDY_DATA_FLAG_FIN : 0;
52          ChannelBuffer header = ChannelBuffers.buffer(ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE);
53          header.writeInt(streamId & 0x7FFFFFFF);
54          header.writeByte(flags);
55          header.writeMedium(data.readableBytes());
56          return ChannelBuffers.wrappedBuffer(header, data);
57      }
58  
59      public ChannelBuffer encodeSynStreamFrame(
60              int streamId, int associatedToStreamId, byte priority, boolean last, boolean unidirectional,
61              ChannelBuffer headerBlock) {
62          byte flags = last ? SPDY_FLAG_FIN : 0;
63          if (unidirectional) {
64              flags |= SPDY_FLAG_UNIDIRECTIONAL;
65          }
66          int length = 10 + headerBlock.readableBytes();
67          ChannelBuffer frame = ChannelBuffers.buffer(ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + 10);
68          writeControlFrameHeader(frame, SPDY_SYN_STREAM_FRAME, flags, length);
69          frame.writeInt(streamId);
70          frame.writeInt(associatedToStreamId);
71          frame.writeShort((priority & 0xFF) << 13);
72          return ChannelBuffers.wrappedBuffer(frame, headerBlock);
73      }
74  
75      public ChannelBuffer encodeSynReplyFrame(int streamId, boolean last, ChannelBuffer headerBlock) {
76          byte flags = last ? SPDY_FLAG_FIN : 0;
77          int length = 4 + headerBlock.readableBytes();
78          ChannelBuffer frame = ChannelBuffers.buffer(ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + 4);
79          writeControlFrameHeader(frame, SPDY_SYN_REPLY_FRAME, flags, length);
80          frame.writeInt(streamId);
81          return ChannelBuffers.wrappedBuffer(frame, headerBlock);
82      }
83  
84      public ChannelBuffer encodeRstStreamFrame(int streamId, int statusCode) {
85          byte flags = 0;
86          int length = 8;
87          ChannelBuffer frame = ChannelBuffers.buffer(ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + length);
88          writeControlFrameHeader(frame, SPDY_RST_STREAM_FRAME, flags, length);
89          frame.writeInt(streamId);
90          frame.writeInt(statusCode);
91          return frame;
92      }
93  
94      public ChannelBuffer encodeSettingsFrame(SpdySettingsFrame spdySettingsFrame) {
95          Set<Integer> ids = spdySettingsFrame.getIds();
96          int numSettings = ids.size();
97  
98          byte flags = spdySettingsFrame.clearPreviouslyPersistedSettings() ?
99              SPDY_SETTINGS_CLEAR : 0;
100         int length = 4 + 8 * numSettings;
101         ChannelBuffer frame = ChannelBuffers.buffer(ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + length);
102         writeControlFrameHeader(frame, SPDY_SETTINGS_FRAME, flags, length);
103         frame.writeInt(numSettings);
104         for (Integer id : ids) {
105             flags = 0;
106             if (spdySettingsFrame.isPersistValue(id)) {
107               flags |= SPDY_SETTINGS_PERSIST_VALUE;
108             }
109             if (spdySettingsFrame.isPersisted(id)) {
110               flags |= SPDY_SETTINGS_PERSISTED;
111             }
112             frame.writeByte(flags);
113             frame.writeMedium(id);
114             frame.writeInt(spdySettingsFrame.getValue(id));
115         }
116         return frame;
117     }
118 
119     public ChannelBuffer encodePingFrame(int id) {
120         byte flags = 0;
121         int length = 4;
122         ChannelBuffer frame = ChannelBuffers.buffer(ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + length);
123         writeControlFrameHeader(frame, SPDY_PING_FRAME, flags, length);
124         frame.writeInt(id);
125         return frame;
126     }
127 
128     public ChannelBuffer encodeGoAwayFrame(int lastGoodStreamId, int statusCode) {
129         byte flags = 0;
130         int length = 8;
131         ChannelBuffer frame = ChannelBuffers.buffer(ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + length);
132         writeControlFrameHeader(frame, SPDY_GOAWAY_FRAME, flags, length);
133         frame.writeInt(lastGoodStreamId);
134         frame.writeInt(statusCode);
135         return frame;
136     }
137 
138     public ChannelBuffer encodeHeadersFrame(int streamId, boolean last, ChannelBuffer headerBlock) {
139         byte flags = last ? SPDY_FLAG_FIN : 0;
140         int length = 4 + headerBlock.readableBytes();
141         ChannelBuffer frame = ChannelBuffers.buffer(ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + 4);
142         writeControlFrameHeader(frame, SPDY_HEADERS_FRAME, flags, length);
143         frame.writeInt(streamId);
144         return ChannelBuffers.wrappedBuffer(frame, headerBlock);
145     }
146 
147     public ChannelBuffer encodeWindowUpdateFrame(int streamId, int deltaWindowSize) {
148         byte flags = 0;
149         int length = 8;
150         ChannelBuffer frame = ChannelBuffers.buffer(ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + length);
151         writeControlFrameHeader(frame, SPDY_WINDOW_UPDATE_FRAME, flags, length);
152         frame.writeInt(streamId);
153         frame.writeInt(deltaWindowSize);
154         return frame;
155     }
156 }