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