|  | // 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 implements the SPDY protocol (currently SPDY/3), described in | 
|  | // http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3. | 
|  | package spdy | 
|  |  | 
|  | import ( | 
|  | "bytes" | 
|  | "compress/zlib" | 
|  | "io" | 
|  | "net/http" | 
|  | ) | 
|  |  | 
|  | // Version is the protocol version number that this package implements. | 
|  | const Version = 3 | 
|  |  | 
|  | // ControlFrameType stores the type field in a control frame header. | 
|  | type ControlFrameType uint16 | 
|  |  | 
|  | const ( | 
|  | TypeSynStream    ControlFrameType = 0x0001 | 
|  | TypeSynReply                      = 0x0002 | 
|  | TypeRstStream                     = 0x0003 | 
|  | TypeSettings                      = 0x0004 | 
|  | TypePing                          = 0x0006 | 
|  | TypeGoAway                        = 0x0007 | 
|  | TypeHeaders                       = 0x0008 | 
|  | TypeWindowUpdate                  = 0x0009 | 
|  | ) | 
|  |  | 
|  | // ControlFlags are the flags that can be set on a control frame. | 
|  | type ControlFlags uint8 | 
|  |  | 
|  | const ( | 
|  | ControlFlagFin                   ControlFlags = 0x01 | 
|  | ControlFlagUnidirectional                     = 0x02 | 
|  | ControlFlagSettingsClearSettings              = 0x01 | 
|  | ) | 
|  |  | 
|  | // DataFlags are the flags that can be set on a data frame. | 
|  | type DataFlags uint8 | 
|  |  | 
|  | const ( | 
|  | DataFlagFin DataFlags = 0x01 | 
|  | ) | 
|  |  | 
|  | // MaxDataLength is the maximum number of bytes that can be stored in one frame. | 
|  | const MaxDataLength = 1<<24 - 1 | 
|  |  | 
|  | // headerValueSepator separates multiple header values. | 
|  | const headerValueSeparator = "\x00" | 
|  |  | 
|  | // Frame is a single SPDY frame in its unpacked in-memory representation. Use | 
|  | // Framer to read and write it. | 
|  | type Frame interface { | 
|  | write(f *Framer) error | 
|  | } | 
|  |  | 
|  | // ControlFrameHeader contains all the fields in a control frame header, | 
|  | // in its unpacked in-memory representation. | 
|  | type ControlFrameHeader struct { | 
|  | // Note, high bit is the "Control" bit. | 
|  | version   uint16 // spdy version number | 
|  | frameType ControlFrameType | 
|  | Flags     ControlFlags | 
|  | length    uint32 // length of data field | 
|  | } | 
|  |  | 
|  | type controlFrame interface { | 
|  | Frame | 
|  | read(h ControlFrameHeader, f *Framer) error | 
|  | } | 
|  |  | 
|  | // StreamId represents a 31-bit value identifying the stream. | 
|  | type StreamId uint32 | 
|  |  | 
|  | // SynStreamFrame is the unpacked, in-memory representation of a SYN_STREAM | 
|  | // frame. | 
|  | type SynStreamFrame struct { | 
|  | CFHeader             ControlFrameHeader | 
|  | StreamId             StreamId | 
|  | AssociatedToStreamId StreamId // stream id for a stream which this stream is associated to | 
|  | Priority             uint8    // priority of this frame (3-bit) | 
|  | Slot                 uint8    // index in the server's credential vector of the client certificate | 
|  | Headers              http.Header | 
|  | } | 
|  |  | 
|  | // SynReplyFrame is the unpacked, in-memory representation of a SYN_REPLY frame. | 
|  | type SynReplyFrame struct { | 
|  | CFHeader ControlFrameHeader | 
|  | StreamId StreamId | 
|  | Headers  http.Header | 
|  | } | 
|  |  | 
|  | // RstStreamStatus represents the status that led to a RST_STREAM. | 
|  | type RstStreamStatus uint32 | 
|  |  | 
|  | const ( | 
|  | ProtocolError RstStreamStatus = iota + 1 | 
|  | InvalidStream | 
|  | RefusedStream | 
|  | UnsupportedVersion | 
|  | Cancel | 
|  | InternalError | 
|  | FlowControlError | 
|  | StreamInUse | 
|  | StreamAlreadyClosed | 
|  | InvalidCredentials | 
|  | FrameTooLarge | 
|  | ) | 
|  |  | 
|  | // RstStreamFrame is the unpacked, in-memory representation of a RST_STREAM | 
|  | // frame. | 
|  | type RstStreamFrame struct { | 
|  | CFHeader ControlFrameHeader | 
|  | StreamId StreamId | 
|  | Status   RstStreamStatus | 
|  | } | 
|  |  | 
|  | // SettingsFlag represents a flag in a SETTINGS frame. | 
|  | type SettingsFlag uint8 | 
|  |  | 
|  | const ( | 
|  | FlagSettingsPersistValue SettingsFlag = 0x1 | 
|  | FlagSettingsPersisted                 = 0x2 | 
|  | ) | 
|  |  | 
|  | // SettingsFlag represents the id of an id/value pair in a SETTINGS frame. | 
|  | type SettingsId uint32 | 
|  |  | 
|  | const ( | 
|  | SettingsUploadBandwidth SettingsId = iota + 1 | 
|  | SettingsDownloadBandwidth | 
|  | SettingsRoundTripTime | 
|  | SettingsMaxConcurrentStreams | 
|  | SettingsCurrentCwnd | 
|  | SettingsDownloadRetransRate | 
|  | SettingsInitialWindowSize | 
|  | SettingsClientCretificateVectorSize | 
|  | ) | 
|  |  | 
|  | // SettingsFlagIdValue is the unpacked, in-memory representation of the | 
|  | // combined flag/id/value for a setting in a SETTINGS frame. | 
|  | type SettingsFlagIdValue struct { | 
|  | Flag  SettingsFlag | 
|  | Id    SettingsId | 
|  | Value uint32 | 
|  | } | 
|  |  | 
|  | // SettingsFrame is the unpacked, in-memory representation of a SPDY | 
|  | // SETTINGS frame. | 
|  | type SettingsFrame struct { | 
|  | CFHeader     ControlFrameHeader | 
|  | FlagIdValues []SettingsFlagIdValue | 
|  | } | 
|  |  | 
|  | // PingFrame is the unpacked, in-memory representation of a PING frame. | 
|  | type PingFrame struct { | 
|  | CFHeader ControlFrameHeader | 
|  | Id       uint32 // unique id for this ping, from server is even, from client is odd. | 
|  | } | 
|  |  | 
|  | // GoAwayStatus represents the status in a GoAwayFrame. | 
|  | type GoAwayStatus uint32 | 
|  |  | 
|  | const ( | 
|  | GoAwayOK GoAwayStatus = iota | 
|  | GoAwayProtocolError | 
|  | GoAwayInternalError | 
|  | ) | 
|  |  | 
|  | // GoAwayFrame is the unpacked, in-memory representation of a GOAWAY frame. | 
|  | type GoAwayFrame struct { | 
|  | CFHeader         ControlFrameHeader | 
|  | LastGoodStreamId StreamId // last stream id which was accepted by sender | 
|  | Status           GoAwayStatus | 
|  | } | 
|  |  | 
|  | // HeadersFrame is the unpacked, in-memory representation of a HEADERS frame. | 
|  | type HeadersFrame struct { | 
|  | CFHeader ControlFrameHeader | 
|  | StreamId StreamId | 
|  | Headers  http.Header | 
|  | } | 
|  |  | 
|  | // WindowUpdateFrame is the unpacked, in-memory representation of a | 
|  | // WINDOW_UPDATE frame. | 
|  | type WindowUpdateFrame struct { | 
|  | CFHeader        ControlFrameHeader | 
|  | StreamId        StreamId | 
|  | DeltaWindowSize uint32 // additional number of bytes to existing window size | 
|  | } | 
|  |  | 
|  | // TODO: Implement credential frame and related methods. | 
|  |  | 
|  | // DataFrame is the unpacked, in-memory representation of a DATA frame. | 
|  | type DataFrame struct { | 
|  | // Note, high bit is the "Control" bit. Should be 0 for data frames. | 
|  | StreamId StreamId | 
|  | Flags    DataFlags | 
|  | Data     []byte // payload data of this frame | 
|  | } | 
|  |  | 
|  | // A SPDY specific error. | 
|  | type ErrorCode string | 
|  |  | 
|  | const ( | 
|  | UnlowercasedHeaderName     ErrorCode = "header was not lowercased" | 
|  | DuplicateHeaders                     = "multiple headers with same name" | 
|  | WrongCompressedPayloadSize           = "compressed payload size was incorrect" | 
|  | UnknownFrameType                     = "unknown frame type" | 
|  | InvalidControlFrame                  = "invalid control frame" | 
|  | InvalidDataFrame                     = "invalid data frame" | 
|  | InvalidHeaderPresent                 = "frame contained invalid header" | 
|  | ZeroStreamId                         = "stream id zero is disallowed" | 
|  | ) | 
|  |  | 
|  | // Error contains both the type of error and additional values. StreamId is 0 | 
|  | // if Error is not associated with a stream. | 
|  | type Error struct { | 
|  | Err      ErrorCode | 
|  | StreamId StreamId | 
|  | } | 
|  |  | 
|  | func (e *Error) Error() string { | 
|  | return string(e.Err) | 
|  | } | 
|  |  | 
|  | var invalidReqHeaders = map[string]bool{ | 
|  | "Connection":        true, | 
|  | "Host":              true, | 
|  | "Keep-Alive":        true, | 
|  | "Proxy-Connection":  true, | 
|  | "Transfer-Encoding": true, | 
|  | } | 
|  |  | 
|  | var invalidRespHeaders = map[string]bool{ | 
|  | "Connection":        true, | 
|  | "Keep-Alive":        true, | 
|  | "Proxy-Connection":  true, | 
|  | "Transfer-Encoding": true, | 
|  | } | 
|  |  | 
|  | // Framer handles serializing/deserializing SPDY frames, including compressing/ | 
|  | // decompressing payloads. | 
|  | type Framer struct { | 
|  | headerCompressionDisabled bool | 
|  | w                         io.Writer | 
|  | headerBuf                 *bytes.Buffer | 
|  | headerCompressor          *zlib.Writer | 
|  | r                         io.Reader | 
|  | headerReader              io.LimitedReader | 
|  | headerDecompressor        io.ReadCloser | 
|  | } | 
|  |  | 
|  | // NewFramer allocates a new Framer for a given SPDY connection, represented by | 
|  | // a io.Writer and io.Reader. Note that Framer will read and write individual fields | 
|  | // from/to the Reader and Writer, so the caller should pass in an appropriately | 
|  | // buffered implementation to optimize performance. | 
|  | func NewFramer(w io.Writer, r io.Reader) (*Framer, error) { | 
|  | compressBuf := new(bytes.Buffer) | 
|  | compressor, err := zlib.NewWriterLevelDict(compressBuf, zlib.BestCompression, []byte(headerDictionary)) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | framer := &Framer{ | 
|  | w:                w, | 
|  | headerBuf:        compressBuf, | 
|  | headerCompressor: compressor, | 
|  | r:                r, | 
|  | } | 
|  | return framer, nil | 
|  | } |