1/*
2   Copyright 2014-2021 Docker Inc.
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   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,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15*/
16
17// Copyright 2011 The Go Authors. All rights reserved.
18// Use of this source code is governed by a BSD-style
19// license that can be found in the LICENSE file.
20
21package spdy
22
23import (
24	"encoding/binary"
25	"io"
26	"net/http"
27	"strings"
28)
29
30func (frame *SynStreamFrame) write(f *Framer) error {
31	return f.writeSynStreamFrame(frame)
32}
33
34func (frame *SynReplyFrame) write(f *Framer) error {
35	return f.writeSynReplyFrame(frame)
36}
37
38func (frame *RstStreamFrame) write(f *Framer) (err error) {
39	if frame.StreamId == 0 {
40		return &Error{ZeroStreamId, 0}
41	}
42	frame.CFHeader.version = Version
43	frame.CFHeader.frameType = TypeRstStream
44	frame.CFHeader.Flags = 0
45	frame.CFHeader.length = 8
46
47	// Serialize frame to Writer.
48	if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
49		return
50	}
51	if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
52		return
53	}
54	if frame.Status == 0 {
55		return &Error{InvalidControlFrame, frame.StreamId}
56	}
57	if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil {
58		return
59	}
60	return
61}
62
63func (frame *SettingsFrame) write(f *Framer) (err error) {
64	frame.CFHeader.version = Version
65	frame.CFHeader.frameType = TypeSettings
66	frame.CFHeader.length = uint32(len(frame.FlagIdValues)*8 + 4)
67
68	// Serialize frame to Writer.
69	if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
70		return
71	}
72	if err = binary.Write(f.w, binary.BigEndian, uint32(len(frame.FlagIdValues))); err != nil {
73		return
74	}
75	for _, flagIdValue := range frame.FlagIdValues {
76		flagId := uint32(flagIdValue.Flag)<<24 | uint32(flagIdValue.Id)
77		if err = binary.Write(f.w, binary.BigEndian, flagId); err != nil {
78			return
79		}
80		if err = binary.Write(f.w, binary.BigEndian, flagIdValue.Value); err != nil {
81			return
82		}
83	}
84	return
85}
86
87func (frame *PingFrame) write(f *Framer) (err error) {
88	if frame.Id == 0 {
89		return &Error{ZeroStreamId, 0}
90	}
91	frame.CFHeader.version = Version
92	frame.CFHeader.frameType = TypePing
93	frame.CFHeader.Flags = 0
94	frame.CFHeader.length = 4
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.Id); err != nil {
101		return
102	}
103	return
104}
105
106func (frame *GoAwayFrame) write(f *Framer) (err error) {
107	frame.CFHeader.version = Version
108	frame.CFHeader.frameType = TypeGoAway
109	frame.CFHeader.Flags = 0
110	frame.CFHeader.length = 8
111
112	// Serialize frame to Writer.
113	if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
114		return
115	}
116	if err = binary.Write(f.w, binary.BigEndian, frame.LastGoodStreamId); err != nil {
117		return
118	}
119	if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil {
120		return
121	}
122	return nil
123}
124
125func (frame *HeadersFrame) write(f *Framer) error {
126	return f.writeHeadersFrame(frame)
127}
128
129func (frame *WindowUpdateFrame) write(f *Framer) (err error) {
130	frame.CFHeader.version = Version
131	frame.CFHeader.frameType = TypeWindowUpdate
132	frame.CFHeader.Flags = 0
133	frame.CFHeader.length = 8
134
135	// Serialize frame to Writer.
136	if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
137		return
138	}
139	if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
140		return
141	}
142	if err = binary.Write(f.w, binary.BigEndian, frame.DeltaWindowSize); err != nil {
143		return
144	}
145	return nil
146}
147
148func (frame *DataFrame) write(f *Framer) error {
149	return f.writeDataFrame(frame)
150}
151
152// WriteFrame writes a frame.
153func (f *Framer) WriteFrame(frame Frame) error {
154	return frame.write(f)
155}
156
157func writeControlFrameHeader(w io.Writer, h ControlFrameHeader) error {
158	if err := binary.Write(w, binary.BigEndian, 0x8000|h.version); err != nil {
159		return err
160	}
161	if err := binary.Write(w, binary.BigEndian, h.frameType); err != nil {
162		return err
163	}
164	flagsAndLength := uint32(h.Flags)<<24 | h.length
165	if err := binary.Write(w, binary.BigEndian, flagsAndLength); err != nil {
166		return err
167	}
168	return nil
169}
170
171func writeHeaderValueBlock(w io.Writer, h http.Header) (n int, err error) {
172	n = 0
173	if err = binary.Write(w, binary.BigEndian, uint32(len(h))); err != nil {
174		return
175	}
176	n += 2
177	for name, values := range h {
178		if err = binary.Write(w, binary.BigEndian, uint32(len(name))); err != nil {
179			return
180		}
181		n += 2
182		name = strings.ToLower(name)
183		if _, err = io.WriteString(w, name); err != nil {
184			return
185		}
186		n += len(name)
187		v := strings.Join(values, headerValueSeparator)
188		if err = binary.Write(w, binary.BigEndian, uint32(len(v))); err != nil {
189			return
190		}
191		n += 2
192		if _, err = io.WriteString(w, v); err != nil {
193			return
194		}
195		n += len(v)
196	}
197	return
198}
199
200func (f *Framer) writeSynStreamFrame(frame *SynStreamFrame) (err error) {
201	if frame.StreamId == 0 {
202		return &Error{ZeroStreamId, 0}
203	}
204	// Marshal the headers.
205	var writer io.Writer = f.headerBuf
206	if !f.headerCompressionDisabled {
207		writer = f.headerCompressor
208	}
209	if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
210		return
211	}
212	if !f.headerCompressionDisabled {
213		f.headerCompressor.Flush()
214	}
215
216	// Set ControlFrameHeader.
217	frame.CFHeader.version = Version
218	frame.CFHeader.frameType = TypeSynStream
219	frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 10)
220
221	// Serialize frame to Writer.
222	if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
223		return err
224	}
225	if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
226		return err
227	}
228	if err = binary.Write(f.w, binary.BigEndian, frame.AssociatedToStreamId); err != nil {
229		return err
230	}
231	if err = binary.Write(f.w, binary.BigEndian, frame.Priority<<5); err != nil {
232		return err
233	}
234	if err = binary.Write(f.w, binary.BigEndian, frame.Slot); err != nil {
235		return err
236	}
237	if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
238		return err
239	}
240	f.headerBuf.Reset()
241	return nil
242}
243
244func (f *Framer) writeSynReplyFrame(frame *SynReplyFrame) (err error) {
245	if frame.StreamId == 0 {
246		return &Error{ZeroStreamId, 0}
247	}
248	// Marshal the headers.
249	var writer io.Writer = f.headerBuf
250	if !f.headerCompressionDisabled {
251		writer = f.headerCompressor
252	}
253	if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
254		return
255	}
256	if !f.headerCompressionDisabled {
257		f.headerCompressor.Flush()
258	}
259
260	// Set ControlFrameHeader.
261	frame.CFHeader.version = Version
262	frame.CFHeader.frameType = TypeSynReply
263	frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4)
264
265	// Serialize frame to Writer.
266	if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
267		return
268	}
269	if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
270		return
271	}
272	if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
273		return
274	}
275	f.headerBuf.Reset()
276	return
277}
278
279func (f *Framer) writeHeadersFrame(frame *HeadersFrame) (err error) {
280	if frame.StreamId == 0 {
281		return &Error{ZeroStreamId, 0}
282	}
283	// Marshal the headers.
284	var writer io.Writer = f.headerBuf
285	if !f.headerCompressionDisabled {
286		writer = f.headerCompressor
287	}
288	if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
289		return
290	}
291	if !f.headerCompressionDisabled {
292		f.headerCompressor.Flush()
293	}
294
295	// Set ControlFrameHeader.
296	frame.CFHeader.version = Version
297	frame.CFHeader.frameType = TypeHeaders
298	frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4)
299
300	// Serialize frame to Writer.
301	if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
302		return
303	}
304	if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
305		return
306	}
307	if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
308		return
309	}
310	f.headerBuf.Reset()
311	return
312}
313
314func (f *Framer) writeDataFrame(frame *DataFrame) (err error) {
315	if frame.StreamId == 0 {
316		return &Error{ZeroStreamId, 0}
317	}
318	if frame.StreamId&0x80000000 != 0 || len(frame.Data) > MaxDataLength {
319		return &Error{InvalidDataFrame, frame.StreamId}
320	}
321
322	// Serialize frame to Writer.
323	if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
324		return
325	}
326	flagsAndLength := uint32(frame.Flags)<<24 | uint32(len(frame.Data))
327	if err = binary.Write(f.w, binary.BigEndian, flagsAndLength); err != nil {
328		return
329	}
330	if _, err = f.w.Write(frame.Data); err != nil {
331		return
332	}
333	return nil
334}
335