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