| // 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 |
| } |