89 lines
2.1 KiB
Go
89 lines
2.1 KiB
Go
package fastcgi
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
)
|
|
|
|
// for padding so we don't have to allocate all the time
|
|
// not synchronized because we don't care what the contents are
|
|
var pad [maxPad]byte
|
|
|
|
// A record is essentially a "packet" in FastCGI.
|
|
// The header lets the server know what type
|
|
// of data is being sent, and it expects
|
|
// a certain structure depending on
|
|
// the type.
|
|
type Header struct {
|
|
Version uint8
|
|
Type FCGIRecordType
|
|
Id uint16
|
|
ContentLength uint16
|
|
PaddingLength uint8
|
|
Reserved uint8
|
|
}
|
|
|
|
type Record struct {
|
|
Header Header
|
|
Content []byte
|
|
ReadBuffer []byte // Buffer to use when reading a response
|
|
}
|
|
|
|
// Turn a record into a byte array so it can be
|
|
// sent over the network. The byte array will
|
|
// be in the shape/order that is expected
|
|
// in the FastCGI protocol.
|
|
func (r *Record) toBytes() ([]byte, error) {
|
|
var buf bytes.Buffer
|
|
|
|
if err := binary.Write(&buf, binary.BigEndian, r.Header); err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err := buf.Write(r.Content); err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err := buf.Write(pad[:r.Header.PaddingLength]); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
func (req *FCGIRequest) NewRecord(t FCGIRecordType, content []byte) *Record {
|
|
r := Record{}
|
|
|
|
r.Header.Version = 1
|
|
r.Header.Type = t
|
|
r.Header.Id = req.Id
|
|
r.Header.ContentLength = uint16(len(content))
|
|
r.Header.PaddingLength = 0
|
|
r.Content = content
|
|
|
|
return &r
|
|
}
|
|
|
|
// FCGI_BEGIN_REQUEST record should
|
|
// have a body of 8 bytes with:
|
|
// - The first byte being the role
|
|
// - The second byte being also the role
|
|
// - The third byte being the flags
|
|
// - The last five bytes are reserved for future use
|
|
func (req *FCGIRequest) NewBeginRequestRecord() *Record {
|
|
role := uint16(FCGI_RESPONDER)
|
|
flags := byte(0)
|
|
// Create an 8-byte array as per the FastCGI specification.
|
|
var b [8]byte
|
|
|
|
// Split the 16-bit role into two bytes and assign them.
|
|
b[0] = byte(role >> 8) // High byte
|
|
b[1] = byte(role) // Low byte
|
|
|
|
// Set the flags.
|
|
b[2] = flags
|
|
|
|
// The reserved bytes (b[3] to b[7]) will remain zero by default.
|
|
|
|
// Return a begin request record
|
|
return req.NewRecord(FCGI_BEGIN_REQUEST, b[:])
|
|
}
|