Commit bc3a72fa authored by William Chan's avatar William Chan Committed by Brad Fitzpatrick

http/spdy: reorganize package.

R=bradfitz, rsc
CC=golang-dev
https://golang.org/cl/4524087
parent 17bfa32f
......@@ -6,7 +6,8 @@ include ../../../Make.inc
TARG=http/spdy
GOFILES=\
framer.go\
protocol.go\
read.go\
types.go\
write.go\
include ../../../Make.pkg
......@@ -5,43 +5,96 @@
package spdy
import (
"bytes"
"encoding/binary"
"compress/zlib"
"encoding/binary"
"http"
"io"
"os"
"strconv"
"strings"
)
type FramerError int
func (frame *SynStreamFrame) read(h ControlFrameHeader, f *Framer) os.Error {
return f.readSynStreamFrame(h, frame)
}
const (
Internal FramerError = iota
InvalidControlFrame
UnlowercasedHeaderName
DuplicateHeaders
UnknownFrameType
InvalidDataFrame
)
func (frame *SynReplyFrame) read(h ControlFrameHeader, f *Framer) os.Error {
return f.readSynReplyFrame(h, frame)
}
func (frame *RstStreamFrame) read(h ControlFrameHeader, f *Framer) os.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
}
return nil
}
func (frame *SettingsFrame) read(h ControlFrameHeader, f *Framer) os.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 *NoopFrame) read(h ControlFrameHeader, f *Framer) os.Error {
frame.CFHeader = h
return nil
}
func (frame *PingFrame) read(h ControlFrameHeader, f *Framer) os.Error {
frame.CFHeader = h
if err := binary.Read(f.r, binary.BigEndian, &frame.Id); err != nil {
return err
}
return nil
}
func (frame *GoAwayFrame) read(h ControlFrameHeader, f *Framer) os.Error {
frame.CFHeader = h
if err := binary.Read(f.r, binary.BigEndian, &frame.LastGoodStreamId); err != nil {
return err
}
return nil
}
func (frame *HeadersFrame) read(h ControlFrameHeader, f *Framer) os.Error {
return f.readHeadersFrame(h, frame)
}
func newControlFrame(frameType ControlFrameType) (controlFrame, os.Error) {
ctor, ok := cframeCtor[frameType]
if !ok {
return nil, InvalidControlFrame
}
return ctor(), nil
}
func (e FramerError) String() string {
switch e {
case Internal:
return "Internal"
case InvalidControlFrame:
return "InvalidControlFrame"
case UnlowercasedHeaderName:
return "UnlowercasedHeaderName"
case DuplicateHeaders:
return "DuplicateHeaders"
case UnknownFrameType:
return "UnknownFrameType"
case InvalidDataFrame:
return "InvalidDataFrame"
}
return "Error(" + strconv.Itoa(int(e)) + ")"
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) },
TypeNoop: func() controlFrame { return new(NoopFrame) },
TypePing: func() controlFrame { return new(PingFrame) },
TypeGoAway: func() controlFrame { return new(GoAwayFrame) },
TypeHeaders: func() controlFrame { return new(HeadersFrame) },
// TODO(willchan): Add TypeWindowUpdate
}
type corkedReader struct {
......@@ -62,37 +115,6 @@ func (cr *corkedReader) Read(p []byte) (int, os.Error) {
return n, err
}
// 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 corkedReader
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, os.Error) {
compressBuf := new(bytes.Buffer)
compressor, err := zlib.NewWriterDict(compressBuf, zlib.BestCompression, []byte(HeaderDictionary))
if err != nil {
return nil, err
}
framer := &Framer{
w: w,
headerBuf: compressBuf,
headerCompressor: compressor,
r: r,
}
return framer, nil
}
func (f *Framer) uncorkHeaderDecompressor(payloadSize int) os.Error {
if f.headerDecompressor != nil {
f.headerReader.ch <- payloadSize
......@@ -263,181 +285,3 @@ func (f *Framer) parseDataFrame(streamId uint32) (*DataFrame, os.Error) {
}
return &frame, nil
}
// WriteFrame writes a frame.
func (f *Framer) WriteFrame(frame Frame) os.Error {
return frame.write(f)
}
func writeControlFrameHeader(w io.Writer, h ControlFrameHeader) os.Error {
if err := binary.Write(w, binary.BigEndian, 0x8000|h.version); err != nil {
return err
}
if err := binary.Write(w, binary.BigEndian, h.frameType); err != nil {
return err
}
flagsAndLength := (uint32(h.Flags) << 24) | h.length
if err := binary.Write(w, binary.BigEndian, flagsAndLength); err != nil {
return err
}
return nil
}
func writeHeaderValueBlock(w io.Writer, h http.Header) (n int, err os.Error) {
n = 0
if err = binary.Write(w, binary.BigEndian, uint16(len(h))); err != nil {
return
}
n += 2
for name, values := range h {
if err = binary.Write(w, binary.BigEndian, uint16(len(name))); err != nil {
return
}
n += 2
name = strings.ToLower(name)
if _, err = io.WriteString(w, name); err != nil {
return
}
n += len(name)
v := strings.Join(values, "\x00")
if err = binary.Write(w, binary.BigEndian, uint16(len(v))); err != nil {
return
}
n += 2
if _, err = io.WriteString(w, v); err != nil {
return
}
n += len(v)
}
return
}
func (f *Framer) writeSynStreamFrame(frame *SynStreamFrame) (err os.Error) {
// Marshal the headers.
var writer io.Writer = f.headerBuf
if !f.headerCompressionDisabled {
writer = f.headerCompressor
}
if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
return
}
if !f.headerCompressionDisabled {
f.headerCompressor.Flush()
}
// Set ControlFrameHeader
frame.CFHeader.version = Version
frame.CFHeader.frameType = TypeSynStream
frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 10)
// Serialize frame to Writer
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
return err
}
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
return err
}
if err = binary.Write(f.w, binary.BigEndian, frame.AssociatedToStreamId); err != nil {
return err
}
if err = binary.Write(f.w, binary.BigEndian, frame.Priority<<14); err != nil {
return err
}
if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
return err
}
f.headerBuf.Reset()
return nil
}
func (f *Framer) writeSynReplyFrame(frame *SynReplyFrame) (err os.Error) {
// Marshal the headers.
var writer io.Writer = f.headerBuf
if !f.headerCompressionDisabled {
writer = f.headerCompressor
}
if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
return
}
if !f.headerCompressionDisabled {
f.headerCompressor.Flush()
}
// Set ControlFrameHeader
frame.CFHeader.version = Version
frame.CFHeader.frameType = TypeSynReply
frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 6)
// Serialize frame to Writer
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, uint16(0)); err != nil {
return
}
if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
return
}
f.headerBuf.Reset()
return
}
func (f *Framer) writeHeadersFrame(frame *HeadersFrame) (err os.Error) {
// Marshal the headers.
var writer io.Writer = f.headerBuf
if !f.headerCompressionDisabled {
writer = f.headerCompressor
}
if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
return
}
if !f.headerCompressionDisabled {
f.headerCompressor.Flush()
}
// Set ControlFrameHeader
frame.CFHeader.version = Version
frame.CFHeader.frameType = TypeHeaders
frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 6)
// Serialize frame to Writer
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, uint16(0)); err != nil {
return
}
if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
return
}
f.headerBuf.Reset()
return
}
func (f *Framer) writeDataFrame(frame *DataFrame) (err os.Error) {
// Validate DataFrame
if frame.StreamId&0x80000000 != 0 || len(frame.Data) >= 0x0f000000 {
return InvalidDataFrame
}
// TODO(willchan): Support data compression.
// Serialize frame to Writer
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
return
}
flagsAndLength := (uint32(frame.Flags) << 24) | uint32(len(frame.Data))
if err = binary.Write(f.w, binary.BigEndian, flagsAndLength); err != nil {
return
}
if _, err = f.w.Write(frame.Data); err != nil {
return
}
return nil
}
......@@ -2,16 +2,15 @@
// 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 (
"encoding/binary"
"bytes"
"compress/zlib"
"http"
"io"
"os"
"strconv"
)
// Data Frame Format
......@@ -193,14 +192,6 @@ type SynStreamFrame struct {
Headers http.Header
}
func (frame *SynStreamFrame) write(f *Framer) os.Error {
return f.writeSynStreamFrame(frame)
}
func (frame *SynStreamFrame) read(h ControlFrameHeader, f *Framer) os.Error {
return f.readSynStreamFrame(h, frame)
}
// SynReplyFrame is the unpacked, in-memory representation of a SYN_REPLY frame.
type SynReplyFrame struct {
CFHeader ControlFrameHeader
......@@ -208,14 +199,6 @@ type SynReplyFrame struct {
Headers http.Header
}
func (frame *SynReplyFrame) write(f *Framer) os.Error {
return f.writeSynReplyFrame(frame)
}
func (frame *SynReplyFrame) read(h ControlFrameHeader, f *Framer) os.Error {
return f.readSynReplyFrame(h, frame)
}
// StatusCode represents the status that led to a RST_STREAM
type StatusCode uint32
......@@ -237,35 +220,6 @@ type RstStreamFrame struct {
Status StatusCode
}
func (frame *RstStreamFrame) write(f *Framer) (err os.Error) {
frame.CFHeader.version = Version
frame.CFHeader.frameType = TypeRstStream
frame.CFHeader.length = 8
// Serialize frame to Writer
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil {
return
}
return
}
func (frame *RstStreamFrame) read(h ControlFrameHeader, f *Framer) os.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
}
return nil
}
// SettingsFlag represents a flag in a SETTINGS frame.
type SettingsFlag uint8
......@@ -300,126 +254,23 @@ type SettingsFrame struct {
FlagIdValues []SettingsFlagIdValue
}
func (frame *SettingsFrame) write(f *Framer) (err os.Error) {
frame.CFHeader.version = Version
frame.CFHeader.frameType = TypeSettings
frame.CFHeader.length = uint32(len(frame.FlagIdValues)*8 + 4)
// Serialize frame to Writer
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, uint32(len(frame.FlagIdValues))); err != nil {
return
}
for _, flagIdValue := range frame.FlagIdValues {
flagId := (uint32(flagIdValue.Flag) << 24) | uint32(flagIdValue.Id)
if err = binary.Write(f.w, binary.BigEndian, flagId); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, flagIdValue.Value); err != nil {
return
}
}
return
}
func (frame *SettingsFrame) read(h ControlFrameHeader, f *Framer) os.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
}
// NoopFrame is the unpacked, in-memory representation of a NOOP frame.
type NoopFrame struct {
CFHeader ControlFrameHeader
}
func (frame *NoopFrame) write(f *Framer) os.Error {
frame.CFHeader.version = Version
frame.CFHeader.frameType = TypeNoop
// Serialize frame to Writer
return writeControlFrameHeader(f.w, frame.CFHeader)
}
func (frame *NoopFrame) read(h ControlFrameHeader, f *Framer) os.Error {
frame.CFHeader = h
return nil
}
// PingFrame is the unpacked, in-memory representation of a PING frame.
type PingFrame struct {
CFHeader ControlFrameHeader
Id uint32
}
func (frame *PingFrame) write(f *Framer) (err os.Error) {
frame.CFHeader.version = Version
frame.CFHeader.frameType = TypePing
frame.CFHeader.length = 4
// Serialize frame to Writer
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, frame.Id); err != nil {
return
}
return
}
func (frame *PingFrame) read(h ControlFrameHeader, f *Framer) os.Error {
frame.CFHeader = h
if err := binary.Read(f.r, binary.BigEndian, &frame.Id); err != nil {
return err
}
return nil
}
// GoAwayFrame is the unpacked, in-memory representation of a GOAWAY frame.
type GoAwayFrame struct {
CFHeader ControlFrameHeader
LastGoodStreamId uint32
}
func (frame *GoAwayFrame) write(f *Framer) (err os.Error) {
frame.CFHeader.version = Version
frame.CFHeader.frameType = TypeGoAway
frame.CFHeader.length = 4
// Serialize frame to Writer
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, frame.LastGoodStreamId); err != nil {
return
}
return nil
}
func (frame *GoAwayFrame) read(h ControlFrameHeader, f *Framer) os.Error {
frame.CFHeader = h
if err := binary.Read(f.r, binary.BigEndian, &frame.LastGoodStreamId); err != nil {
return err
}
return nil
}
// HeadersFrame is the unpacked, in-memory representation of a HEADERS frame.
type HeadersFrame struct {
CFHeader ControlFrameHeader
......@@ -427,34 +278,6 @@ type HeadersFrame struct {
Headers http.Header
}
func (frame *HeadersFrame) write(f *Framer) os.Error {
return f.writeHeadersFrame(frame)
}
func (frame *HeadersFrame) read(h ControlFrameHeader, f *Framer) os.Error {
return f.readHeadersFrame(h, frame)
}
func newControlFrame(frameType ControlFrameType) (controlFrame, os.Error) {
ctor, ok := cframeCtor[frameType]
if !ok {
return nil, 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) },
TypeNoop: func() controlFrame { return new(NoopFrame) },
TypePing: func() controlFrame { return new(PingFrame) },
TypeGoAway: func() controlFrame { return new(GoAwayFrame) },
TypeHeaders: func() controlFrame { return new(HeadersFrame) },
// TODO(willchan): Add TypeWindowUpdate
}
// 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.
......@@ -463,10 +286,6 @@ type DataFrame struct {
Data []byte
}
func (frame *DataFrame) write(f *Framer) os.Error {
return f.writeDataFrame(frame)
}
// 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" +
......@@ -482,3 +301,63 @@ const HeaderDictionary = "optionsgetheadpostputdeletetrace" +
"JanFebMarAprMayJunJulAugSepOctNovDec" +
"chunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplication/xhtmltext/plainpublicmax-age" +
"charset=iso-8859-1utf-8gzipdeflateHTTP/1.1statusversionurl\x00"
type FramerError int
const (
Internal FramerError = iota
InvalidControlFrame
UnlowercasedHeaderName
DuplicateHeaders
UnknownFrameType
InvalidDataFrame
)
func (e FramerError) String() string {
switch e {
case Internal:
return "Internal"
case InvalidControlFrame:
return "InvalidControlFrame"
case UnlowercasedHeaderName:
return "UnlowercasedHeaderName"
case DuplicateHeaders:
return "DuplicateHeaders"
case UnknownFrameType:
return "UnknownFrameType"
case InvalidDataFrame:
return "InvalidDataFrame"
}
return "Error(" + strconv.Itoa(int(e)) + ")"
}
// 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 corkedReader
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, os.Error) {
compressBuf := new(bytes.Buffer)
compressor, err := zlib.NewWriterDict(compressBuf, zlib.BestCompression, []byte(HeaderDictionary))
if err != nil {
return nil, err
}
framer := &Framer{
w: w,
headerBuf: compressBuf,
headerCompressor: compressor,
r: r,
}
return framer, nil
}
// 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 (
"encoding/binary"
"http"
"io"
"os"
"strings"
)
func (frame *SynStreamFrame) write(f *Framer) os.Error {
return f.writeSynStreamFrame(frame)
}
func (frame *SynReplyFrame) write(f *Framer) os.Error {
return f.writeSynReplyFrame(frame)
}
func (frame *RstStreamFrame) write(f *Framer) (err os.Error) {
frame.CFHeader.version = Version
frame.CFHeader.frameType = TypeRstStream
frame.CFHeader.length = 8
// Serialize frame to Writer
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil {
return
}
return
}
func (frame *SettingsFrame) write(f *Framer) (err os.Error) {
frame.CFHeader.version = Version
frame.CFHeader.frameType = TypeSettings
frame.CFHeader.length = uint32(len(frame.FlagIdValues)*8 + 4)
// Serialize frame to Writer
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, uint32(len(frame.FlagIdValues))); err != nil {
return
}
for _, flagIdValue := range frame.FlagIdValues {
flagId := (uint32(flagIdValue.Flag) << 24) | uint32(flagIdValue.Id)
if err = binary.Write(f.w, binary.BigEndian, flagId); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, flagIdValue.Value); err != nil {
return
}
}
return
}
func (frame *NoopFrame) write(f *Framer) os.Error {
frame.CFHeader.version = Version
frame.CFHeader.frameType = TypeNoop
// Serialize frame to Writer
return writeControlFrameHeader(f.w, frame.CFHeader)
}
func (frame *PingFrame) write(f *Framer) (err os.Error) {
frame.CFHeader.version = Version
frame.CFHeader.frameType = TypePing
frame.CFHeader.length = 4
// Serialize frame to Writer
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, frame.Id); err != nil {
return
}
return
}
func (frame *GoAwayFrame) write(f *Framer) (err os.Error) {
frame.CFHeader.version = Version
frame.CFHeader.frameType = TypeGoAway
frame.CFHeader.length = 4
// Serialize frame to Writer
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, frame.LastGoodStreamId); err != nil {
return
}
return nil
}
func (frame *HeadersFrame) write(f *Framer) os.Error {
return f.writeHeadersFrame(frame)
}
func (frame *DataFrame) write(f *Framer) os.Error {
return f.writeDataFrame(frame)
}
// WriteFrame writes a frame.
func (f *Framer) WriteFrame(frame Frame) os.Error {
return frame.write(f)
}
func writeControlFrameHeader(w io.Writer, h ControlFrameHeader) os.Error {
if err := binary.Write(w, binary.BigEndian, 0x8000|h.version); err != nil {
return err
}
if err := binary.Write(w, binary.BigEndian, h.frameType); err != nil {
return err
}
flagsAndLength := (uint32(h.Flags) << 24) | h.length
if err := binary.Write(w, binary.BigEndian, flagsAndLength); err != nil {
return err
}
return nil
}
func writeHeaderValueBlock(w io.Writer, h http.Header) (n int, err os.Error) {
n = 0
if err = binary.Write(w, binary.BigEndian, uint16(len(h))); err != nil {
return
}
n += 2
for name, values := range h {
if err = binary.Write(w, binary.BigEndian, uint16(len(name))); err != nil {
return
}
n += 2
name = strings.ToLower(name)
if _, err = io.WriteString(w, name); err != nil {
return
}
n += len(name)
v := strings.Join(values, "\x00")
if err = binary.Write(w, binary.BigEndian, uint16(len(v))); err != nil {
return
}
n += 2
if _, err = io.WriteString(w, v); err != nil {
return
}
n += len(v)
}
return
}
func (f *Framer) writeSynStreamFrame(frame *SynStreamFrame) (err os.Error) {
// Marshal the headers.
var writer io.Writer = f.headerBuf
if !f.headerCompressionDisabled {
writer = f.headerCompressor
}
if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
return
}
if !f.headerCompressionDisabled {
f.headerCompressor.Flush()
}
// Set ControlFrameHeader
frame.CFHeader.version = Version
frame.CFHeader.frameType = TypeSynStream
frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 10)
// Serialize frame to Writer
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
return err
}
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
return err
}
if err = binary.Write(f.w, binary.BigEndian, frame.AssociatedToStreamId); err != nil {
return err
}
if err = binary.Write(f.w, binary.BigEndian, frame.Priority<<14); err != nil {
return err
}
if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
return err
}
f.headerBuf.Reset()
return nil
}
func (f *Framer) writeSynReplyFrame(frame *SynReplyFrame) (err os.Error) {
// Marshal the headers.
var writer io.Writer = f.headerBuf
if !f.headerCompressionDisabled {
writer = f.headerCompressor
}
if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
return
}
if !f.headerCompressionDisabled {
f.headerCompressor.Flush()
}
// Set ControlFrameHeader
frame.CFHeader.version = Version
frame.CFHeader.frameType = TypeSynReply
frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 6)
// Serialize frame to Writer
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, uint16(0)); err != nil {
return
}
if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
return
}
f.headerBuf.Reset()
return
}
func (f *Framer) writeHeadersFrame(frame *HeadersFrame) (err os.Error) {
// Marshal the headers.
var writer io.Writer = f.headerBuf
if !f.headerCompressionDisabled {
writer = f.headerCompressor
}
if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
return
}
if !f.headerCompressionDisabled {
f.headerCompressor.Flush()
}
// Set ControlFrameHeader
frame.CFHeader.version = Version
frame.CFHeader.frameType = TypeHeaders
frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 6)
// Serialize frame to Writer
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
return
}
if err = binary.Write(f.w, binary.BigEndian, uint16(0)); err != nil {
return
}
if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
return
}
f.headerBuf.Reset()
return
}
func (f *Framer) writeDataFrame(frame *DataFrame) (err os.Error) {
// Validate DataFrame
if frame.StreamId&0x80000000 != 0 || len(frame.Data) >= 0x0f000000 {
return InvalidDataFrame
}
// TODO(willchan): Support data compression.
// Serialize frame to Writer
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
return
}
flagsAndLength := (uint32(frame.Flags) << 24) | uint32(len(frame.Data))
if err = binary.Write(f.w, binary.BigEndian, flagsAndLength); err != nil {
return
}
if _, err = f.w.Write(frame.Data); err != nil {
return
}
return nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment