349 lines
9.6 KiB
Go
349 lines
9.6 KiB
Go
|
// 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
|
||
|
}
|