1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Package spdy is an incomplete implementation of the SPDY protocol.
7 // The implementation follows draft 2 of the spec:
8 // https://sites.google.com/a/chromium.org/dev/spdy/spdy-protocol/spdy-protocol-draft2
23 // Version is the protocol version number that this package implements.
26 // ControlFrameType stores the type field in a control frame header.
27 type ControlFrameType uint16
29 // Control frame type constants
31 TypeSynStream ControlFrameType = 0x0001
33 TypeRstStream = 0x0003
39 TypeWindowUpdate = 0x0009
42 func (t ControlFrameType) String() string {
60 case TypeWindowUpdate:
61 return "WINDOW_UPDATE"
63 return "Type(" + strconv.Itoa(int(t)) + ")"
70 FlagFin FrameFlags = 0x01
71 FlagUnidirectional = 0x02
74 // SETTINGS frame flags
76 FlagClearPreviouslyPersistedSettings FrameFlags = 0x01
79 // MaxDataLength is the maximum number of bytes that can be stored in one frame.
80 const MaxDataLength = 1<<24 - 1
82 // A Frame is a framed message as sent between clients and servers.
83 // There are two types of frames: control frames and data frames.
90 // ControlFrame creates a control frame with the given information.
91 func ControlFrame(t ControlFrameType, f FrameFlags, data []byte) Frame {
94 (Version&0xff00)>>8 | 0x80,
96 byte((t & 0xff00) >> 8),
97 byte((t & 0x00ff) >> 0),
104 // DataFrame creates a data frame with the given information.
105 func DataFrame(streamId uint32, f FrameFlags, data []byte) Frame {
108 byte(streamId & 0x7f000000 >> 24),
109 byte(streamId & 0x00ff0000 >> 16),
110 byte(streamId & 0x0000ff00 >> 8),
111 byte(streamId & 0x000000ff >> 0),
118 // ReadFrame reads an entire frame into memory.
119 func ReadFrame(r io.Reader) (f Frame, err os.Error) {
120 _, err = io.ReadFull(r, f.Header[:])
124 err = binary.Read(r, binary.BigEndian, &f.Flags)
128 var lengthField [3]byte
129 _, err = io.ReadFull(r, lengthField[:])
132 err = io.ErrUnexpectedEOF
137 length |= uint32(lengthField[0]) << 16
138 length |= uint32(lengthField[1]) << 8
139 length |= uint32(lengthField[2]) << 0
141 f.Data = make([]byte, int(length))
142 _, err = io.ReadFull(r, f.Data)
144 err = io.ErrUnexpectedEOF
152 // IsControl returns whether the frame holds a control frame.
153 func (f Frame) IsControl() bool {
154 return f.Header[0]&0x80 != 0
157 // Type obtains the type field if the frame is a control frame, otherwise it returns zero.
158 func (f Frame) Type() ControlFrameType {
162 return (ControlFrameType(f.Header[2])<<8 | ControlFrameType(f.Header[3]))
165 // StreamId returns the stream ID field if the frame is a data frame, otherwise it returns zero.
166 func (f Frame) StreamId() (id uint32) {
170 id |= uint32(f.Header[0]) << 24
171 id |= uint32(f.Header[1]) << 16
172 id |= uint32(f.Header[2]) << 8
173 id |= uint32(f.Header[3]) << 0
177 // WriteTo writes the frame in the SPDY format.
178 func (f Frame) WriteTo(w io.Writer) (n int64, err os.Error) {
181 nn, err = w.Write(f.Header[:])
187 nn, err = w.Write([]byte{byte(f.Flags)})
193 nn, err = w.Write([]byte{
194 byte(len(f.Data) & 0x00ff0000 >> 16),
195 byte(len(f.Data) & 0x0000ff00 >> 8),
196 byte(len(f.Data) & 0x000000ff),
204 nn, err = w.Write(f.Data)
210 // headerDictionary is the dictionary sent to the zlib compressor/decompressor.
211 // Even though the specification states there is no null byte at the end, Chrome sends it.
212 const headerDictionary = "optionsgetheadpostputdeletetrace" +
213 "acceptaccept-charsetaccept-encodingaccept-languageauthorizationexpectfromhost" +
214 "if-modified-sinceif-matchif-none-matchif-rangeif-unmodifiedsince" +
215 "max-forwardsproxy-authorizationrangerefererteuser-agent" +
216 "100101200201202203204205206300301302303304305306307400401402403404405406407408409410411412413414415416417500501502503504505" +
217 "accept-rangesageetaglocationproxy-authenticatepublicretry-after" +
218 "servervarywarningwww-authenticateallowcontent-basecontent-encodingcache-control" +
219 "connectiondatetrailertransfer-encodingupgradeviawarning" +
220 "content-languagecontent-lengthcontent-locationcontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookie" +
221 "MondayTuesdayWednesdayThursdayFridaySaturdaySunday" +
222 "JanFebMarAprMayJunJulAugSepOctNovDec" +
223 "chunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplication/xhtmltext/plainpublicmax-age" +
224 "charset=iso-8859-1utf-8gzipdeflateHTTP/1.1statusversionurl\x00"
226 // hrSource is a reader that passes through reads from another reader.
227 // When the underlying reader reaches EOF, Read will block until another reader is added via change.
228 type hrSource struct {
234 func (src *hrSource) Read(p []byte) (n int, err os.Error) {
239 n, err = src.r.Read(p)
248 func (src *hrSource) change(r io.Reader) {
255 // A HeaderReader reads zlib-compressed headers.
256 type HeaderReader struct {
258 decompressor io.ReadCloser
261 // NewHeaderReader creates a HeaderReader with the initial dictionary.
262 func NewHeaderReader() (hr *HeaderReader) {
263 hr = new(HeaderReader)
264 hr.source.c = sync.NewCond(hr.source.m.RLocker())
268 // ReadHeader reads a set of headers from a reader.
269 func (hr *HeaderReader) ReadHeader(r io.Reader) (h http.Header, err os.Error) {
275 // Decode reads a set of headers from a block of bytes.
276 func (hr *HeaderReader) Decode(data []byte) (h http.Header, err os.Error) {
277 hr.source.change(bytes.NewBuffer(data))
282 func (hr *HeaderReader) read() (h http.Header, err os.Error) {
284 if hr.decompressor == nil {
285 hr.decompressor, err = zlib.NewReaderDict(&hr.source, []byte(headerDictionary))
290 err = binary.Read(hr.decompressor, binary.BigEndian, &count)
294 h = make(http.Header, int(count))
295 for i := 0; i < int(count); i++ {
296 var name, value string
297 name, err = readHeaderString(hr.decompressor)
301 value, err = readHeaderString(hr.decompressor)
305 valueList := strings.Split(string(value), "\x00", -1)
306 for _, v := range valueList {
313 func readHeaderString(r io.Reader) (s string, err os.Error) {
315 err = binary.Read(r, binary.BigEndian, &length)
319 data := make([]byte, int(length))
320 _, err = io.ReadFull(r, data)
324 return string(data), nil
327 // HeaderWriter will write zlib-compressed headers on different streams.
328 type HeaderWriter struct {
329 compressor *zlib.Writer
333 // NewHeaderWriter creates a HeaderWriter ready to compress headers.
334 func NewHeaderWriter(level int) (hw *HeaderWriter) {
335 hw = &HeaderWriter{buffer: new(bytes.Buffer)}
336 hw.compressor, _ = zlib.NewWriterDict(hw.buffer, level, []byte(headerDictionary))
340 // WriteHeader writes a header block directly to an output.
341 func (hw *HeaderWriter) WriteHeader(w io.Writer, h http.Header) (err os.Error) {
343 _, err = io.Copy(w, hw.buffer)
348 // Encode returns a compressed header block.
349 func (hw *HeaderWriter) Encode(h http.Header) (data []byte) {
351 data = make([]byte, hw.buffer.Len())
356 func (hw *HeaderWriter) write(h http.Header) {
357 binary.Write(hw.compressor, binary.BigEndian, uint16(len(h)))
358 for k, vals := range h {
359 k = strings.ToLower(k)
360 binary.Write(hw.compressor, binary.BigEndian, uint16(len(k)))
361 binary.Write(hw.compressor, binary.BigEndian, []byte(k))
362 v := strings.Join(vals, "\x00")
363 binary.Write(hw.compressor, binary.BigEndian, uint16(len(v)))
364 binary.Write(hw.compressor, binary.BigEndian, []byte(v))
366 hw.compressor.Flush()