rewrite proxy part

new
fangdingjun 6 years ago
parent 15d3e5d050
commit 4debfbd3b8

@ -1,48 +1,41 @@
package main
import (
"github.com/go-yaml/yaml"
"io/ioutil"
"github.com/go-yaml/yaml"
)
type conf []server
type conf struct {
Listens []listen `yaml:"listen"`
Vhosts []vhost `yaml:"vhost"`
Proxy proxycfg `yaml:"proxy"`
}
type server struct {
Host string
Port int
Docroot string
URLRules []rule
EnableProxy bool
EnableAuth bool
PasswdFile string
Realm string
Vhost []vhost
type proxycfg struct {
HTTP1Proxy bool `yaml:"http1-proxy"`
HTTP2Proxy bool `yaml:"http2-proxy"`
LocalDomains []string `yaml:"localdomains"`
}
type vhost struct {
Docroot string
Hostname string
Cert string
Key string
URLRules []rule
type listen struct {
Addr string `yaml:"addr"`
Port int16 `yaml:"port"`
Certificates []certificate `yaml:"certificates"`
}
type rule struct {
URLPrefix string
IsRegex bool
Docroot string
Type string
Target target
type certificate struct {
CertFile string `yaml:"certfile"`
KeyFile string `yaml:"keyfile"`
}
type target struct {
Type string
Host string
Port int
Path string
type vhost struct {
Docroot string `yaml:"docroot"`
Hostname string `yaml:"hostname"`
ProxyPass string `yaml:"proxypass"`
}
func loadConfig(fn string) (conf, error) {
func loadConfig(fn string) (*conf, error) {
data, err := ioutil.ReadFile(fn)
if err != nil {
return nil, err
@ -53,5 +46,5 @@ func loadConfig(fn string) (conf, error) {
return nil, err
}
return c, nil
return &c, nil
}

@ -1,145 +1,33 @@
# vim: set ft=yaml:
# when provide certficate file, server will listen https and enable http2
# http config
listen:
-
# listen address
host: 0.0.0.0
# listen port
addr: 0.0.0.0
port: 9001
certificates:
-
addr: 0.0.0.0
port: 9002
certificates:
-
certfile: /etc/letsencrypt/live/ratafee.nl/fullchain.pem
keyfile: /etc/letsencrypt/live/ratafee.nl/privkey.pem
# default document root
# virtual host support
vhost:
-
hostname: www.ratafee.nl
docroot: /srv/www
enableproxy: true
enableauth: true
passwdfile: ./passwdfile
realm: example.com
# default host's url rule
# urlrules:
# -
# urlprefix: /a
# type: alias
# target:
# type: dir
# path: /home/user1/a
# -
# urlprefix: /b/a.txt
# type: alias
# target:
# type: file
# path: /home/user1/a/b/a.txt
# virtual host config
# vhost:
# - &example1_www
# hostname: www.example1.com
# docroot: /var/www/html/
# # cert:
# # key:
#
# # url rule for www.example.com
# urlrules:
# -
# # url start with /APIv1/ forward to uwsg socket
# urlprefix: /APIv1/
# type: uwsgi
# target:
# type: unix
# path: /run/uwsgi/APIv1.sock
# -
# # run php script on /phpmyadmin/ subdirectory
# urlprefix: /phpmyadmin/
# type: fastcgi
# target:
# type: unix
# path: /var/run/php-fpm/www.sock
# -
# # pass php to fastcgi socket
# urlprefix: \.php$|\.php/.*
# isregex: true
# type: fastcgi
# target:
# type: unix
# path: /var/run/php-fpm/www.sock
# -
# # run php script on other location
# urlprefix: /a/
# docroot: /home/user/php
# type: fastcgi
# target:
# type: unix
# path: /var/run/php-fpm/www.sock
# -
# # url start with /proxy/ reverse proxy for http://10.10.1.1/
# # this act as reverse proxy
# urlprefix: /proxy/
# type: reverse
# target:
# type: http
# host: 10.10.1.1
# port: 8080
# path: /
# - &example1
# <<: *example1_www
# hostname: example1.com
#
# - &example_www
# hostname: www.example.com
# docroot: /var/www/example
# urlrules:
# -
# urlprefix: /APIv2
# type: uwsgi
# target:
# type: unix
# path: /run/uwsgi/APIv2.sock
# - &example
# <<: *example_www
# hostname: example.com
#
# - &example_bbs
# hostname: bbs.example.com
# docroot: /var/www/example_bbs/
# urlrules:
# -
# #urlprefix: \.php$|\.php\/.*
# #isregex: true
#
# urlprefix: /
# type: fastcgi
# target:
# type: unix
# path: /var/run/php-fpm/www.sock
#
# https config
#-
# host: 0.0.0.0
# port: 9002
# docroot: /srv/www
# enableproxy: false
# vhost:
# -
# <<: *example1
# cert: /home/user1/cert/example1.com.crt
# key: /home/user1/cert/example1.com.key
# -
# <<: *example1_www
# cert: /home/user1/cert/example1.com.crt
# key: /home/user1/cert/example1.com.key
# -
# <<: *example_www
# cert: /etc/letsencrypt/live/example.com/fullchain.pem
# key: /etc/letsencrypt/live/example.com/privkey.pem
# -
# <<: *example
# cert: /etc/letsencrypt/live/example.com/fullchain.pem
# key: /etc/letsencrypt/live/example.com/privkey.pem
# -
# <<: *example_bbs
# cert: /etc/letsencrypt/live/bbs.example.com/fullchain.pem
# key: /etc/letsencrypt/live/bbs.example.com/privkey.pem
proxypass: http://nginx:80/
proxy:
http1-proxy: false
http2-proxy: true
# trust the follow domains as local virtual host
# when http2 proxy enabled
localdomains:
- localhost
- localdomain
- 127.0.0.1
- ratafee.nl
- 98.142.138.194

@ -0,0 +1,50 @@
package main
import (
"bufio"
"net"
proxyproto "github.com/pires/go-proxyproto"
)
type listener struct {
net.Listener
}
type conn struct {
net.Conn
headerDone bool
r *bufio.Reader
proxy *proxyproto.Header
}
func (l *listener) Accept() (net.Conn, error) {
c, err := l.Listener.Accept()
if err != nil {
return nil, err
}
return &conn{Conn: c}, err
}
func (c *conn) Read(buf []byte) (int, error) {
var err error
if !c.headerDone {
c.r = bufio.NewReader(c.Conn)
c.proxy, err = proxyproto.Read(c.r)
if err != nil && err != proxyproto.ErrNoProxyProtocol {
return 0, err
}
c.headerDone = true
return c.r.Read(buf)
}
return c.r.Read(buf)
}
func (c *conn) RemoteAddr() net.Addr {
if c.proxy == nil {
return c.Conn.RemoteAddr()
}
return &net.TCPAddr{
IP: c.proxy.SourceAddress,
Port: int(c.proxy.SourcePort)}
}

@ -1,90 +0,0 @@
package main
import (
"bufio"
"os"
"strings"
"sync"
"time"
)
type digestPwFile struct {
path string
entry []pwEntry
mtime time.Time
mu *sync.Mutex
}
type pwEntry struct {
user string
realm string
hashPw string
}
func newDigestSecret(f string) (*digestPwFile, error) {
a := &digestPwFile{path: f, mu: new(sync.Mutex)}
if err := a.loadFile(); err != nil {
return nil, err
}
go a.tryReload()
return a, nil
}
func (df *digestPwFile) tryReload() {
for {
time.Sleep(10 * time.Second)
fi, _ := os.Stat(df.path)
t1 := fi.ModTime()
if t1 != df.mtime {
df.loadFile()
}
}
}
func (df *digestPwFile) loadFile() error {
df.mu.Lock()
defer df.mu.Unlock()
fp, err := os.Open(df.path)
if err != nil {
return err
}
defer fp.Close()
entry := []pwEntry{}
r := bufio.NewReader(fp)
for {
line, err := r.ReadString('\n')
if err != nil {
break
}
line1 := strings.Trim(line, " \r\n")
if line1 == "" || line1[0] == '#' {
continue
}
fields := strings.SplitN(line1, ":", 3)
entry = append(entry, pwEntry{fields[0], fields[1], fields[2]})
}
df.entry = entry
fi, _ := os.Stat(df.path)
df.mtime = fi.ModTime()
return nil
}
func (df *digestPwFile) getPw(user, realm string) string {
df.mu.Lock()
defer df.mu.Unlock()
for i := range df.entry {
if df.entry[i].user == user && df.entry[i].realm == realm {
return df.entry[i].hashPw
}
}
return ""
}

@ -2,23 +2,20 @@ package main
import (
"fmt"
auth "github.com/fangdingjun/go-http-auth"
"io"
"log"
"net"
"net/http"
"strings"
"time"
"github.com/fangdingjun/go-log"
)
// handler process the proxy request first(if enabled)
// and route the request to the registered http.Handler
type handler struct {
handler http.Handler
enableProxy bool
enableAuth bool
authMethod *auth.DigestAuth
localDomains []string
cfg *conf
}
var defaultTransport http.RoundTripper = &http.Transport{
@ -54,19 +51,17 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// proxy request
if !h.enableProxy {
if r.ProtoMajor == 1 && !h.cfg.Proxy.HTTP1Proxy {
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, "<h1>404 Not Found</h1>")
return
}
if h.enableAuth {
u, _ := h.authMethod.CheckAuth(r)
if u == "" {
h.authMethod.RequireAuth(w, r)
if r.ProtoMajor == 2 && !h.cfg.Proxy.HTTP2Proxy {
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, "<h1>404 Not Found</h1>")
return
}
}
if r.Method == http.MethodConnect {
// CONNECT request
@ -178,15 +173,15 @@ func (h *handler) handleCONNECT(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.(http.Flusher).Flush()
ch := make(chan int, 2)
ch := make(chan struct{}, 2)
go func() {
io.Copy(conn, r.Body)
ch <- 1
ch <- struct{}{}
}()
go func() {
io.Copy(flushWriter{w}, conn)
ch <- 1
ch <- struct{}{}
}()
<-ch
@ -195,11 +190,11 @@ func (h *handler) handleCONNECT(w http.ResponseWriter, r *http.Request) {
// isLocalRequest determine the http2 request is local path request
// or the proxy request
func (h *handler) isLocalRequest(r *http.Request) bool {
if !h.enableProxy {
if !h.cfg.Proxy.HTTP2Proxy {
return true
}
if len(h.localDomains) == 0 {
if len(h.cfg.Proxy.LocalDomains) == 0 {
return true
}
@ -208,7 +203,7 @@ func (h *handler) isLocalRequest(r *http.Request) bool {
host = h1
}
for _, s := range h.localDomains {
for _, s := range h.cfg.Proxy.LocalDomains {
if strings.HasSuffix(host, s) {
return true
}
@ -227,15 +222,15 @@ func pipeAndClose(r1, r2 io.ReadWriteCloser) {
defer r1.Close()
defer r2.Close()
ch := make(chan int, 2)
ch := make(chan struct{}, 2)
go func() {
io.Copy(r1, r2)
ch <- 1
ch <- struct{}{}
}()
go func() {
io.Copy(r2, r1)
ch <- 1
ch <- struct{}{}
}()
<-ch

@ -1,10 +0,0 @@
# format
# user:realm:hashed_passwd
#
# hashed_passwd = MD5(user:realm:plain_passwd)
#
# user "test", realm "example.com", password "test"
# MD5("test:example:test") = 3441b753b98a6dc702183c989e35970f
# the entry is
test:example.com:3441b753b98a6dc702183c989e35970f

@ -2,14 +2,12 @@ package main
import (
"context"
"io"
"net"
"net/http"
//"bufio"
//"fmt"
"io"
"log"
//"strings"
"time"
"github.com/fangdingjun/go-log"
)
type proxy struct {

@ -1,262 +0,0 @@
package main
import (
"crypto/tls"
"fmt"
auth "github.com/fangdingjun/go-http-auth"
"github.com/fangdingjun/gofast"
loghandler "github.com/gorilla/handlers"
"github.com/gorilla/mux"
"io"
"log"
"net"
"net/http"
"net/http/httputil"
"net/url"
"os"
"regexp"
"sync"
//"path/filepath"
"strings"
)
type logwriter struct {
w io.Writer
l *sync.Mutex
}
func (lw *logwriter) Write(buf []byte) (int, error) {
lw.l.Lock()
defer lw.l.Unlock()
return lw.w.Write(buf)
}
func initRouters(cfg conf) {
logout := os.Stdout
if logfile != "" {
fp, err := os.OpenFile(logfile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
log.Println(err)
} else {
logout = fp
}
}
w := &logwriter{logout, new(sync.Mutex)}
for _, l := range cfg {
router := mux.NewRouter()
domains := []string{}
certs := []tls.Certificate{}
// initial virtual host
for _, h := range l.Vhost {
h2 := h.Hostname
if h1, _, err := net.SplitHostPort(h.Hostname); err == nil {
h2 = h1
}
domains = append(domains, h2)
if h.Cert != "" && h.Key != "" {
if cert, err := tls.LoadX509KeyPair(h.Cert, h.Key); err == nil {
certs = append(certs, cert)
} else {
log.Fatal(err)
}
}
r := router.Host(h2).Subrouter()
for _, rule := range h.URLRules {
switch rule.Type {
case "alias":
registerAliasHandler(rule, r)
case "uwsgi":
registerUwsgiHandler(rule, r)
case "fastcgi":
registerFastCGIHandler(rule, h.Docroot, r)
case "reverse":
registerHTTPHandler(rule, r)
default:
fmt.Printf("invalid type: %s\n", rule.Type)
}
}
r.PathPrefix("/").Handler(http.FileServer(http.Dir(h.Docroot)))
}
// default host config
for _, rule := range l.URLRules {
switch rule.Type {
case "alias":
registerAliasHandler(rule, router)
case "uwsgi":
registerUwsgiHandler(rule, router)
case "fastcgi":
docroot := l.Docroot
if rule.Docroot != "" {
docroot = rule.Docroot
}
registerFastCGIHandler(rule, docroot, router)
case "reverse":
registerHTTPHandler(rule, router)
default:
fmt.Printf("invalid type: %s\n", rule.Type)
}
}
router.PathPrefix("/").Handler(http.FileServer(http.Dir(l.Docroot)))
go func(l server) {
addr := fmt.Sprintf("%s:%d", l.Host, l.Port)
hdlr := &handler{
handler: router,
enableProxy: l.EnableProxy,
enableAuth: l.EnableAuth,
localDomains: domains,
}
if l.EnableAuth {
if l.PasswdFile == "" {
log.Fatal("passwdfile required")
}
du, err := newDigestSecret(l.PasswdFile)
if err != nil {
log.Fatal(err)
}
digestAuth := auth.NewDigestAuthenticator(l.Realm, du.getPw)
digestAuth.Headers = auth.ProxyHeaders
hdlr.authMethod = digestAuth
}
if len(certs) > 0 {
tlsconfig := &tls.Config{
Certificates: certs,
}
tlsconfig.BuildNameToCertificate()
srv := http.Server{
Addr: addr,
TLSConfig: tlsconfig,
Handler: loghandler.CombinedLoggingHandler(w, hdlr),
}
log.Printf("listen https on %s", addr)
if err := srv.ListenAndServeTLS("", ""); err != nil {
log.Fatal(err)
}
} else {
log.Printf("listen http on %s", addr)
if err := http.ListenAndServe(
addr,
loghandler.CombinedLoggingHandler(w, hdlr),
); err != nil {
log.Fatal(err)
}
}
}(l)
}
}
func registerAliasHandler(r rule, router *mux.Router) {
switch r.Target.Type {
case "file":
registerFileHandler(r, router)
case "dir":
registerDirHandler(r, router)
default:
fmt.Printf("invalid type: %s, only file, dir allowed\n", r.Target.Type)
os.Exit(-1)
}
}
func registerFileHandler(r rule, router *mux.Router) {
router.HandleFunc(r.URLPrefix,
func(w http.ResponseWriter, req *http.Request) {
http.ServeFile(w, req, r.Target.Path)
})
}
func registerDirHandler(r rule, router *mux.Router) {
p := strings.TrimRight(r.URLPrefix, "/")
router.PathPrefix(r.URLPrefix).Handler(
http.StripPrefix(p,
http.FileServer(http.Dir(r.Target.Path))))
}
func registerUwsgiHandler(r rule, router *mux.Router) {
var p string
switch r.Target.Type {
case "unix":
p = r.Target.Path
case "tcp":
p = fmt.Sprintf("%s:%d", r.Target.Host, r.Target.Port)
default:
fmt.Printf("invalid scheme: %s, only support unix, tcp", r.Target.Type)
os.Exit(-1)
}
if r.IsRegex {
m1 := myURLMatch{regexp.MustCompile(r.URLPrefix)}
u := NewUwsgi(r.Target.Type, p, "")
router.MatcherFunc(m1.match).Handler(u)
} else {
u := NewUwsgi(r.Target.Type, p, r.URLPrefix)
router.PathPrefix(r.URLPrefix).Handler(u)
}
}
func registerFastCGIHandler(r rule, docroot string, router *mux.Router) {
var n, p string
switch r.Target.Type {
case "unix":
n = "unix"
p = r.Target.Path
case "tcp":
n = "tcp"
p = fmt.Sprintf("%s:%d", r.Target.Host, r.Target.Port)
default:
fmt.Printf("invalid scheme: %s, only support unix, tcp", r.Target.Type)
os.Exit(-1)
}
u := gofast.NewHandler(gofast.NewPHPFS(docroot), n, p)
if r.IsRegex {
m1 := myURLMatch{regexp.MustCompile(r.URLPrefix)}
router.MatcherFunc(m1.match).Handler(u)
} else {
router.PathPrefix(r.URLPrefix).Handler(u)
}
}
func registerHTTPHandler(r rule, router *mux.Router) {
var u http.Handler
var addr string
switch r.Target.Type {
case "unix":
addr = r.Target.Path
u = newProxy(addr, r.URLPrefix)
case "http":
addr = fmt.Sprintf("%s:%d", r.Target.Host, r.Target.Port)
u1 := &url.URL{
Scheme: "http",
Host: addr,
Path: r.Target.Path,
}
u = httputil.NewSingleHostReverseProxy(u1)
default:
fmt.Printf("invalid scheme: %s, only support unix, http", r.Target.Type)
os.Exit(-1)
}
p := strings.TrimRight(r.URLPrefix, "/")
router.PathPrefix(r.URLPrefix).Handler(
http.StripPrefix(p, u))
}
type myURLMatch struct {
re *regexp.Regexp
}
func (m myURLMatch) match(r *http.Request, route *mux.RouteMatch) bool {
ret := m.re.MatchString(r.URL.Path)
return ret
}

@ -1,23 +1,142 @@
package main
import (
"crypto/tls"
"flag"
//"fmt"
"log"
//"net/http"
"fmt"
"net"
"net/http"
"os"
"os/signal"
"syscall"
"github.com/fangdingjun/go-log"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"golang.org/x/net/http2"
)
var logfile string
func initServer(c *conf) error {
mux := mux.NewRouter()
for _, vh := range c.Vhosts {
subroute := mux.Host(vh.Hostname)
subroute.PathPrefix("/").Handler(http.FileServer(http.Dir(vh.Docroot)))
}
if len(c.Vhosts) > 0 {
mux.PathPrefix("/").Handler(http.FileServer(http.Dir(c.Vhosts[0].Docroot)))
} else {
mux.PathPrefix("/").Handler(http.FileServer(http.Dir("/var/www/html")))
}
for _, _l := range c.Listens {
var err error
certs := []tls.Certificate{}
tlsconfig := &tls.Config{}
for _, cert := range _l.Certificates {
if cert.CertFile != "" && cert.KeyFile != "" {
_cert, err := tls.LoadX509KeyPair(cert.CertFile, cert.KeyFile)
if err != nil {
return err
}
certs = append(certs, _cert)
}
}
var h http.Handler
h = &handler{handler: mux, cfg: c}
h = handlers.CombinedLoggingHandler(&logout{}, h)
srv := &http.Server{
Addr: fmt.Sprintf("%s:%d", _l.Addr, _l.Port),
Handler: h,
}
var l net.Listener
l, err = net.Listen("tcp", srv.Addr)
if err != nil {
return err
}
l = &listener{Listener: l}
if len(certs) > 0 {
tlsconfig.Certificates = certs
tlsconfig.BuildNameToCertificate()
srv.TLSConfig = tlsconfig
http2.ConfigureServer(srv, nil)
l = tls.NewListener(l, srv.TLSConfig)
}
go func(l net.Listener) {
defer l.Close()
err = srv.Serve(l)
if err != nil {
log.Errorln(err)
}
}(l)
}
return nil
}
type logout struct{}
func (l *logout) Write(buf []byte) (int, error) {
log.Debugf("%s", buf)
return len(buf), nil
}
func main() {
var configfile string
var loglevel string
var logfile string
var logFileCount int
var logFileSize int64
flag.StringVar(&logfile, "log_file", "", "log file, default stdout")
flag.IntVar(&logFileCount, "log_count", 10, "max count of log to keep")
flag.Int64Var(&logFileSize, "log_size", 10, "max log file size MB")
flag.StringVar(&loglevel, "log_level", "INFO",
"log level, values:\nOFF, FATAL, PANIC, ERROR, WARN, INFO, DEBUG")
flag.StringVar(&configfile, "c", "config.yaml", "config file")
flag.StringVar(&logfile, "log", "", "log file")
flag.Parse()
if logfile != "" {
log.Default.Out = &log.FixedSizeFileWriter{
MaxCount: logFileCount,
Name: logfile,
MaxSize: logFileSize * 1024 * 1024,
}
}
if loglevel != "" {
lv, err := log.ParseLevel(loglevel)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
log.Default.Level = lv
}
c, err := loadConfig(configfile)
if err != nil {
log.Fatal(err)
}
initRouters(c)
select {}
log.Infof("%+v", c)
err = initServer(c)
if err != nil {
log.Fatalln(err)
}
ch := make(chan os.Signal, 2)
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
select {
case sig := <-ch:
log.Errorf("received signal %s, exit", sig)
}
log.Debug("exited.")
}

@ -1,107 +0,0 @@
package main
import (
//"fmt"
uwsgi "github.com/fangdingjun/go-uwsgi"
"net"
"net/http"
"strconv"
"strings"
)
// Uwsgi is a struct for uwsgi
type Uwsgi struct {
Passenger *uwsgi.Passenger
URLPrefix string
}
// NewUwsgi create a new Uwsgi
func NewUwsgi(network, addr, urlPrefix string) *Uwsgi {
u := strings.TrimRight(urlPrefix, "/")
return &Uwsgi{
Passenger: &uwsgi.Passenger{
Net: network,
Addr: addr,
},
URLPrefix: u,
}
}
// ServeHTTP implements http.Handler interface
func (u *Uwsgi) ServeHTTP(w http.ResponseWriter, r *http.Request) {
u.UwsgiPass(w, r)
}
// UwsgiPass pass the request to uwsgi interface
func (u *Uwsgi) UwsgiPass(w http.ResponseWriter, r *http.Request) {
params := buildParams(r, u.URLPrefix)
u.Passenger.UwsgiPass(w, r, params)
}
func buildParams(req *http.Request, urlPrefix string) map[string][]string {
var err error
header := make(map[string][]string)
if urlPrefix != "" {
header["SCRIPT_NAME"] = []string{urlPrefix}
p := strings.Replace(req.URL.Path, urlPrefix, "", 1)
header["PATH_INFO"] = []string{p}
} else {
header["PATH_INFO"] = []string{req.URL.Path}
}
//fmt.Printf("url: %s, scheme: %s\n", req.URL.String(), req.URL.Scheme)
scheme := "http"
if req.TLS != nil {
scheme = "https"
}
header["REQUEST_SCHEME"] = []string{scheme}
header["HTTPS"] = []string{"off"}
/* https */
if scheme == "https" {
header["HTTPS"] = []string{"on"}
}
/* speicial port */
host, port, err := net.SplitHostPort(req.Host)
if err != nil {
host = req.Host
if scheme == "http" {
port = "80"
} else {
port = "443"
}
}
header["SERVER_NAME"] = []string{host}
header["SERVER_PORT"] = []string{port}
host, port, err = net.SplitHostPort(req.RemoteAddr)
if err != nil {
host = req.RemoteAddr
port = "80"
}
header["REMOTE_PORT"] = []string{port}
header["REMOTE_ADDR"] = []string{host}
header["REQUEST_METHOD"] = []string{req.Method}
header["REQUEST_URI"] = []string{req.RequestURI}
header["CONTENT_LENGTH"] = []string{strconv.Itoa(int(req.ContentLength))}
header["SERVER_PROTOCOL"] = []string{req.Proto}
header["QUERY_STRING"] = []string{req.URL.RawQuery}
if ctype := req.Header.Get("Content-Type"); ctype != "" {
header["CONTENT_TYPE"] = []string{ctype}
}
for k, v := range req.Header {
k = "HTTP_" + strings.ToUpper(strings.Replace(k, "-", "_", -1))
if _, ok := header[k]; ok == false {
header[k] = v
}
}
return header
}
Loading…
Cancel
Save