// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package spdy import ( "compress/zlib" "encoding/binary" "io" "net/http" "strings" ) func (frame *SynStreamFrame) read(h ControlFrameHeader, f *Framer) error { return f.readSynStreamFrame(h, frame) } func (frame *SynReplyFrame) read(h ControlFrameHeader, f *Framer) error { return f.readSynReplyFrame(h, frame) } func (frame *RstStreamFrame) read(h ControlFrameHeader, f *Framer) error { frame.CFHeader = h if err := binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { return err } if err := binary.Read(f.r, binary.BigEndian, &frame.Status); err != nil { return err } if frame.Status == 0 { return &Error{InvalidControlFrame, frame.StreamId} } if frame.StreamId == 0 { return &Error{ZeroStreamId, 0} } return nil } func (frame *SettingsFrame) read(h ControlFrameHeader, f *Framer) error { frame.CFHeader = h var numSettings uint32 if err := binary.Read(f.r, binary.BigEndian, &numSettings); err != nil { return err } frame.FlagIdValues = make([]SettingsFlagIdValue, numSettings) for i := uint32(0); i < numSettings; i++ { if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Id); err != nil { return err } frame.FlagIdValues[i].Flag = SettingsFlag((frame.FlagIdValues[i].Id & 0xff000000) >> 24) frame.FlagIdValues[i].Id &= 0xffffff if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Value); err != nil { return err } } return nil } func (frame *PingFrame) read(h ControlFrameHeader, f *Framer) error { frame.CFHeader = h if err := binary.Read(f.r, binary.BigEndian, &frame.Id); err != nil { return err } if frame.Id == 0 { return &Error{ZeroStreamId, 0} } if frame.CFHeader.Flags != 0 { return &Error{InvalidControlFrame, StreamId(frame.Id)} } return nil } func (frame *GoAwayFrame) read(h ControlFrameHeader, f *Framer) error { frame.CFHeader = h if err := binary.Read(f.r, binary.BigEndian, &frame.LastGoodStreamId); err != nil { return err } if frame.CFHeader.Flags != 0 { return &Error{InvalidControlFrame, frame.LastGoodStreamId} } if frame.CFHeader.length != 8 { return &Error{InvalidControlFrame, frame.LastGoodStreamId} } if err := binary.Read(f.r, binary.BigEndian, &frame.Status); err != nil { return err } return nil } func (frame *HeadersFrame) read(h ControlFrameHeader, f *Framer) error { return f.readHeadersFrame(h, frame) } func (frame *WindowUpdateFrame) read(h ControlFrameHeader, f *Framer) error { frame.CFHeader = h if err := binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { return err } if frame.CFHeader.Flags != 0 { return &Error{InvalidControlFrame, frame.StreamId} } if frame.CFHeader.length != 8 { return &Error{InvalidControlFrame, frame.StreamId} } if err := binary.Read(f.r, binary.BigEndian, &frame.DeltaWindowSize); err != nil { return err } return nil } func newControlFrame(frameType ControlFrameType) (controlFrame, error) { ctor, ok := cframeCtor[frameType] if !ok { return nil, &Error{Err: InvalidControlFrame} } return ctor(), nil } var cframeCtor = map[ControlFrameType]func() controlFrame{ TypeSynStream: func() controlFrame { return new(SynStreamFrame) }, TypeSynReply: func() controlFrame { return new(SynReplyFrame) }, TypeRstStream: func() controlFrame { return new(RstStreamFrame) }, TypeSettings: func() controlFrame { return new(SettingsFrame) }, TypePing: func() controlFrame { return new(PingFrame) }, TypeGoAway: func() controlFrame { return new(GoAwayFrame) }, TypeHeaders: func() controlFrame { return new(HeadersFrame) }, TypeWindowUpdate: func() controlFrame { return new(WindowUpdateFrame) }, } func (f *Framer) uncorkHeaderDecompressor(payloadSize int64) error { if f.headerDecompressor != nil { f.headerReader.N = payloadSize return nil } f.headerReader = io.LimitedReader{R: f.r, N: payloadSize} decompressor, err := zlib.NewReaderDict(&f.headerReader, []byte(headerDictionary)) if err != nil { return err } f.headerDecompressor = decompressor return nil } // ReadFrame reads SPDY encoded data and returns a decompressed Frame. func (f *Framer) ReadFrame() (Frame, error) { var firstWord uint32 if err := binary.Read(f.r, binary.BigEndian, &firstWord); err != nil { return nil, err } if firstWord&0x80000000 != 0 { frameType := ControlFrameType(firstWord & 0xffff) version := uint16(firstWord >> 16 & 0x7fff) return f.parseControlFrame(version, frameType) } return f.parseDataFrame(StreamId(firstWord & 0x7fffffff)) } func (f *Framer) parseControlFrame(version uint16, frameType ControlFrameType) (Frame, error) { var length uint32 if err := binary.Read(f.r, binary.BigEndian, &length); err != nil { return nil, err } flags := ControlFlags((length & 0xff000000) >> 24) length &= 0xffffff header := ControlFrameHeader{version, frameType, flags, length} cframe, err := newControlFrame(frameType) if err != nil { return nil, err } if err = cframe.read(header, f); err != nil { return nil, err } return cframe, nil } func parseHeaderValueBlock(r io.Reader, streamId StreamId) (http.Header, error) { var numHeaders uint32 if err := binary.Read(r, binary.BigEndian, &numHeaders); err != nil { return nil, err } var e error h := make(http.Header, int(numHeaders)) for i := 0; i < int(numHeaders); i++ { var length uint32 if err := binary.Read(r, binary.BigEndian, &length); err != nil { return nil, err } nameBytes := make([]byte, length) if _, err := io.ReadFull(r, nameBytes); err != nil { return nil, err } name := string(nameBytes) if name != strings.ToLower(name) { e = &Error{UnlowercasedHeaderName, streamId} name = strings.ToLower(name) } if h[name] != nil { e = &Error{DuplicateHeaders, streamId} } if err := binary.Read(r, binary.BigEndian, &length); err != nil { return nil, err } value := make([]byte, length) if _, err := io.ReadFull(r, value); err != nil { return nil, err } valueList := strings.Split(string(value), headerValueSeparator) for _, v := range valueList { h.Add(name, v) } } if e != nil { return h, e } return h, nil } func (f *Framer) readSynStreamFrame(h ControlFrameHeader, frame *SynStreamFrame) error { frame.CFHeader = h var err error if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { return err } if err = binary.Read(f.r, binary.BigEndian, &frame.AssociatedToStreamId); err != nil { return err } if err = binary.Read(f.r, binary.BigEndian, &frame.Priority); err != nil { return err } frame.Priority >>= 5 if err = binary.Read(f.r, binary.BigEndian, &frame.Slot); err != nil { return err } reader := f.r if !f.headerCompressionDisabled { err := f.uncorkHeaderDecompressor(int64(h.length - 10)) if err != nil { return err } reader = f.headerDecompressor } frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId) if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) { err = &Error{WrongCompressedPayloadSize, 0} } if err != nil { return err } for h := range frame.Headers { if invalidReqHeaders[h] { return &Error{InvalidHeaderPresent, frame.StreamId} } } if frame.StreamId == 0 { return &Error{ZeroStreamId, 0} } return nil } func (f *Framer) readSynReplyFrame(h ControlFrameHeader, frame *SynReplyFrame) error { frame.CFHeader = h var err error if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { return err } reader := f.r if !f.headerCompressionDisabled { err := f.uncorkHeaderDecompressor(int64(h.length - 4)) if err != nil { return err } reader = f.headerDecompressor } frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId) if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) { err = &Error{WrongCompressedPayloadSize, 0} } if err != nil { return err } for h := range frame.Headers { if invalidRespHeaders[h] { return &Error{InvalidHeaderPresent, frame.StreamId} } } if frame.StreamId == 0 { return &Error{ZeroStreamId, 0} } return nil } func (f *Framer) readHeadersFrame(h ControlFrameHeader, frame *HeadersFrame) error { frame.CFHeader = h var err error if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil { return err } reader := f.r if !f.headerCompressionDisabled { err := f.uncorkHeaderDecompressor(int64(h.length - 4)) if err != nil { return err } reader = f.headerDecompressor } frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId) if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) { err = &Error{WrongCompressedPayloadSize, 0} } if err != nil { return err } var invalidHeaders map[string]bool if frame.StreamId%2 == 0 { invalidHeaders = invalidReqHeaders } else { invalidHeaders = invalidRespHeaders } for h := range frame.Headers { if invalidHeaders[h] { return &Error{InvalidHeaderPresent, frame.StreamId} } } if frame.StreamId == 0 { return &Error{ZeroStreamId, 0} } return nil } func (f *Framer) parseDataFrame(streamId StreamId) (*DataFrame, error) { var length uint32 if err := binary.Read(f.r, binary.BigEndian, &length); err != nil { return nil, err } var frame DataFrame frame.StreamId = streamId frame.Flags = DataFlags(length >> 24) length &= 0xffffff frame.Data = make([]byte, length) if _, err := io.ReadFull(f.r, frame.Data); err != nil { return nil, err } if frame.StreamId == 0 { return nil, &Error{ZeroStreamId, 0} } return &frame, nil }