func (h Handler) buildEnv(r *http.Request, rule Rule, fpath string) (map[string]string, error) {
	var env map[string]string
	var ip, port string
	if idx := strings.LastIndex(r.RemoteAddr, ":"); idx > -1 {
		ip = r.RemoteAddr[:idx]
		port = r.RemoteAddr[idx+1:]
	} else {
		ip = r.RemoteAddr
	}
	ip = strings.Replace(ip, "[", "", 1)
	ip = strings.Replace(ip, "]", "", 1)
	splitPos := rule.splitPos(fpath)
	docURI := fpath[:splitPos+len(rule.SplitPath)]
	pathInfo := fpath[splitPos+len(rule.SplitPath):]
	scriptName := fpath
	scriptName = strings.TrimSuffix(scriptName, pathInfo)
	scriptFilename := filepath.Join(rule.Root, scriptName)
	pathPrefix, _ := r.Context().Value(casket.CtxKey("path_prefix")).(string)
	scriptName = path.Join(pathPrefix, scriptName)
	reqURL, _ := r.Context().Value(httpserver.OriginalURLCtxKey).(url.URL)
	remoteUser, _ := r.Context().Value(httpserver.RemoteUserCtxKey).(string)
	requestScheme := "http"
	if r.TLS != nil {
		requestScheme = "https"
	}
	env = map[string]string{
		"AUTH_TYPE":         "",  
		"CONTENT_LENGTH":    r.Header.Get("Content-Length"),
		"CONTENT_TYPE":      r.Header.Get("Content-Type"),
		"GATEWAY_INTERFACE": "CGI/1.1",
		"PATH_INFO":         pathInfo,
		"QUERY_STRING":      r.URL.RawQuery,
		"REMOTE_ADDR":       ip,
		"REMOTE_HOST":       ip,  
		"REMOTE_PORT":       port,
		"REMOTE_IDENT":      "",  
		"REMOTE_USER":       remoteUser,
		"REQUEST_METHOD":    r.Method,
		"REQUEST_SCHEME":    requestScheme,
		"SERVER_NAME":       h.ServerName,
		"SERVER_PORT":       h.ServerPort,
		"SERVER_PROTOCOL":   r.Proto,
		"SERVER_SOFTWARE":   h.SoftwareName + "/" + h.SoftwareVersion,
		"DOCUMENT_ROOT":   rule.Root,
		"DOCUMENT_URI":    docURI,
		"HTTP_HOST":       r.Host,  
		"REQUEST_URI":     reqURL.RequestURI(),
		"SCRIPT_FILENAME": scriptFilename,
		"SCRIPT_NAME":     scriptName,
	}
	if env["PATH_INFO"] != "" {
		env["PATH_TRANSLATED"] = filepath.Join(rule.Root, pathInfo)  
	}
	if r.TLS != nil {
		env["HTTPS"] = "on"
		v, ok := tlsProtocolStringToMap[r.TLS.Version]
		if ok {
			env["SSL_PROTOCOL"] = v
		}
		for k, v := range caskettls.SupportedCiphersMap {
			if v == r.TLS.CipherSuite {
				env["SSL_CIPHER"] = k
				break
			}
		}
	}
	replacer := httpserver.NewReplacer(r, nil, "")
	for _, envVar := range rule.EnvVars {
		env[envVar[0]] = replacer.Replace(envVar[1])
	}
	for field, val := range r.Header {
		header := strings.ToUpper(field)
		header = headerNameReplacer.Replace(header)
		env["HTTP_"+header] = strings.Join(val, ", ")
	}
	return env, nil
}
buildEnv returns a set of CGI environment variables for the request.
package fastcgi
import (
	"context"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"sync/atomic"
	"time"
	"crypto/tls"
	"github.com/tmpim/casket"
	"github.com/tmpim/casket/caskettls"
	"github.com/tmpim/casket/caskethttp/httpserver"
)
type Handler struct {
	Next    httpserver.Handler
	Rules   []Rule
	Root    string
	FileSys http.FileSystem
	SoftwareName    string
	SoftwareVersion string
	ServerName      string
	ServerPort      string
}
func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
	for _, rule := range h.Rules {
		hpath := httpserver.Path(r.URL.Path)
		if !hpath.Matches(rule.Path) {
			if strings.HasPrefix(string(hpath), "/") {
				continue
			}
			hpath = httpserver.Path("/" + string(hpath))  
			if !hpath.Matches(rule.Path) {
				continue
			}
		}
		if !rule.AllowedPath(r.URL.Path) {
			continue
		}
		fpath := r.URL.Path
		fpath = strings.TrimRight(fpath, " .")
		if idx, ok := httpserver.IndexFile(h.FileSys, fpath, rule.IndexFiles); ok {
			fpath = idx
			if !rule.canSplit(fpath) {
				return http.StatusInternalServerError, ErrIndexMissingSplit
			}
		} else {
			if !rule.canSplit(fpath) {
				continue
			}
		}
		if !h.exists(fpath) || fpath[len(fpath)-1] == '/' || strings.HasSuffix(strings.ToLower(fpath), strings.ToLower(rule.Ext)) {
			env, err := h.buildEnv(r, rule, fpath)
			if err != nil {
				return http.StatusInternalServerError, err
			}
			address, err := rule.Address()
			if err != nil {
				return http.StatusBadGateway, err
			}
			network, address := parseAddress(address)
			ctx := context.Background()
			if rule.ConnectTimeout > 0 {
				var cancel context.CancelFunc
				ctx, cancel = context.WithTimeout(ctx, rule.ConnectTimeout)
				defer cancel()
			}
			fcgiBackend, err := DialContext(ctx, network, address)
			if err != nil {
				return http.StatusBadGateway, err
			}
			defer fcgiBackend.Close()
			if err := fcgiBackend.SetReadTimeout(rule.ReadTimeout); err != nil {
				return http.StatusInternalServerError, err
			}
			if err := fcgiBackend.SetSendTimeout(rule.SendTimeout); err != nil {
				return http.StatusInternalServerError, err
			}
			var resp *http.Response
			var contentLength int64
			if r.ContentLength > 0 {
				contentLength = r.ContentLength
			} else {
				contentLength, _ = strconv.ParseInt(r.Header.Get("Content-Length"), 10, 64)
			}
			switch r.Method {
			case "HEAD":
				resp, err = fcgiBackend.Head(env)
			case "GET":
				resp, err = fcgiBackend.Get(env, r.Body, contentLength)
			case "OPTIONS":
				resp, err = fcgiBackend.Options(env)
			default:
				resp, err = fcgiBackend.Post(env, r.Method, r.Header.Get("Content-Type"), r.Body, contentLength)
			}
			if resp != nil && resp.Body != nil {
				defer resp.Body.Close()
			}
			if err != nil {
				if err, ok := err.(net.Error); ok && err.Timeout() {
					return http.StatusGatewayTimeout, err
				} else if err != io.EOF {
					return http.StatusBadGateway, err
				}
			}
			writeHeader(w, resp)
			_, err = io.Copy(w, resp.Body)
			if err != nil {
				return http.StatusBadGateway, err
			}
			if fcgiBackend.stderr.Len() != 0 {
				err = LogError(strings.TrimSuffix(fcgiBackend.stderr.String(), "\n"))
			}
			return 0, err
		}
	}
	return h.Next.ServeHTTP(w, r)
}
func parseAddress(fcgiAddress string) (string, string) {
	if strings.HasPrefix(fcgiAddress, "tcp://") {
		return "tcp", fcgiAddress[len("tcp://"):]
	}
	if strings.HasPrefix(fcgiAddress, "fastcgi://") {
		return "tcp", fcgiAddress[len("fastcgi://"):]
	}
	if trim := strings.HasPrefix(fcgiAddress, "unix"); strings.HasPrefix(fcgiAddress, "/") || trim {
		if trim {
			return "unix", fcgiAddress[len("unix:"):]
		}
		return "unix", fcgiAddress
	}
	return "tcp", fcgiAddress
}
func writeHeader(w http.ResponseWriter, r *http.Response) {
	for key, vals := range r.Header {
		for _, val := range vals {
			w.Header().Add(key, val)
		}
	}
	w.WriteHeader(r.StatusCode)
}
func (h Handler) exists(path string) bool {
	if _, err := os.Stat(h.Root + path); err == nil {
		return true
	}
	return false
}