diff options
Diffstat (limited to 'libgo/go/http/spdy/protocol.go')
-rw-r--r-- | libgo/go/http/spdy/protocol.go | 367 |
1 files changed, 0 insertions, 367 deletions
diff --git a/libgo/go/http/spdy/protocol.go b/libgo/go/http/spdy/protocol.go deleted file mode 100644 index d584ea232ea..00000000000 --- a/libgo/go/http/spdy/protocol.go +++ /dev/null @@ -1,367 +0,0 @@ -// 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 is an incomplete implementation of the SPDY protocol. -// -// The implementation follows draft 2 of the spec: -// https://sites.google.com/a/chromium.org/dev/spdy/spdy-protocol/spdy-protocol-draft2 -package spdy - -import ( - "bytes" - "compress/zlib" - "encoding/binary" - "http" - "io" - "os" - "strconv" - "strings" - "sync" -) - -// Version is the protocol version number that this package implements. -const Version = 2 - -// ControlFrameType stores the type field in a control frame header. -type ControlFrameType uint16 - -// Control frame type constants -const ( - TypeSynStream ControlFrameType = 0x0001 - TypeSynReply = 0x0002 - TypeRstStream = 0x0003 - TypeSettings = 0x0004 - TypeNoop = 0x0005 - TypePing = 0x0006 - TypeGoaway = 0x0007 - TypeHeaders = 0x0008 - TypeWindowUpdate = 0x0009 -) - -func (t ControlFrameType) String() string { - switch t { - case TypeSynStream: - return "SYN_STREAM" - case TypeSynReply: - return "SYN_REPLY" - case TypeRstStream: - return "RST_STREAM" - case TypeSettings: - return "SETTINGS" - case TypeNoop: - return "NOOP" - case TypePing: - return "PING" - case TypeGoaway: - return "GOAWAY" - case TypeHeaders: - return "HEADERS" - case TypeWindowUpdate: - return "WINDOW_UPDATE" - } - return "Type(" + strconv.Itoa(int(t)) + ")" -} - -type FrameFlags uint8 - -// Stream frame flags -const ( - FlagFin FrameFlags = 0x01 - FlagUnidirectional = 0x02 -) - -// SETTINGS frame flags -const ( - FlagClearPreviouslyPersistedSettings FrameFlags = 0x01 -) - -// MaxDataLength is the maximum number of bytes that can be stored in one frame. -const MaxDataLength = 1<<24 - 1 - -// A Frame is a framed message as sent between clients and servers. -// There are two types of frames: control frames and data frames. -type Frame struct { - Header [4]byte - Flags FrameFlags - Data []byte -} - -// ControlFrame creates a control frame with the given information. -func ControlFrame(t ControlFrameType, f FrameFlags, data []byte) Frame { - return Frame{ - Header: [4]byte{ - (Version&0xff00)>>8 | 0x80, - (Version & 0x00ff), - byte((t & 0xff00) >> 8), - byte((t & 0x00ff) >> 0), - }, - Flags: f, - Data: data, - } -} - -// DataFrame creates a data frame with the given information. -func DataFrame(streamId uint32, f FrameFlags, data []byte) Frame { - return Frame{ - Header: [4]byte{ - byte(streamId & 0x7f000000 >> 24), - byte(streamId & 0x00ff0000 >> 16), - byte(streamId & 0x0000ff00 >> 8), - byte(streamId & 0x000000ff >> 0), - }, - Flags: f, - Data: data, - } -} - -// ReadFrame reads an entire frame into memory. -func ReadFrame(r io.Reader) (f Frame, err os.Error) { - _, err = io.ReadFull(r, f.Header[:]) - if err != nil { - return - } - err = binary.Read(r, binary.BigEndian, &f.Flags) - if err != nil { - return - } - var lengthField [3]byte - _, err = io.ReadFull(r, lengthField[:]) - if err != nil { - if err == os.EOF { - err = io.ErrUnexpectedEOF - } - return - } - var length uint32 - length |= uint32(lengthField[0]) << 16 - length |= uint32(lengthField[1]) << 8 - length |= uint32(lengthField[2]) << 0 - if length > 0 { - f.Data = make([]byte, int(length)) - _, err = io.ReadFull(r, f.Data) - if err == os.EOF { - err = io.ErrUnexpectedEOF - } - } else { - f.Data = []byte{} - } - return -} - -// IsControl returns whether the frame holds a control frame. -func (f Frame) IsControl() bool { - return f.Header[0]&0x80 != 0 -} - -// Type obtains the type field if the frame is a control frame, otherwise it returns zero. -func (f Frame) Type() ControlFrameType { - if !f.IsControl() { - return 0 - } - return (ControlFrameType(f.Header[2])<<8 | ControlFrameType(f.Header[3])) -} - -// StreamId returns the stream ID field if the frame is a data frame, otherwise it returns zero. -func (f Frame) StreamId() (id uint32) { - if f.IsControl() { - return 0 - } - id |= uint32(f.Header[0]) << 24 - id |= uint32(f.Header[1]) << 16 - id |= uint32(f.Header[2]) << 8 - id |= uint32(f.Header[3]) << 0 - return -} - -// WriteTo writes the frame in the SPDY format. -func (f Frame) WriteTo(w io.Writer) (n int64, err os.Error) { - var nn int - // Header - nn, err = w.Write(f.Header[:]) - n += int64(nn) - if err != nil { - return - } - // Flags - nn, err = w.Write([]byte{byte(f.Flags)}) - n += int64(nn) - if err != nil { - return - } - // Length - nn, err = w.Write([]byte{ - byte(len(f.Data) & 0x00ff0000 >> 16), - byte(len(f.Data) & 0x0000ff00 >> 8), - byte(len(f.Data) & 0x000000ff), - }) - n += int64(nn) - if err != nil { - return - } - // Data - if len(f.Data) > 0 { - nn, err = w.Write(f.Data) - n += int64(nn) - } - return -} - -// headerDictionary is the dictionary sent to the zlib compressor/decompressor. -// Even though the specification states there is no null byte at the end, Chrome sends it. -const headerDictionary = "optionsgetheadpostputdeletetrace" + - "acceptaccept-charsetaccept-encodingaccept-languageauthorizationexpectfromhost" + - "if-modified-sinceif-matchif-none-matchif-rangeif-unmodifiedsince" + - "max-forwardsproxy-authorizationrangerefererteuser-agent" + - "100101200201202203204205206300301302303304305306307400401402403404405406407408409410411412413414415416417500501502503504505" + - "accept-rangesageetaglocationproxy-authenticatepublicretry-after" + - "servervarywarningwww-authenticateallowcontent-basecontent-encodingcache-control" + - "connectiondatetrailertransfer-encodingupgradeviawarning" + - "content-languagecontent-lengthcontent-locationcontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookie" + - "MondayTuesdayWednesdayThursdayFridaySaturdaySunday" + - "JanFebMarAprMayJunJulAugSepOctNovDec" + - "chunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplication/xhtmltext/plainpublicmax-age" + - "charset=iso-8859-1utf-8gzipdeflateHTTP/1.1statusversionurl\x00" - -// hrSource is a reader that passes through reads from another reader. -// When the underlying reader reaches EOF, Read will block until another reader is added via change. -type hrSource struct { - r io.Reader - m sync.RWMutex - c *sync.Cond -} - -func (src *hrSource) Read(p []byte) (n int, err os.Error) { - src.m.RLock() - for src.r == nil { - src.c.Wait() - } - n, err = src.r.Read(p) - src.m.RUnlock() - if err == os.EOF { - src.change(nil) - err = nil - } - return -} - -func (src *hrSource) change(r io.Reader) { - src.m.Lock() - defer src.m.Unlock() - src.r = r - src.c.Broadcast() -} - -// A HeaderReader reads zlib-compressed headers. -type HeaderReader struct { - source hrSource - decompressor io.ReadCloser -} - -// NewHeaderReader creates a HeaderReader with the initial dictionary. -func NewHeaderReader() (hr *HeaderReader) { - hr = new(HeaderReader) - hr.source.c = sync.NewCond(hr.source.m.RLocker()) - return -} - -// ReadHeader reads a set of headers from a reader. -func (hr *HeaderReader) ReadHeader(r io.Reader) (h http.Header, err os.Error) { - hr.source.change(r) - h, err = hr.read() - return -} - -// Decode reads a set of headers from a block of bytes. -func (hr *HeaderReader) Decode(data []byte) (h http.Header, err os.Error) { - hr.source.change(bytes.NewBuffer(data)) - h, err = hr.read() - return -} - -func (hr *HeaderReader) read() (h http.Header, err os.Error) { - var count uint16 - if hr.decompressor == nil { - hr.decompressor, err = zlib.NewReaderDict(&hr.source, []byte(headerDictionary)) - if err != nil { - return - } - } - err = binary.Read(hr.decompressor, binary.BigEndian, &count) - if err != nil { - return - } - h = make(http.Header, int(count)) - for i := 0; i < int(count); i++ { - var name, value string - name, err = readHeaderString(hr.decompressor) - if err != nil { - return - } - value, err = readHeaderString(hr.decompressor) - if err != nil { - return - } - valueList := strings.Split(string(value), "\x00", -1) - for _, v := range valueList { - h.Add(name, v) - } - } - return -} - -func readHeaderString(r io.Reader) (s string, err os.Error) { - var length uint16 - err = binary.Read(r, binary.BigEndian, &length) - if err != nil { - return - } - data := make([]byte, int(length)) - _, err = io.ReadFull(r, data) - if err != nil { - return - } - return string(data), nil -} - -// HeaderWriter will write zlib-compressed headers on different streams. -type HeaderWriter struct { - compressor *zlib.Writer - buffer *bytes.Buffer -} - -// NewHeaderWriter creates a HeaderWriter ready to compress headers. -func NewHeaderWriter(level int) (hw *HeaderWriter) { - hw = &HeaderWriter{buffer: new(bytes.Buffer)} - hw.compressor, _ = zlib.NewWriterDict(hw.buffer, level, []byte(headerDictionary)) - return -} - -// WriteHeader writes a header block directly to an output. -func (hw *HeaderWriter) WriteHeader(w io.Writer, h http.Header) (err os.Error) { - hw.write(h) - _, err = io.Copy(w, hw.buffer) - hw.buffer.Reset() - return -} - -// Encode returns a compressed header block. -func (hw *HeaderWriter) Encode(h http.Header) (data []byte) { - hw.write(h) - data = make([]byte, hw.buffer.Len()) - hw.buffer.Read(data) - return -} - -func (hw *HeaderWriter) write(h http.Header) { - binary.Write(hw.compressor, binary.BigEndian, uint16(len(h))) - for k, vals := range h { - k = strings.ToLower(k) - binary.Write(hw.compressor, binary.BigEndian, uint16(len(k))) - binary.Write(hw.compressor, binary.BigEndian, []byte(k)) - v := strings.Join(vals, "\x00") - binary.Write(hw.compressor, binary.BigEndian, uint16(len(v))) - binary.Write(hw.compressor, binary.BigEndian, []byte(v)) - } - hw.compressor.Flush() -} |