package fastcgi import ( "bufio" "encoding/binary" "fmt" "io" "net" ) type FCGIRequestType uint8 const FCGI_LISTENSOCK_FILENO uint8 = 0 const FCGI_HEADER_LEN uint8 = 8 const VERSION_1 uint8 = 1 const FCGI_NULL_REQUEST_ID uint8 = 0 const FCGI_KEEP_CONN uint8 = 1 const doubleCRLF = "\r\n\r\n" const ( FCGI_BEGIN_REQUEST FCGIRequestType = iota + 1 FCGI_ABORT_REQUEST FCGI_END_REQUEST FCGI_PARAMS FCGI_STDIN FCGI_STDOUT FCGI_STDERR FCGI_DATA FCGI_GET_VALUES FCGI_GET_VALUES_RESULT FCGI_UNKNOWN_TYPE FCGI_MAXTYPE = FCGI_UNKNOWN_TYPE ) const ( FCGI_RESPONDER uint8 = iota + 1 FCGI_AUTHORIZER FCGI_FILTER ) const ( FCGI_REQUEST_COMPLETE uint8 = iota FCGI_CANT_MPX_CONN FCGI_OVERLOADED FCGI_UNKNOWN_ROLE ) const ( FCGI_MAX_CONNS string = "MAX_CONNS" FCGI_MAX_REQS string = "MAX_REQS" FCGI_MPXS_CONNS string = "MPXS_CONNS" ) const ( maxWrite = 65500 // 65530 may work, but for compatibility maxPad = 255 ) // Connects to the fcgi responder at the specified network address. // See func net.Dial for a description of the network and address parameters. func Dial(network, address string) (fcgi *FCGIClient, err error) { var conn net.Conn conn, err = net.Dial(network, address) if err != nil { return } fcgi = &FCGIClient{ rwc: conn, keepAlive: false, reqId: 1, } return } func readSize(s []byte) (uint32, int) { if len(s) == 0 { return 0, 0 } size, n := uint32(s[0]), 1 if size&(1<<7) != 0 { if len(s) < 4 { return 0, 0 } n = 4 size = 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 << 31 binary.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 *FCGIClient, recType FCGIRequestType) *bufWriter { s := &streamWriter{c: c, recType: recType} w := bufio.NewWriterSize(s, maxWrite) return &bufWriter{s, w} } type badStringError struct { what string str string } func (e *badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) } // Checks whether chunked is part of the encodings stack func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }