blob: b212f66a23543d780460d339523f8c894638a416 [file] [log] [blame]
Russ Cox3294cb52012-01-25 15:31:30 -05001// Copyright 2011 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package spdy
6
7import (
8 "encoding/binary"
9 "io"
10 "net/http"
11 "strings"
12)
13
14func (frame *SynStreamFrame) write(f *Framer) error {
15 return f.writeSynStreamFrame(frame)
16}
17
18func (frame *SynReplyFrame) write(f *Framer) error {
19 return f.writeSynReplyFrame(frame)
20}
21
22func (frame *RstStreamFrame) write(f *Framer) (err error) {
Jeff Hodges6fefb5e2012-10-30 16:12:50 +090023 if frame.StreamId == 0 {
24 return &Error{ZeroStreamId, 0}
25 }
Russ Cox3294cb52012-01-25 15:31:30 -050026 frame.CFHeader.version = Version
27 frame.CFHeader.frameType = TypeRstStream
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +090028 frame.CFHeader.Flags = 0
Russ Cox3294cb52012-01-25 15:31:30 -050029 frame.CFHeader.length = 8
30
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +090031 // Serialize frame to Writer.
Russ Cox3294cb52012-01-25 15:31:30 -050032 if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
33 return
34 }
35 if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
36 return
37 }
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +090038 if frame.Status == 0 {
39 return &Error{InvalidControlFrame, frame.StreamId}
40 }
Russ Cox3294cb52012-01-25 15:31:30 -050041 if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil {
42 return
43 }
44 return
45}
46
47func (frame *SettingsFrame) write(f *Framer) (err error) {
48 frame.CFHeader.version = Version
49 frame.CFHeader.frameType = TypeSettings
50 frame.CFHeader.length = uint32(len(frame.FlagIdValues)*8 + 4)
51
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +090052 // Serialize frame to Writer.
Russ Cox3294cb52012-01-25 15:31:30 -050053 if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
54 return
55 }
56 if err = binary.Write(f.w, binary.BigEndian, uint32(len(frame.FlagIdValues))); err != nil {
57 return
58 }
59 for _, flagIdValue := range frame.FlagIdValues {
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +090060 flagId := uint32(flagIdValue.Flag)<<24 | uint32(flagIdValue.Id)
Russ Cox3294cb52012-01-25 15:31:30 -050061 if err = binary.Write(f.w, binary.BigEndian, flagId); err != nil {
62 return
63 }
64 if err = binary.Write(f.w, binary.BigEndian, flagIdValue.Value); err != nil {
65 return
66 }
67 }
68 return
69}
70
Russ Cox3294cb52012-01-25 15:31:30 -050071func (frame *PingFrame) write(f *Framer) (err error) {
Jeff Hodges6fefb5e2012-10-30 16:12:50 +090072 if frame.Id == 0 {
73 return &Error{ZeroStreamId, 0}
74 }
Russ Cox3294cb52012-01-25 15:31:30 -050075 frame.CFHeader.version = Version
76 frame.CFHeader.frameType = TypePing
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +090077 frame.CFHeader.Flags = 0
Russ Cox3294cb52012-01-25 15:31:30 -050078 frame.CFHeader.length = 4
79
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +090080 // Serialize frame to Writer.
Russ Cox3294cb52012-01-25 15:31:30 -050081 if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
82 return
83 }
84 if err = binary.Write(f.w, binary.BigEndian, frame.Id); err != nil {
85 return
86 }
87 return
88}
89
90func (frame *GoAwayFrame) write(f *Framer) (err error) {
91 frame.CFHeader.version = Version
92 frame.CFHeader.frameType = TypeGoAway
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +090093 frame.CFHeader.Flags = 0
94 frame.CFHeader.length = 8
Russ Cox3294cb52012-01-25 15:31:30 -050095
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +090096 // Serialize frame to Writer.
Russ Cox3294cb52012-01-25 15:31:30 -050097 if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
98 return
99 }
100 if err = binary.Write(f.w, binary.BigEndian, frame.LastGoodStreamId); err != nil {
101 return
102 }
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900103 if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil {
104 return
105 }
Russ Cox3294cb52012-01-25 15:31:30 -0500106 return nil
107}
108
109func (frame *HeadersFrame) write(f *Framer) error {
110 return f.writeHeadersFrame(frame)
111}
112
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900113func (frame *WindowUpdateFrame) write(f *Framer) (err error) {
114 frame.CFHeader.version = Version
115 frame.CFHeader.frameType = TypeWindowUpdate
116 frame.CFHeader.Flags = 0
117 frame.CFHeader.length = 8
118
119 // Serialize frame to Writer.
120 if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
121 return
Jeff Hodges6fefb5e2012-10-30 16:12:50 +0900122 }
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900123 if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
124 return
125 }
126 if err = binary.Write(f.w, binary.BigEndian, frame.DeltaWindowSize); err != nil {
127 return
128 }
129 return nil
130}
131
132func (frame *DataFrame) write(f *Framer) error {
Russ Cox3294cb52012-01-25 15:31:30 -0500133 return f.writeDataFrame(frame)
134}
135
136// WriteFrame writes a frame.
137func (f *Framer) WriteFrame(frame Frame) error {
138 return frame.write(f)
139}
140
141func writeControlFrameHeader(w io.Writer, h ControlFrameHeader) error {
142 if err := binary.Write(w, binary.BigEndian, 0x8000|h.version); err != nil {
143 return err
144 }
145 if err := binary.Write(w, binary.BigEndian, h.frameType); err != nil {
146 return err
147 }
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900148 flagsAndLength := uint32(h.Flags)<<24 | h.length
Russ Cox3294cb52012-01-25 15:31:30 -0500149 if err := binary.Write(w, binary.BigEndian, flagsAndLength); err != nil {
150 return err
151 }
152 return nil
153}
154
155func writeHeaderValueBlock(w io.Writer, h http.Header) (n int, err error) {
156 n = 0
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900157 if err = binary.Write(w, binary.BigEndian, uint32(len(h))); err != nil {
Russ Cox3294cb52012-01-25 15:31:30 -0500158 return
159 }
160 n += 2
161 for name, values := range h {
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900162 if err = binary.Write(w, binary.BigEndian, uint32(len(name))); err != nil {
Russ Cox3294cb52012-01-25 15:31:30 -0500163 return
164 }
165 n += 2
166 name = strings.ToLower(name)
167 if _, err = io.WriteString(w, name); err != nil {
168 return
169 }
170 n += len(name)
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900171 v := strings.Join(values, headerValueSeparator)
172 if err = binary.Write(w, binary.BigEndian, uint32(len(v))); err != nil {
Russ Cox3294cb52012-01-25 15:31:30 -0500173 return
174 }
175 n += 2
176 if _, err = io.WriteString(w, v); err != nil {
177 return
178 }
179 n += len(v)
180 }
181 return
182}
183
184func (f *Framer) writeSynStreamFrame(frame *SynStreamFrame) (err error) {
Jeff Hodges6fefb5e2012-10-30 16:12:50 +0900185 if frame.StreamId == 0 {
186 return &Error{ZeroStreamId, 0}
187 }
Russ Cox3294cb52012-01-25 15:31:30 -0500188 // Marshal the headers.
189 var writer io.Writer = f.headerBuf
190 if !f.headerCompressionDisabled {
191 writer = f.headerCompressor
192 }
193 if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
194 return
195 }
196 if !f.headerCompressionDisabled {
197 f.headerCompressor.Flush()
198 }
199
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900200 // Set ControlFrameHeader.
Russ Cox3294cb52012-01-25 15:31:30 -0500201 frame.CFHeader.version = Version
202 frame.CFHeader.frameType = TypeSynStream
203 frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 10)
204
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900205 // Serialize frame to Writer.
Russ Cox3294cb52012-01-25 15:31:30 -0500206 if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
207 return err
208 }
209 if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
210 return err
211 }
212 if err = binary.Write(f.w, binary.BigEndian, frame.AssociatedToStreamId); err != nil {
213 return err
214 }
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900215 if err = binary.Write(f.w, binary.BigEndian, frame.Priority<<5); err != nil {
216 return err
217 }
218 if err = binary.Write(f.w, binary.BigEndian, frame.Slot); err != nil {
Russ Cox3294cb52012-01-25 15:31:30 -0500219 return err
220 }
221 if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
222 return err
223 }
224 f.headerBuf.Reset()
225 return nil
226}
227
228func (f *Framer) writeSynReplyFrame(frame *SynReplyFrame) (err error) {
Jeff Hodges6fefb5e2012-10-30 16:12:50 +0900229 if frame.StreamId == 0 {
230 return &Error{ZeroStreamId, 0}
231 }
Russ Cox3294cb52012-01-25 15:31:30 -0500232 // Marshal the headers.
233 var writer io.Writer = f.headerBuf
234 if !f.headerCompressionDisabled {
235 writer = f.headerCompressor
236 }
237 if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
238 return
239 }
240 if !f.headerCompressionDisabled {
241 f.headerCompressor.Flush()
242 }
243
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900244 // Set ControlFrameHeader.
Russ Cox3294cb52012-01-25 15:31:30 -0500245 frame.CFHeader.version = Version
246 frame.CFHeader.frameType = TypeSynReply
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900247 frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4)
Russ Cox3294cb52012-01-25 15:31:30 -0500248
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900249 // Serialize frame to Writer.
Russ Cox3294cb52012-01-25 15:31:30 -0500250 if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
251 return
252 }
253 if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
254 return
255 }
Russ Cox3294cb52012-01-25 15:31:30 -0500256 if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
257 return
258 }
259 f.headerBuf.Reset()
260 return
261}
262
263func (f *Framer) writeHeadersFrame(frame *HeadersFrame) (err error) {
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900264 if frame.StreamId == 0 {
265 return &Error{ZeroStreamId, 0}
266 }
Russ Cox3294cb52012-01-25 15:31:30 -0500267 // Marshal the headers.
268 var writer io.Writer = f.headerBuf
269 if !f.headerCompressionDisabled {
270 writer = f.headerCompressor
271 }
272 if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
273 return
274 }
275 if !f.headerCompressionDisabled {
276 f.headerCompressor.Flush()
277 }
278
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900279 // Set ControlFrameHeader.
Russ Cox3294cb52012-01-25 15:31:30 -0500280 frame.CFHeader.version = Version
281 frame.CFHeader.frameType = TypeHeaders
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900282 frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4)
Russ Cox3294cb52012-01-25 15:31:30 -0500283
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900284 // Serialize frame to Writer.
Russ Cox3294cb52012-01-25 15:31:30 -0500285 if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
286 return
287 }
288 if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
289 return
290 }
Russ Cox3294cb52012-01-25 15:31:30 -0500291 if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
292 return
293 }
294 f.headerBuf.Reset()
295 return
296}
297
298func (f *Framer) writeDataFrame(frame *DataFrame) (err error) {
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900299 if frame.StreamId == 0 {
300 return &Error{ZeroStreamId, 0}
301 }
Mikio Hara1f1a1ed2013-02-19 00:47:13 +0900302 if frame.StreamId&0x80000000 != 0 || len(frame.Data) > MaxDataLength {
Russ Cox3294cb52012-01-25 15:31:30 -0500303 return &Error{InvalidDataFrame, frame.StreamId}
304 }
305
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900306 // Serialize frame to Writer.
Russ Cox3294cb52012-01-25 15:31:30 -0500307 if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
308 return
309 }
Yusuke Kagiwada10d81ae2013-02-06 19:24:32 +0900310 flagsAndLength := uint32(frame.Flags)<<24 | uint32(len(frame.Data))
Russ Cox3294cb52012-01-25 15:31:30 -0500311 if err = binary.Write(f.w, binary.BigEndian, flagsAndLength); err != nil {
312 return
313 }
314 if _, err = f.w.Write(frame.Data); err != nil {
315 return
316 }
Russ Cox3294cb52012-01-25 15:31:30 -0500317 return nil
318}