Ross Light avatar Ross Light committed aabc1d2 Merge

merge

Comments (0)

Files changed (3)

 
 import (
 	"bytes"
-	"os"
+	"io"
 	"sync"
+	"syscall"
 )
 
 // An asyncPipe is similar to *io.Pipe, but writes never block: they are sent to a buffer, where a reader will block until it has some data in the buffer.
 	data    bytes.Buffer // data remaining
 	rwait   sync.Cond    // waiting reader
 	rclosed bool         // if reader closed, break pipe
-	werr    os.Error     // if writer closed, error to give reads
+	werr    error        // if writer closed, error to give reads
 }
 
-func (p *asyncPipe) read(b []byte) (n int, err os.Error) {
+func (p *asyncPipe) read(b []byte) (n int, err error) {
 	// One reader at a time.
 	p.rl.Lock()
 	defer p.rl.Unlock()
 	defer p.l.Unlock()
 	for {
 		if p.rclosed {
-			return 0, os.EINVAL
+			return 0, syscall.EINVAL
 		}
 		if p.data.Len() > 0 {
 			break
 	return p.data.Read(b)
 }
 
-func (p *asyncPipe) write(b []byte) (n int, err os.Error) {
+func (p *asyncPipe) write(b []byte) (n int, err error) {
 	// One writer at a time.
 	p.wl.Lock()
 	defer p.wl.Unlock()
 	p.data.Write(b)
 	p.rwait.Signal()
 	if p.rclosed {
-		err = os.EPIPE
+		err = io.ErrClosedPipe
 	}
 	if p.werr != nil {
-		err = os.EINVAL
+		err = syscall.EINVAL
 	}
 	n = len(b)
 	return
 	p.rwait.Signal()
 }
 
-func (p *asyncPipe) wclose(err os.Error) {
+func (p *asyncPipe) wclose(err error) {
 	if err == nil {
-		err = os.EOF
+		err = io.EOF
 	}
 	p.l.Lock()
 	defer p.l.Unlock()
 	"compress/zlib"
 	"encoding/binary"
 	"fmt"
-	"http"
 	"io"
-	"os"
+	"net/http"
 	"strings"
 	"sync"
 )
 func (f ControlFrame) GetFlags() FrameFlags { return f.Flags }
 func (f ControlFrame) GetData() []byte      { return f.Data }
 
-func (f ControlFrame) WriteTo(w io.Writer) (n int64, err os.Error) {
-	nn, err := writeFrame(w, []interface{}{uint16(0x8002), f.Type, f.Flags}, f.Data)
+func (f ControlFrame) WriteTo(w io.Writer) (n int64, err error) {
+	nn, err := writeFrame(w, []interface{}{uint16(0x8003), f.Type, f.Flags}, f.Data)
 	return int64(nn), err
 }
 
 func (f DataFrame) GetFlags() FrameFlags { return f.Flags }
 func (f DataFrame) GetData() []byte      { return f.Data }
 
-func (f DataFrame) WriteTo(w io.Writer) (n int64, err os.Error) {
+func (f DataFrame) WriteTo(w io.Writer) (n int64, err error) {
 	nn, err := writeFrame(w, []interface{}{f.StreamID & 0x7fffffff, f.Flags}, f.Data)
 	return int64(nn), err
 }
 const frameHeadSize = 5 // in bytes, excluding length field
 
 // ReadFrame reads an entire frame into memory.
-func ReadFrame(r io.Reader) (f Frame, err os.Error) {
+func ReadFrame(r io.Reader) (f Frame, err error) {
 	headBuffer := new(bytes.Buffer)
-	_, err = io.Copyn(headBuffer, r, frameHeadSize)
+	_, err = io.CopyN(headBuffer, r, frameHeadSize)
 	if err != nil {
 		return
 	}
 	return
 }
 
-func readBinary(r io.Reader, args ...interface{}) (err os.Error) {
+func readBinary(r io.Reader, args ...interface{}) (err error) {
 	for _, a := range args {
 		err = binary.Read(r, binary.BigEndian, a)
 		if err != nil {
 	return
 }
 
-func readData(r io.Reader) (data []byte, err os.Error) {
+func readData(r io.Reader) (data []byte, err error) {
 	lengthField := make([]byte, 3)
 	_, err = io.ReadFull(r, lengthField)
 	if err != nil {
 	if length > 0 {
 		data = make([]byte, int(length))
 		_, err = io.ReadFull(r, data)
+		if err != nil {
+			data = nil
+			return
+		}
 	} else {
 		data = []byte{}
 	}
 	return
 }
 
-func writeFrame(w io.Writer, head []interface{}, data []byte) (n int, err os.Error) {
+func writeFrame(w io.Writer, head []interface{}, data []byte) (n int, err error) {
 	var nn int
 	// Header (40 bits)
 	err = writeBinary(w, head...)
 	return
 }
 
-func writeBinary(r io.Writer, args ...interface{}) (err os.Error) {
+func writeBinary(r io.Writer, args ...interface{}) (err error) {
 	for _, a := range args {
 		err = binary.Write(r, binary.BigEndian, a)
 		if err != nil {
 	return
 }
 
-const headerDictionary = `optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchif-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser-agent100101200201202203204205206300301302303304305306307400401402403404405406407408409410411412413414415416417500501502503504505accept-rangesageetaglocationproxy-authenticatepublicretry-afterservervarywarningwww-authenticateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertransfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locationcontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMondayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSepOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplication/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1.1statusversionurl` + "\x00"
+const headerDictionary = "\x00\x00\x00\x07\x6f\x70\x74\x69\x6f\x6e\x73\x00\x00\x00\x04\x68\x65" +
+	"\x61\x64\x00\x00\x00\x04\x70\x6f\x73\x74\x00\x00\x00\x03\x70\x75\x74" +
+	"\x00\x00\x00\x06\x64\x65\x6c\x65\x74\x65\x00\x00\x00\x05\x74\x72\x61" +
+	"\x63\x65\x00\x00\x00\x06\x61\x63\x63\x65\x70\x74\x00\x00\x00\x0e\x61" +
+	"\x63\x63\x65\x70\x74\x2d\x63\x68\x61\x72\x73\x65\x74\x00\x00\x00\x0f" +
+	"\x61\x63\x63\x65\x70\x74\x2d\x65\x6e\x63\x6f\x64\x69\x6e\x67\x00\x00" +
+	"\x00\x0f\x61\x63\x63\x65\x70\x74\x2d\x6c\x61\x6e\x67\x75\x61\x67\x65" +
+	"\x00\x00\x00\x0d\x61\x63\x63\x65\x70\x74\x2d\x72\x61\x6e\x67\x65\x73" +
+	"\x00\x00\x00\x03\x61\x67\x65\x00\x00\x00\x05\x61\x6c\x6c\x6f\x77\x00" +
+	"\x00\x00\x0d\x61\x75\x74\x68\x6f\x72\x69\x7a\x61\x74\x69\x6f\x6e\x00" +
+	"\x00\x00\x0d\x63\x61\x63\x68\x65\x2d\x63\x6f\x6e\x74\x72\x6f\x6c\x00" +
+	"\x00\x00\x0a\x63\x6f\x6e\x6e\x65\x63\x74\x69\x6f\x6e\x00\x00\x00\x0c" +
+	"\x63\x6f\x6e\x74\x65\x6e\x74\x2d\x62\x61\x73\x65\x00\x00\x00\x10\x63" +
+	"\x6f\x6e\x74\x65\x6e\x74\x2d\x65\x6e\x63\x6f\x64\x69\x6e\x67\x00\x00" +
+	"\x00\x10\x63\x6f\x6e\x74\x65\x6e\x74\x2d\x6c\x61\x6e\x67\x75\x61\x67" +
+	"\x65\x00\x00\x00\x0e\x63\x6f\x6e\x74\x65\x6e\x74\x2d\x6c\x65\x6e\x67" +
+	"\x74\x68\x00\x00\x00\x10\x63\x6f\x6e\x74\x65\x6e\x74\x2d\x6c\x6f\x63" +
+	"\x61\x74\x69\x6f\x6e\x00\x00\x00\x0b\x63\x6f\x6e\x74\x65\x6e\x74\x2d" +
+	"\x6d\x64\x35\x00\x00\x00\x0d\x63\x6f\x6e\x74\x65\x6e\x74\x2d\x72\x61" +
+	"\x6e\x67\x65\x00\x00\x00\x0c\x63\x6f\x6e\x74\x65\x6e\x74\x2d\x74\x79" +
+	"\x70\x65\x00\x00\x00\x04\x64\x61\x74\x65\x00\x00\x00\x04\x65\x74\x61" +
+	"\x67\x00\x00\x00\x06\x65\x78\x70\x65\x63\x74\x00\x00\x00\x07\x65\x78" +
+	"\x70\x69\x72\x65\x73\x00\x00\x00\x04\x66\x72\x6f\x6d\x00\x00\x00\x04" +
+	"\x68\x6f\x73\x74\x00\x00\x00\x08\x69\x66\x2d\x6d\x61\x74\x63\x68\x00" +
+	"\x00\x00\x11\x69\x66\x2d\x6d\x6f\x64\x69\x66\x69\x65\x64\x2d\x73\x69" +
+	"\x6e\x63\x65\x00\x00\x00\x0d\x69\x66\x2d\x6e\x6f\x6e\x65\x2d\x6d\x61" +
+	"\x74\x63\x68\x00\x00\x00\x08\x69\x66\x2d\x72\x61\x6e\x67\x65\x00\x00" +
+	"\x00\x13\x69\x66\x2d\x75\x6e\x6d\x6f\x64\x69\x66\x69\x65\x64\x2d\x73" +
+	"\x69\x6e\x63\x65\x00\x00\x00\x0d\x6c\x61\x73\x74\x2d\x6d\x6f\x64\x69" +
+	"\x66\x69\x65\x64\x00\x00\x00\x08\x6c\x6f\x63\x61\x74\x69\x6f\x6e\x00" +
+	"\x00\x00\x0c\x6d\x61\x78\x2d\x66\x6f\x72\x77\x61\x72\x64\x73\x00\x00" +
+	"\x00\x06\x70\x72\x61\x67\x6d\x61\x00\x00\x00\x12\x70\x72\x6f\x78\x79" +
+	"\x2d\x61\x75\x74\x68\x65\x6e\x74\x69\x63\x61\x74\x65\x00\x00\x00\x13" +
+	"\x70\x72\x6f\x78\x79\x2d\x61\x75\x74\x68\x6f\x72\x69\x7a\x61\x74\x69" +
+	"\x6f\x6e\x00\x00\x00\x05\x72\x61\x6e\x67\x65\x00\x00\x00\x07\x72\x65" +
+	"\x66\x65\x72\x65\x72\x00\x00\x00\x0b\x72\x65\x74\x72\x79\x2d\x61\x66" +
+	"\x74\x65\x72\x00\x00\x00\x06\x73\x65\x72\x76\x65\x72\x00\x00\x00\x02" +
+	"\x74\x65\x00\x00\x00\x07\x74\x72\x61\x69\x6c\x65\x72\x00\x00\x00\x11" +
+	"\x74\x72\x61\x6e\x73\x66\x65\x72\x2d\x65\x6e\x63\x6f\x64\x69\x6e\x67" +
+	"\x00\x00\x00\x07\x75\x70\x67\x72\x61\x64\x65\x00\x00\x00\x0a\x75\x73" +
+	"\x65\x72\x2d\x61\x67\x65\x6e\x74\x00\x00\x00\x04\x76\x61\x72\x79\x00" +
+	"\x00\x00\x03\x76\x69\x61\x00\x00\x00\x07\x77\x61\x72\x6e\x69\x6e\x67" +
+	"\x00\x00\x00\x10\x77\x77\x77\x2d\x61\x75\x74\x68\x65\x6e\x74\x69\x63" +
+	"\x61\x74\x65\x00\x00\x00\x06\x6d\x65\x74\x68\x6f\x64\x00\x00\x00\x03" +
+	"\x67\x65\x74\x00\x00\x00\x06\x73\x74\x61\x74\x75\x73\x00\x00\x00\x06" +
+	"\x32\x30\x30\x20\x4f\x4b\x00\x00\x00\x07\x76\x65\x72\x73\x69\x6f\x6e" +
+	"\x00\x00\x00\x08\x48\x54\x54\x50\x2f\x31\x2e\x31\x00\x00\x00\x03\x75" +
+	"\x72\x6c\x00\x00\x00\x06\x70\x75\x62\x6c\x69\x63\x00\x00\x00\x0a\x73" +
+	"\x65\x74\x2d\x63\x6f\x6f\x6b\x69\x65\x00\x00\x00\x0a\x6b\x65\x65\x70" +
+	"\x2d\x61\x6c\x69\x76\x65\x00\x00\x00\x06\x6f\x72\x69\x67\x69\x6e\x31" +
+	"\x30\x30\x31\x30\x31\x32\x30\x31\x32\x30\x32\x32\x30\x35\x32\x30\x36" +
+	"\x33\x30\x30\x33\x30\x32\x33\x30\x33\x33\x30\x34\x33\x30\x35\x33\x30" +
+	"\x36\x33\x30\x37\x34\x30\x32\x34\x30\x35\x34\x30\x36\x34\x30\x37\x34" +
+	"\x30\x38\x34\x30\x39\x34\x31\x30\x34\x31\x31\x34\x31\x32\x34\x31\x33" +
+	"\x34\x31\x34\x34\x31\x35\x34\x31\x36\x34\x31\x37\x35\x30\x32\x35\x30" +
+	"\x34\x35\x30\x35\x32\x30\x33\x20\x4e\x6f\x6e\x2d\x41\x75\x74\x68\x6f" +
+	"\x72\x69\x74\x61\x74\x69\x76\x65\x20\x49\x6e\x66\x6f\x72\x6d\x61\x74" +
+	"\x69\x6f\x6e\x32\x30\x34\x20\x4e\x6f\x20\x43\x6f\x6e\x74\x65\x6e\x74" +
+	"\x33\x30\x31\x20\x4d\x6f\x76\x65\x64\x20\x50\x65\x72\x6d\x61\x6e\x65" +
+	"\x6e\x74\x6c\x79\x34\x30\x30\x20\x42\x61\x64\x20\x52\x65\x71\x75\x65" +
+	"\x73\x74\x34\x30\x31\x20\x55\x6e\x61\x75\x74\x68\x6f\x72\x69\x7a\x65" +
+	"\x64\x34\x30\x33\x20\x46\x6f\x72\x62\x69\x64\x64\x65\x6e\x34\x30\x34" +
+	"\x20\x4e\x6f\x74\x20\x46\x6f\x75\x6e\x64\x35\x30\x30\x20\x49\x6e\x74" +
+	"\x65\x72\x6e\x61\x6c\x20\x53\x65\x72\x76\x65\x72\x20\x45\x72\x72\x6f" +
+	"\x72\x35\x30\x31\x20\x4e\x6f\x74\x20\x49\x6d\x70\x6c\x65\x6d\x65\x6e" +
+	"\x74\x65\x64\x35\x30\x33\x20\x53\x65\x72\x76\x69\x63\x65\x20\x55\x6e" +
+	"\x61\x76\x61\x69\x6c\x61\x62\x6c\x65\x4a\x61\x6e\x20\x46\x65\x62\x20" +
+	"\x4d\x61\x72\x20\x41\x70\x72\x20\x4d\x61\x79\x20\x4a\x75\x6e\x20\x4a" +
+	"\x75\x6c\x20\x41\x75\x67\x20\x53\x65\x70\x74\x20\x4f\x63\x74\x20\x4e" +
+	"\x6f\x76\x20\x44\x65\x63\x20\x30\x30\x3a\x30\x30\x3a\x30\x30\x20\x4d" +
+	"\x6f\x6e\x2c\x20\x54\x75\x65\x2c\x20\x57\x65\x64\x2c\x20\x54\x68\x75" +
+	"\x2c\x20\x46\x72\x69\x2c\x20\x53\x61\x74\x2c\x20\x53\x75\x6e\x2c\x20" +
+	"\x47\x4d\x54\x63\x68\x75\x6e\x6b\x65\x64\x2c\x74\x65\x78\x74\x2f\x68" +
+	"\x74\x6d\x6c\x2c\x69\x6d\x61\x67\x65\x2f\x70\x6e\x67\x2c\x69\x6d\x61" +
+	"\x67\x65\x2f\x6a\x70\x67\x2c\x69\x6d\x61\x67\x65\x2f\x67\x69\x66\x2c" +
+	"\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x78\x6d\x6c\x2c\x61" +
+	"\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e\x2f\x78\x68\x74\x6d\x6c\x2b" +
+	"\x78\x6d\x6c\x2c\x74\x65\x78\x74\x2f\x70\x6c\x61\x69\x6e\x2c\x74\x65" +
+	"\x78\x74\x2f\x6a\x61\x76\x61\x73\x63\x72\x69\x70\x74\x2c\x70\x75\x62" +
+	"\x6c\x69\x63\x70\x72\x69\x76\x61\x74\x65\x6d\x61\x78\x2d\x61\x67\x65" +
+	"\x3d\x67\x7a\x69\x70\x2c\x64\x65\x66\x6c\x61\x74\x65\x2c\x73\x64\x63" +
+	"\x68\x63\x68\x61\x72\x73\x65\x74\x3d\x75\x74\x66\x2d\x38\x63\x68\x61" +
+	"\x72\x73\x65\x74\x3d\x69\x73\x6f\x2d\x38\x38\x35\x39\x2d\x31\x2c\x75" +
+	"\x74\x66\x2d\x2c\x2a\x2c\x65\x6e\x71\x3d\x30\x2e"
 
 type hrSource struct {
 	r io.Reader
 	c *sync.Cond
 }
 
-func (src *hrSource) Read(p []byte) (n int, err os.Error) {
+func (src *hrSource) Read(p []byte) (n int, err error) {
 	src.m.RLock()
 	for src.r == nil {
 		src.c.Wait()
 	}
 	n, err = src.r.Read(p)
 	src.m.RUnlock()
-	if err == os.EOF {
+	if err == io.EOF {
 		src.change(nil)
 		err = nil
 	}
 }
 
 // ReadHeader reads a set of headers from a reader.
-func (hr *HeaderReader) ReadHeader(r io.Reader) (h http.Header, err os.Error) {
+func (hr *HeaderReader) ReadHeader(r io.Reader) (h http.Header, err 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) {
+func (hr *HeaderReader) Decode(data []byte) (h http.Header, err 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
+func (hr *HeaderReader) read() (h http.Header, err error) {
+	var count uint32
 	if hr.decompressor == nil {
 		hr.decompressor, _ = zlib.NewReaderDict(&hr.source, []byte(headerDictionary))
 		if err != nil {
 		if err != nil {
 			return
 		}
-		valueList := strings.Split(string(value), "\x00", -1)
+		valueList := strings.Split(string(value), "\x00")
 		for _, v := range valueList {
 			h.Add(name, v)
 		}
 	return
 }
 
-func readHeaderString(r io.Reader) (s string, err os.Error) {
-	var length uint16
+func readHeaderString(r io.Reader) (s string, err error) {
+	var length uint32
 	err = binary.Read(r, binary.BigEndian, &length)
 	if err != nil {
 		return
 // 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))
+	hw.compressor, _ = zlib.NewWriterLevelDict(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) {
+func (hw *HeaderWriter) WriteHeader(w io.Writer, h http.Header) (err error) {
 	hw.write(h)
 	_, err = io.Copy(w, hw.buffer)
 	hw.buffer.Reset()
 }
 
 func (hw *HeaderWriter) write(h http.Header) {
-	binary.Write(hw.compressor, binary.BigEndian, uint16(len(h)))
+	binary.Write(hw.compressor, binary.BigEndian, uint32(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, uint32(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, uint32(len(v)))
 		binary.Write(hw.compressor, binary.BigEndian, []byte(v))
 	}
 	hw.compressor.Flush()
 	"crypto/rand"
 	"crypto/tls"
 	"encoding/binary"
-	"http"
+	"errors"
 	"io"
 	"net"
-	"os"
+	"net/http"
+	"net/url"
 	"strconv"
 	"time"
 )
 
+const (
+	statusHeader  = ":status"
+	methodHeader  = ":method"
+	versionHeader = ":version"
+	pathHeader    = ":path"
+)
+
 // ListenAndServe creates a new Server that serves on the given address.  If
 // the handler is nil, then http.DefaultServeMux is used.
-func ListenAndServe(addr string, handler http.Handler) os.Error {
+func ListenAndServe(addr string, handler http.Handler) error {
 	srv := &Server{addr, handler}
 	return srv.ListenAndServe()
 }
 
 // ListenAndServeTLS acts like ListenAndServe except it uses TLS.
-func ListenAndServeTLS(addr string, certFile, keyFile string, handler http.Handler) (err os.Error) {
+func ListenAndServeTLS(addr string, certFile, keyFile string, handler http.Handler) (err error) {
 	config := &tls.Config{
 		Rand:         rand.Reader,
-		Time:         time.Seconds,
-		NextProtos:   []string{"http/1.1"},
+		Time:         time.Now,
+		NextProtos:   []string{"spdy/3", "http/1.1"},
 		Certificates: make([]tls.Certificate, 1),
 	}
 	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
 
 // ListenAndServe services SPDY requests on the given address.
 // If the handler is nil, then http.DefaultServeMux is used.
-func (srv *Server) ListenAndServe() os.Error {
+func (srv *Server) ListenAndServe() error {
 	addr := srv.Addr
 	if addr == "" {
 		addr = ":http"
 
 // ListenAndServe services SPDY requests using the given listener.
 // If the handler is nil, then http.DefaultServeMux is used.
-func (srv *Server) Serve(l net.Listener) os.Error {
+func (srv *Server) Serve(l net.Listener) error {
 	defer l.Close()
 	handler := srv.Handler
 	if handler == nil {
 
 // A session manages a single TCP connection to a client.
 type session struct {
-	c       net.Conn
-	handler http.Handler
-	in, out chan Frame
-	streams map[uint32]*serverStream // all access is done synchronously
+	c         net.Conn
+	handler   http.Handler
+	out       chan Frame
+	streams   map[uint32]*serverStream // all access is done synchronously
+	last_good uint32
 
 	headerReader *HeaderReader
 	headerWriter *HeaderWriter
 }
 
-func newSession(c net.Conn, h http.Handler) (s *session, err os.Error) {
+func newSession(c net.Conn, h http.Handler) (s *session, err error) {
 	s = &session{
 		c:            c,
 		handler:      h,
 		headerReader: NewHeaderReader(),
 		headerWriter: NewHeaderWriter(-1),
-		in:           make(chan Frame),
 		out:          make(chan Frame),
 		streams:      make(map[uint32]*serverStream),
+		last_good:    0,
 	}
 	return
 }
 
 func (sess *session) serve() {
 	defer sess.c.Close()
-	go sess.sendFrames()
 	go sess.receiveFrames()
 
-	for {
-		select {
-		case f := <-sess.in:
-			switch frame := f.(type) {
-			case ControlFrame:
-				sess.handleControl(frame)
-			case DataFrame:
-				sess.handleData(frame)
-			}
+	for frame := range sess.out {
+
+		if frame == nil {
+			// EOF, signalling end of session
+			// initiated by us (on errors, etc.)
+			return
 		}
+
+		// TODO: Check for errors
+		frame.WriteTo(sess.c)
 	}
 }
 
+func (sess *session) fail() {
+	sess.out <- ControlFrame{
+		Type: TypeGoaway,
+		Data: []byte{
+			byte(sess.last_good & 0x7f000000 >> 24),
+			byte(sess.last_good & 0x00ff0000 >> 16),
+			byte(sess.last_good & 0x0000ff00 >> 8),
+			byte(sess.last_good & 0x000000ff >> 0),
+			byte(0), byte(0), byte(0), byte(0),
+		},
+	}
+	sess.out <- nil
+}
+
 func (sess *session) handleControl(frame ControlFrame) {
 	switch frame.Type {
 	case TypeSynStream:
-		if stream, err := newServerStream(sess, frame); err == nil {
-			if _, exists := sess.streams[stream.id]; !exists {
-				sess.streams[stream.id] = stream
-				go func() {
-					sess.handler.ServeHTTP(stream, stream.Request())
-					stream.finish()
+		stream, err := newServerStream(sess, frame)
+		if err == nil && stream.id%2 == 0 {
+			err = errors.New("Invalid stream id")
+		}
+
+		if err == nil {
+			sess.last_good = stream.id
+			sess.streams[stream.id] = stream
+			go func() {
+				defer func() {
+					if r := recover(); r != nil {
+						stream.session.fail()
+					}
 				}()
-			}
+				sess.handler.ServeHTTP(stream, stream.Request())
+				stream.finish()
+			}()
+		} else {
+			sess.fail()
 		}
 	case TypeRstStream:
 		d := bytes.NewBuffer(frame.Data)
 	}
 }
 
-func (sess *session) sendFrames() {
-	for frame := range sess.out {
-		// TODO: Check for errors
-		frame.WriteTo(sess.c)
-	}
-}
-
 func (sess *session) receiveFrames() {
-	defer close(sess.in)
+	defer func() {
+		if r := recover(); r != nil {
+			sess.fail()
+		}
+	}()
 	for {
-		frame, err := ReadFrame(sess.c)
+		f, err := ReadFrame(sess.c)
 		if err != nil {
 			return
 		}
-		sess.in <- frame
+
+		if f == nil {
+			// EOF, signalling end of session
+			return
+		}
+		switch frame := f.(type) {
+		case ControlFrame:
+			sess.handleControl(frame)
+		case DataFrame:
+			sess.handleData(frame)
+		}
 	}
 }
 
 	dataPipe *asyncPipe
 }
 
-func newServerStream(sess *session, frame ControlFrame) (st *serverStream, err os.Error) {
+func newServerStream(sess *session, frame ControlFrame) (st *serverStream, err error) {
 	if frame.Type != TypeSynStream {
-		err = os.NewError("Server stream must be created from a SynStream frame")
+		err = errors.New("Server stream must be created from a SynStream frame")
 		return
 	}
 	st = &serverStream{
 		return
 	}
 	st.requestHeaders, err = sess.headerReader.Decode(data.Bytes())
+	if err != nil {
+		return
+	}
+
+	if st.requestHeaders.Get(methodHeader) == "" {
+		err = errors.New("Missing method header")
+	} else if st.requestHeaders.Get(versionHeader) == "" {
+		err = errors.New("Missing version header")
+	} else if st.requestHeaders.Get(pathHeader) == "" {
+		err = errors.New("Missing path header")
+	}
+
 	return
 }
 
 func (st *serverStream) Request() (req *http.Request) {
 	// TODO: Add more info
 	req = &http.Request{
-		Method:     st.requestHeaders.Get("method"),
-		RawURL:     st.requestHeaders.Get("url"),
-		Proto:      st.requestHeaders.Get("version"),
+		Method:     st.requestHeaders.Get(methodHeader),
+		Proto:      st.requestHeaders.Get(versionHeader),
 		Header:     st.requestHeaders,
 		Body:       st,
 		RemoteAddr: st.session.c.RemoteAddr().String(),
 	}
-	req.URL, _ = http.ParseRequestURL(req.RawURL)
+	req.URL, _ = url.ParseRequestURI(st.requestHeaders.Get(pathHeader))
 	return
 }
 
-func (st *serverStream) Read(p []byte) (n int, err os.Error) {
+func (st *serverStream) Read(p []byte) (n int, err error) {
 	return st.dataPipe.read(p)
 }
 
 // Header returns the current response headers.
 func (st *serverStream) Header() http.Header { return st.responseHeaders }
 
-func (st *serverStream) Write(p []byte) (n int, err os.Error) {
+func (st *serverStream) Write(p []byte) (n int, err error) {
 	if st.closed {
-		err = os.NewError("Write on closed serverStream")
+		err = errors.New("Write on closed serverStream")
 		return
 	}
 	if !st.wroteHeader {
 func (frame synReplyFrame) GetData() []byte {
 	buf := new(bytes.Buffer)
 	binary.Write(buf, binary.BigEndian, frame.stream.id&0x7fffffff)
-	buf.Write([2]byte{}[:])
 	frame.stream.session.headerWriter.WriteHeader(buf, frame.stream.responseHeaders)
 	return buf.Bytes()
 }
 
-func (frame synReplyFrame) WriteTo(w io.Writer) (n int64, err os.Error) {
+func (frame synReplyFrame) WriteTo(w io.Writer) (n int64, err error) {
 	cf := ControlFrame{Type: TypeSynReply, Data: frame.GetData()}
 	return cf.WriteTo(w)
 }
 	if st.wroteHeader {
 		return
 	}
-	st.responseHeaders.Set("status", strconv.Itoa(code)+" "+http.StatusText(code))
-	st.responseHeaders.Set("version", "HTTP/1.1")
+	st.responseHeaders.Set(statusHeader, strconv.Itoa(code)+" "+http.StatusText(code))
+	st.responseHeaders.Set(versionHeader, "HTTP/1.1")
 	if st.responseHeaders.Get("Content-Type") == "" {
 		st.responseHeaders.Set("Content-Type", "text/html; charset=utf-8")
 	}
 	if st.responseHeaders.Get("Date") == "" {
-		st.responseHeaders.Set("Date", time.UTC().Format(http.TimeFormat))
+		st.responseHeaders.Set("Date", time.Now().UTC().Format(http.TimeFormat))
 	}
 	// Write the frame
 	// TODO: Copy headers
 
 // Close sends a closing frame, thus preventing the server from sending more
 // data over the stream.  The client may still send data.
-func (st *serverStream) Close() (err os.Error) {
+func (st *serverStream) Close() (err error) {
 	if st.closed {
 		return
 	}
 	return nil
 }
 
-func (st *serverStream) finish() (err os.Error) {
+func (st *serverStream) finish() (err error) {
 	if !st.wroteHeader {
 		st.WriteHeader(http.StatusOK)
 	}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.