100 lines
2 KiB
Go
100 lines
2 KiB
Go
package phpfpm
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// Create an fcgi client
|
|
func newFcgiClient(timeout time.Duration, h string, args ...interface{}) (*conn, error) {
|
|
var con net.Conn
|
|
if len(args) != 1 {
|
|
return nil, errors.New("fcgi: not enough params")
|
|
}
|
|
|
|
var err error
|
|
switch args[0].(type) {
|
|
case int:
|
|
addr := h + ":" + strconv.FormatInt(int64(args[0].(int)), 10)
|
|
if timeout == 0 {
|
|
con, err = net.Dial("tcp", addr)
|
|
} else {
|
|
con, err = net.DialTimeout("tcp", addr, timeout)
|
|
}
|
|
case string:
|
|
laddr := net.UnixAddr{Name: args[0].(string), Net: h}
|
|
con, err = net.DialUnix(h, nil, &laddr)
|
|
default:
|
|
return nil, errors.New("fcgi: we only accept int (port) or string (socket) params")
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if timeout != 0 {
|
|
if err := con.SetDeadline(time.Now().Add(timeout)); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return &conn{rwc: con}, nil
|
|
}
|
|
|
|
func (c *conn) request(env map[string]string, requestData string) (retout, reterr []byte, err error) {
|
|
defer c.rwc.Close()
|
|
var reqID uint16 = 1
|
|
|
|
err = c.writeBeginRequest(reqID, uint16(roleResponder), 0)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
err = c.writePairs(typeParams, reqID, env)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
if len(requestData) > 0 {
|
|
if err := c.writeRecord(typeStdin, reqID, []byte(requestData)); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
|
|
rec := &record{}
|
|
var err1 error
|
|
|
|
// receive until EOF or FCGI_END_REQUEST
|
|
READ_LOOP:
|
|
for {
|
|
err1 = rec.read(c.rwc)
|
|
if err1 != nil && strings.Contains(err1.Error(), "use of closed network connection") {
|
|
if !errors.Is(err1, io.EOF) {
|
|
err = err1
|
|
}
|
|
break
|
|
}
|
|
if err1 != nil && strings.Contains(err1.Error(), "i/o timeout") {
|
|
if !errors.Is(err1, io.EOF) {
|
|
err = err1
|
|
}
|
|
break
|
|
}
|
|
|
|
switch rec.h.Type {
|
|
case typeStdout:
|
|
retout = append(retout, rec.content()...)
|
|
case typeStderr:
|
|
reterr = append(reterr, rec.content()...)
|
|
case typeEndRequest:
|
|
fallthrough
|
|
default:
|
|
break READ_LOOP
|
|
}
|
|
}
|
|
|
|
return retout, reterr, err
|
|
}
|