Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 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 | |
| 5 | package spdy |
| 6 | |
| 7 | import ( |
| 8 | "compress/zlib" |
| 9 | "encoding/binary" |
| 10 | "io" |
| 11 | "net/http" |
| 12 | "strings" |
| 13 | ) |
| 14 | |
| 15 | func (frame *SynStreamFrame) read(h ControlFrameHeader, f *Framer) error { |
| 16 | return f.readSynStreamFrame(h, frame) |
| 17 | } |
| 18 | |
| 19 | func (frame *SynReplyFrame) read(h ControlFrameHeader, f *Framer) error { |
| 20 | return f.readSynReplyFrame(h, frame) |
| 21 | } |
| 22 | |
| 23 | func (frame *RstStreamFrame) read(h ControlFrameHeader, f *Framer) error { |
| 24 | frame.CFHeader = h |
| 25 | if err := binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { |
| 26 | return err |
| 27 | } |
| 28 | if err := binary.Read(f.r, binary.BigEndian, &frame.Status); err != nil { |
| 29 | return err |
| 30 | } |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 31 | if frame.Status == 0 { |
| 32 | return &Error{InvalidControlFrame, frame.StreamId} |
| 33 | } |
Jeff Hodges | 6fefb5e | 2012-10-30 16:12:50 +0900 | [diff] [blame] | 34 | if frame.StreamId == 0 { |
| 35 | return &Error{ZeroStreamId, 0} |
| 36 | } |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 37 | return nil |
| 38 | } |
| 39 | |
| 40 | func (frame *SettingsFrame) read(h ControlFrameHeader, f *Framer) error { |
| 41 | frame.CFHeader = h |
| 42 | var numSettings uint32 |
| 43 | if err := binary.Read(f.r, binary.BigEndian, &numSettings); err != nil { |
| 44 | return err |
| 45 | } |
| 46 | frame.FlagIdValues = make([]SettingsFlagIdValue, numSettings) |
| 47 | for i := uint32(0); i < numSettings; i++ { |
| 48 | if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Id); err != nil { |
| 49 | return err |
| 50 | } |
| 51 | frame.FlagIdValues[i].Flag = SettingsFlag((frame.FlagIdValues[i].Id & 0xff000000) >> 24) |
| 52 | frame.FlagIdValues[i].Id &= 0xffffff |
| 53 | if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Value); err != nil { |
| 54 | return err |
| 55 | } |
| 56 | } |
| 57 | return nil |
| 58 | } |
| 59 | |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 60 | func (frame *PingFrame) read(h ControlFrameHeader, f *Framer) error { |
| 61 | frame.CFHeader = h |
| 62 | if err := binary.Read(f.r, binary.BigEndian, &frame.Id); err != nil { |
| 63 | return err |
| 64 | } |
Jeff Hodges | 6fefb5e | 2012-10-30 16:12:50 +0900 | [diff] [blame] | 65 | if frame.Id == 0 { |
| 66 | return &Error{ZeroStreamId, 0} |
| 67 | } |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 68 | if frame.CFHeader.Flags != 0 { |
| 69 | return &Error{InvalidControlFrame, StreamId(frame.Id)} |
| 70 | } |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 71 | return nil |
| 72 | } |
| 73 | |
| 74 | func (frame *GoAwayFrame) read(h ControlFrameHeader, f *Framer) error { |
| 75 | frame.CFHeader = h |
| 76 | if err := binary.Read(f.r, binary.BigEndian, &frame.LastGoodStreamId); err != nil { |
| 77 | return err |
| 78 | } |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 79 | if frame.CFHeader.Flags != 0 { |
| 80 | return &Error{InvalidControlFrame, frame.LastGoodStreamId} |
| 81 | } |
| 82 | if frame.CFHeader.length != 8 { |
| 83 | return &Error{InvalidControlFrame, frame.LastGoodStreamId} |
| 84 | } |
| 85 | if err := binary.Read(f.r, binary.BigEndian, &frame.Status); err != nil { |
| 86 | return err |
| 87 | } |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 88 | return nil |
| 89 | } |
| 90 | |
| 91 | func (frame *HeadersFrame) read(h ControlFrameHeader, f *Framer) error { |
| 92 | return f.readHeadersFrame(h, frame) |
| 93 | } |
| 94 | |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 95 | func (frame *WindowUpdateFrame) read(h ControlFrameHeader, f *Framer) error { |
| 96 | frame.CFHeader = h |
| 97 | if err := binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { |
| 98 | return err |
| 99 | } |
| 100 | if frame.CFHeader.Flags != 0 { |
| 101 | return &Error{InvalidControlFrame, frame.StreamId} |
| 102 | } |
| 103 | if frame.CFHeader.length != 8 { |
| 104 | return &Error{InvalidControlFrame, frame.StreamId} |
| 105 | } |
| 106 | if err := binary.Read(f.r, binary.BigEndian, &frame.DeltaWindowSize); err != nil { |
| 107 | return err |
| 108 | } |
| 109 | return nil |
| 110 | } |
| 111 | |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 112 | func newControlFrame(frameType ControlFrameType) (controlFrame, error) { |
| 113 | ctor, ok := cframeCtor[frameType] |
| 114 | if !ok { |
| 115 | return nil, &Error{Err: InvalidControlFrame} |
| 116 | } |
| 117 | return ctor(), nil |
| 118 | } |
| 119 | |
| 120 | var cframeCtor = map[ControlFrameType]func() controlFrame{ |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 121 | TypeSynStream: func() controlFrame { return new(SynStreamFrame) }, |
| 122 | TypeSynReply: func() controlFrame { return new(SynReplyFrame) }, |
| 123 | TypeRstStream: func() controlFrame { return new(RstStreamFrame) }, |
| 124 | TypeSettings: func() controlFrame { return new(SettingsFrame) }, |
| 125 | TypePing: func() controlFrame { return new(PingFrame) }, |
| 126 | TypeGoAway: func() controlFrame { return new(GoAwayFrame) }, |
| 127 | TypeHeaders: func() controlFrame { return new(HeadersFrame) }, |
| 128 | TypeWindowUpdate: func() controlFrame { return new(WindowUpdateFrame) }, |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 129 | } |
| 130 | |
| 131 | func (f *Framer) uncorkHeaderDecompressor(payloadSize int64) error { |
| 132 | if f.headerDecompressor != nil { |
| 133 | f.headerReader.N = payloadSize |
| 134 | return nil |
| 135 | } |
| 136 | f.headerReader = io.LimitedReader{R: f.r, N: payloadSize} |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 137 | decompressor, err := zlib.NewReaderDict(&f.headerReader, []byte(headerDictionary)) |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 138 | if err != nil { |
| 139 | return err |
| 140 | } |
| 141 | f.headerDecompressor = decompressor |
| 142 | return nil |
| 143 | } |
| 144 | |
| 145 | // ReadFrame reads SPDY encoded data and returns a decompressed Frame. |
| 146 | func (f *Framer) ReadFrame() (Frame, error) { |
| 147 | var firstWord uint32 |
| 148 | if err := binary.Read(f.r, binary.BigEndian, &firstWord); err != nil { |
| 149 | return nil, err |
| 150 | } |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 151 | if firstWord&0x80000000 != 0 { |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 152 | frameType := ControlFrameType(firstWord & 0xffff) |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 153 | version := uint16(firstWord >> 16 & 0x7fff) |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 154 | return f.parseControlFrame(version, frameType) |
| 155 | } |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 156 | return f.parseDataFrame(StreamId(firstWord & 0x7fffffff)) |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 157 | } |
| 158 | |
| 159 | func (f *Framer) parseControlFrame(version uint16, frameType ControlFrameType) (Frame, error) { |
| 160 | var length uint32 |
| 161 | if err := binary.Read(f.r, binary.BigEndian, &length); err != nil { |
| 162 | return nil, err |
| 163 | } |
| 164 | flags := ControlFlags((length & 0xff000000) >> 24) |
| 165 | length &= 0xffffff |
| 166 | header := ControlFrameHeader{version, frameType, flags, length} |
| 167 | cframe, err := newControlFrame(frameType) |
| 168 | if err != nil { |
| 169 | return nil, err |
| 170 | } |
| 171 | if err = cframe.read(header, f); err != nil { |
| 172 | return nil, err |
| 173 | } |
| 174 | return cframe, nil |
| 175 | } |
| 176 | |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 177 | func parseHeaderValueBlock(r io.Reader, streamId StreamId) (http.Header, error) { |
| 178 | var numHeaders uint32 |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 179 | if err := binary.Read(r, binary.BigEndian, &numHeaders); err != nil { |
| 180 | return nil, err |
| 181 | } |
| 182 | var e error |
| 183 | h := make(http.Header, int(numHeaders)) |
| 184 | for i := 0; i < int(numHeaders); i++ { |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 185 | var length uint32 |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 186 | if err := binary.Read(r, binary.BigEndian, &length); err != nil { |
| 187 | return nil, err |
| 188 | } |
| 189 | nameBytes := make([]byte, length) |
| 190 | if _, err := io.ReadFull(r, nameBytes); err != nil { |
| 191 | return nil, err |
| 192 | } |
| 193 | name := string(nameBytes) |
| 194 | if name != strings.ToLower(name) { |
| 195 | e = &Error{UnlowercasedHeaderName, streamId} |
| 196 | name = strings.ToLower(name) |
| 197 | } |
| 198 | if h[name] != nil { |
| 199 | e = &Error{DuplicateHeaders, streamId} |
| 200 | } |
| 201 | if err := binary.Read(r, binary.BigEndian, &length); err != nil { |
| 202 | return nil, err |
| 203 | } |
| 204 | value := make([]byte, length) |
| 205 | if _, err := io.ReadFull(r, value); err != nil { |
| 206 | return nil, err |
| 207 | } |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 208 | valueList := strings.Split(string(value), headerValueSeparator) |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 209 | for _, v := range valueList { |
| 210 | h.Add(name, v) |
| 211 | } |
| 212 | } |
| 213 | if e != nil { |
| 214 | return h, e |
| 215 | } |
| 216 | return h, nil |
| 217 | } |
| 218 | |
| 219 | func (f *Framer) readSynStreamFrame(h ControlFrameHeader, frame *SynStreamFrame) error { |
| 220 | frame.CFHeader = h |
| 221 | var err error |
| 222 | if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { |
| 223 | return err |
| 224 | } |
| 225 | if err = binary.Read(f.r, binary.BigEndian, &frame.AssociatedToStreamId); err != nil { |
| 226 | return err |
| 227 | } |
| 228 | if err = binary.Read(f.r, binary.BigEndian, &frame.Priority); err != nil { |
| 229 | return err |
| 230 | } |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 231 | frame.Priority >>= 5 |
| 232 | if err = binary.Read(f.r, binary.BigEndian, &frame.Slot); err != nil { |
| 233 | return err |
| 234 | } |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 235 | reader := f.r |
| 236 | if !f.headerCompressionDisabled { |
Jeff Hodges | 06fe5ee | 2012-10-29 10:23:10 -0400 | [diff] [blame] | 237 | err := f.uncorkHeaderDecompressor(int64(h.length - 10)) |
| 238 | if err != nil { |
| 239 | return err |
| 240 | } |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 241 | reader = f.headerDecompressor |
| 242 | } |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 243 | frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId) |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 244 | if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) { |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 245 | err = &Error{WrongCompressedPayloadSize, 0} |
| 246 | } |
| 247 | if err != nil { |
| 248 | return err |
| 249 | } |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 250 | for h := range frame.Headers { |
| 251 | if invalidReqHeaders[h] { |
| 252 | return &Error{InvalidHeaderPresent, frame.StreamId} |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 253 | } |
| 254 | } |
Jeff Hodges | 6fefb5e | 2012-10-30 16:12:50 +0900 | [diff] [blame] | 255 | if frame.StreamId == 0 { |
| 256 | return &Error{ZeroStreamId, 0} |
| 257 | } |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 258 | return nil |
| 259 | } |
| 260 | |
| 261 | func (f *Framer) readSynReplyFrame(h ControlFrameHeader, frame *SynReplyFrame) error { |
| 262 | frame.CFHeader = h |
| 263 | var err error |
| 264 | if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { |
| 265 | return err |
| 266 | } |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 267 | reader := f.r |
| 268 | if !f.headerCompressionDisabled { |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 269 | err := f.uncorkHeaderDecompressor(int64(h.length - 4)) |
Jeff Hodges | 06fe5ee | 2012-10-29 10:23:10 -0400 | [diff] [blame] | 270 | if err != nil { |
| 271 | return err |
| 272 | } |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 273 | reader = f.headerDecompressor |
| 274 | } |
| 275 | frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId) |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 276 | if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) { |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 277 | err = &Error{WrongCompressedPayloadSize, 0} |
| 278 | } |
| 279 | if err != nil { |
| 280 | return err |
| 281 | } |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 282 | for h := range frame.Headers { |
| 283 | if invalidRespHeaders[h] { |
| 284 | return &Error{InvalidHeaderPresent, frame.StreamId} |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 285 | } |
| 286 | } |
Jeff Hodges | 6fefb5e | 2012-10-30 16:12:50 +0900 | [diff] [blame] | 287 | if frame.StreamId == 0 { |
| 288 | return &Error{ZeroStreamId, 0} |
| 289 | } |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 290 | return nil |
| 291 | } |
| 292 | |
| 293 | func (f *Framer) readHeadersFrame(h ControlFrameHeader, frame *HeadersFrame) error { |
| 294 | frame.CFHeader = h |
| 295 | var err error |
| 296 | if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { |
| 297 | return err |
| 298 | } |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 299 | reader := f.r |
| 300 | if !f.headerCompressionDisabled { |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 301 | err := f.uncorkHeaderDecompressor(int64(h.length - 4)) |
Jeff Hodges | 06fe5ee | 2012-10-29 10:23:10 -0400 | [diff] [blame] | 302 | if err != nil { |
| 303 | return err |
| 304 | } |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 305 | reader = f.headerDecompressor |
| 306 | } |
| 307 | frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId) |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 308 | if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) { |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 309 | err = &Error{WrongCompressedPayloadSize, 0} |
| 310 | } |
| 311 | if err != nil { |
| 312 | return err |
| 313 | } |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 314 | var invalidHeaders map[string]bool |
| 315 | if frame.StreamId%2 == 0 { |
| 316 | invalidHeaders = invalidReqHeaders |
| 317 | } else { |
| 318 | invalidHeaders = invalidRespHeaders |
| 319 | } |
| 320 | for h := range frame.Headers { |
| 321 | if invalidHeaders[h] { |
| 322 | return &Error{InvalidHeaderPresent, frame.StreamId} |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 323 | } |
| 324 | } |
Jeff Hodges | 6fefb5e | 2012-10-30 16:12:50 +0900 | [diff] [blame] | 325 | if frame.StreamId == 0 { |
| 326 | return &Error{ZeroStreamId, 0} |
| 327 | } |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 328 | return nil |
| 329 | } |
| 330 | |
Yusuke Kagiwada | 10d81ae | 2013-02-06 19:24:32 +0900 | [diff] [blame] | 331 | func (f *Framer) parseDataFrame(streamId StreamId) (*DataFrame, error) { |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 332 | var length uint32 |
| 333 | if err := binary.Read(f.r, binary.BigEndian, &length); err != nil { |
| 334 | return nil, err |
| 335 | } |
| 336 | var frame DataFrame |
| 337 | frame.StreamId = streamId |
| 338 | frame.Flags = DataFlags(length >> 24) |
| 339 | length &= 0xffffff |
| 340 | frame.Data = make([]byte, length) |
| 341 | if _, err := io.ReadFull(f.r, frame.Data); err != nil { |
| 342 | return nil, err |
| 343 | } |
Jeff Hodges | 6fefb5e | 2012-10-30 16:12:50 +0900 | [diff] [blame] | 344 | if frame.StreamId == 0 { |
| 345 | return nil, &Error{ZeroStreamId, 0} |
| 346 | } |
Russ Cox | 3294cb5 | 2012-01-25 15:31:30 -0500 | [diff] [blame] | 347 | return &frame, nil |
| 348 | } |