URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [net/] [http/] [fcgi/] [fcgi.go] - Rev 747
Compare with Previous | Blame | View Log
// 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 fcgi implements the FastCGI protocol.// Currently only the responder role is supported.// The protocol is defined at http://www.fastcgi.com/drupal/node/6?q=node/22package fcgi// This file defines the raw protocol and some utilities used by the child and// the host.import ("bufio""bytes""encoding/binary""errors""io""sync")// recType is a record type, as defined by// http://www.fastcgi.com/devkit/doc/fcgi-spec.html#S8type recType uint8const (typeBeginRequest recType = 1typeAbortRequest recType = 2typeEndRequest recType = 3typeParams recType = 4typeStdin recType = 5typeStdout recType = 6typeStderr recType = 7typeData recType = 8typeGetValues recType = 9typeGetValuesResult recType = 10typeUnknownType recType = 11)// keep the connection between web-server and responder open after requestconst flagKeepConn = 1const (maxWrite = 65535 // maximum record bodymaxPad = 255)const (roleResponder = iota + 1 // only Responders are implemented.roleAuthorizerroleFilter)const (statusRequestComplete = iotastatusCantMultiplexstatusOverloadedstatusUnknownRole)const headerLen = 8type header struct {Version uint8Type recTypeId uint16ContentLength uint16PaddingLength uint8Reserved uint8}type beginRequest struct {role uint16flags uint8reserved [5]uint8}func (br *beginRequest) read(content []byte) error {if len(content) != 8 {return errors.New("fcgi: invalid begin request record")}br.role = binary.BigEndian.Uint16(content)br.flags = content[2]return nil}// for padding so we don't have to allocate all the time// not synchronized because we don't care what the contents arevar pad [maxPad]bytefunc (h *header) init(recType recType, reqId uint16, contentLength int) {h.Version = 1h.Type = recTypeh.Id = reqIdh.ContentLength = uint16(contentLength)h.PaddingLength = uint8(-contentLength & 7)}// conn sends records over rwctype conn struct {mutex sync.Mutexrwc io.ReadWriteCloser// to avoid allocationsbuf bytes.Bufferh header}func newConn(rwc io.ReadWriteCloser) *conn {return &conn{rwc: rwc}}func (c *conn) Close() error {c.mutex.Lock()defer c.mutex.Unlock()return c.rwc.Close()}type record struct {h headerbuf [maxWrite + maxPad]byte}func (rec *record) read(r io.Reader) (err error) {if err = binary.Read(r, binary.BigEndian, &rec.h); err != nil {return err}if rec.h.Version != 1 {return errors.New("fcgi: invalid header version")}n := int(rec.h.ContentLength) + int(rec.h.PaddingLength)if _, err = io.ReadFull(r, rec.buf[:n]); err != nil {return err}return nil}func (r *record) content() []byte {return r.buf[:r.h.ContentLength]}// writeRecord writes and sends a single record.func (c *conn) writeRecord(recType recType, reqId uint16, b []byte) error {c.mutex.Lock()defer c.mutex.Unlock()c.buf.Reset()c.h.init(recType, reqId, len(b))if err := binary.Write(&c.buf, binary.BigEndian, c.h); err != nil {return err}if _, err := c.buf.Write(b); err != nil {return err}if _, err := c.buf.Write(pad[:c.h.PaddingLength]); err != nil {return err}_, err := c.rwc.Write(c.buf.Bytes())return err}func (c *conn) writeBeginRequest(reqId uint16, role uint16, flags uint8) error {b := [8]byte{byte(role >> 8), byte(role), flags}return c.writeRecord(typeBeginRequest, reqId, b[:])}func (c *conn) writeEndRequest(reqId uint16, appStatus int, protocolStatus uint8) error {b := make([]byte, 8)binary.BigEndian.PutUint32(b, uint32(appStatus))b[4] = protocolStatusreturn c.writeRecord(typeEndRequest, reqId, b)}func (c *conn) writePairs(recType recType, reqId uint16, pairs map[string]string) error {w := newWriter(c, recType, reqId)b := make([]byte, 8)for k, v := range pairs {n := encodeSize(b, uint32(len(k)))n += encodeSize(b[n:], uint32(len(v)))if _, err := w.Write(b[:n]); err != nil {return err}if _, err := w.WriteString(k); err != nil {return err}if _, err := w.WriteString(v); err != nil {return err}}w.Close()return nil}func readSize(s []byte) (uint32, int) {if len(s) == 0 {return 0, 0}size, n := uint32(s[0]), 1if size&(1<<7) != 0 {if len(s) < 4 {return 0, 0}n = 4size = binary.BigEndian.Uint32(s)size &^= 1 << 31}return size, n}func readString(s []byte, size uint32) string {if size > uint32(len(s)) {return ""}return string(s[:size])}func encodeSize(b []byte, size uint32) int {if size > 127 {size |= 1 << 31binary.BigEndian.PutUint32(b, size)return 4}b[0] = byte(size)return 1}// bufWriter encapsulates bufio.Writer but also closes the underlying stream when// Closed.type bufWriter struct {closer io.Closer*bufio.Writer}func (w *bufWriter) Close() error {if err := w.Writer.Flush(); err != nil {w.closer.Close()return err}return w.closer.Close()}func newWriter(c *conn, recType recType, reqId uint16) *bufWriter {s := &streamWriter{c: c, recType: recType, reqId: reqId}w := bufio.NewWriterSize(s, maxWrite)return &bufWriter{s, w}}// streamWriter abstracts out the separation of a stream into discrete records.// It only writes maxWrite bytes at a time.type streamWriter struct {c *connrecType recTypereqId uint16}func (w *streamWriter) Write(p []byte) (int, error) {nn := 0for len(p) > 0 {n := len(p)if n > maxWrite {n = maxWrite}if err := w.c.writeRecord(w.recType, w.reqId, p[:n]); err != nil {return nn, err}nn += np = p[n:]}return nn, nil}func (w *streamWriter) Close() error {// send empty record to close the streamreturn w.c.writeRecord(w.recType, w.reqId, nil)}
