1// 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) {
23	if frame.StreamId == 0 {
24		return &Error{ZeroStreamId, 0}
25	}
26	frame.CFHeader.version = Version
27	frame.CFHeader.frameType = TypeRstStream
28	frame.CFHeader.Flags = 0
29	frame.CFHeader.length = 8
30
31	// Serialize frame to Writer.
32	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	}
38	if frame.Status == 0 {
39		return &Error{InvalidControlFrame, frame.StreamId}
40	}
41	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
52	// Serialize frame to Writer.
53	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 {
60		flagId := uint32(flagIdValue.Flag)<<24 | uint32(flagIdValue.Id)
61		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
71func (frame *PingFrame) write(f *Framer) (err error) {
72	if frame.Id == 0 {
73		return &Error{ZeroStreamId, 0}
74	}
75	frame.CFHeader.version = Version
76	frame.CFHeader.frameType = TypePing
77	frame.CFHeader.Flags = 0
78	frame.CFHeader.length = 4
79
80	// Serialize frame to Writer.
81	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
93	frame.CFHeader.Flags = 0
94	frame.CFHeader.length = 8
95
96	// Serialize frame to Writer.
97	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	}
103	if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil {
104		return
105	}
106	return nil
107}
108
109func (frame *HeadersFrame) write(f *Framer) error {
110	return f.writeHeadersFrame(frame)
111}
112
113func (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
122	}
123	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 {
133	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	}
148	flagsAndLength := uint32(h.Flags)<<24 | h.length
149	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
157	if err = binary.Write(w, binary.BigEndian, uint32(len(h))); err != nil {
158		return
159	}
160	n += 2
161	for name, values := range h {
162		if err = binary.Write(w, binary.BigEndian, uint32(len(name))); err != nil {
163			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)
171		v := strings.Join(values, headerValueSeparator)
172		if err = binary.Write(w, binary.BigEndian, uint32(len(v))); err != nil {
173			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) {
185	if frame.StreamId == 0 {
186		return &Error{ZeroStreamId, 0}
187	}
188	// 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
200	// Set ControlFrameHeader.
201	frame.CFHeader.version = Version
202	frame.CFHeader.frameType = TypeSynStream
203	frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 10)
204
205	// Serialize frame to Writer.
206	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	}
215	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 {
219		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) {
229	if frame.StreamId == 0 {
230		return &Error{ZeroStreamId, 0}
231	}
232	// 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
244	// Set ControlFrameHeader.
245	frame.CFHeader.version = Version
246	frame.CFHeader.frameType = TypeSynReply
247	frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4)
248
249	// Serialize frame to Writer.
250	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	}
256	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) {
264	if frame.StreamId == 0 {
265		return &Error{ZeroStreamId, 0}
266	}
267	// 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
279	// Set ControlFrameHeader.
280	frame.CFHeader.version = Version
281	frame.CFHeader.frameType = TypeHeaders
282	frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4)
283
284	// Serialize frame to Writer.
285	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	}
291	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) {
299	if frame.StreamId == 0 {
300		return &Error{ZeroStreamId, 0}
301	}
302	if frame.StreamId&0x80000000 != 0 || len(frame.Data) > MaxDataLength {
303		return &Error{InvalidDataFrame, frame.StreamId}
304	}
305
306	// Serialize frame to Writer.
307	if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
308		return
309	}
310	flagsAndLength := uint32(frame.Flags)<<24 | uint32(len(frame.Data))
311	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	}
317	return nil
318}
319