diff --git a/conf.go b/conf.go
index a7c46c3..f72b7c9 100644
--- a/conf.go
+++ b/conf.go
@@ -1,48 +1,41 @@
package main
import (
- "github.com/go-yaml/yaml"
"io/ioutil"
+
+ "github.com/go-yaml/yaml"
)
-type conf []server
-
-type server struct {
- Host string
- Port int
- Docroot string
- URLRules []rule
- EnableProxy bool
- EnableAuth bool
- PasswdFile string
- Realm string
- Vhost []vhost
+type conf struct {
+ Listens []listen `yaml:"listen"`
+ Vhosts []vhost `yaml:"vhost"`
+ Proxy proxycfg `yaml:"proxy"`
}
-type vhost struct {
- Docroot string
- Hostname string
- Cert string
- Key string
- URLRules []rule
+type proxycfg struct {
+ HTTP1Proxy bool `yaml:"http1-proxy"`
+ HTTP2Proxy bool `yaml:"http2-proxy"`
+ LocalDomains []string `yaml:"localdomains"`
}
-type rule struct {
- URLPrefix string
- IsRegex bool
- Docroot string
- Type string
- Target target
+type listen struct {
+ Addr string `yaml:"addr"`
+ Port int16 `yaml:"port"`
+ Certificates []certificate `yaml:"certificates"`
}
-type target struct {
- Type string
- Host string
- Port int
- Path string
+type certificate struct {
+ CertFile string `yaml:"certfile"`
+ KeyFile string `yaml:"keyfile"`
+}
+
+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
}
diff --git a/config_example.yaml b/config_example.yaml
index e60dc1f..6ac143f 100644
--- a/config_example.yaml
+++ b/config_example.yaml
@@ -1,145 +1,33 @@
# vim: set ft=yaml:
-# when provide certficate file, server will listen https and enable http2
-
-
-# http config
--
- # listen address
- host: 0.0.0.0
-
- # listen port
+# when provide certficate file, server will listen https and enable http2
+listen:
+ -
+ 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
diff --git a/conn.go b/conn.go
new file mode 100644
index 0000000..8c74764
--- /dev/null
+++ b/conn.go
@@ -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)}
+}
diff --git a/digest_passwd_file.go b/digest_passwd_file.go
deleted file mode 100644
index 3f06c40..0000000
--- a/digest_passwd_file.go
+++ /dev/null
@@ -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 ""
-}
diff --git a/handler.go b/handler.go
index 821ff40..629ed3d 100644
--- a/handler.go
+++ b/handler.go
@@ -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
+ handler http.Handler
+ cfg *conf
}
var defaultTransport http.RoundTripper = &http.Transport{
@@ -54,18 +51,16 @@ 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, "
404 Not Found
")
return
}
- if h.enableAuth {
- u, _ := h.authMethod.CheckAuth(r)
- if u == "" {
- h.authMethod.RequireAuth(w, r)
- return
- }
+ if r.ProtoMajor == 2 && !h.cfg.Proxy.HTTP2Proxy {
+ w.WriteHeader(http.StatusNotFound)
+ fmt.Fprintf(w, "404 Not Found
")
+ return
}
if r.Method == http.MethodConnect {
@@ -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
diff --git a/passwdfile b/passwdfile
deleted file mode 100644
index c2323a2..0000000
--- a/passwdfile
+++ /dev/null
@@ -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
diff --git a/proxy.go b/proxy.go
index 8cb41d6..09a9e23 100644
--- a/proxy.go
+++ b/proxy.go
@@ -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 {
diff --git a/routers.go b/routers.go
deleted file mode 100644
index 1f75f06..0000000
--- a/routers.go
+++ /dev/null
@@ -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
-}
diff --git a/server.go b/server.go
index 40c5bf2..5e411b3 100644
--- a/server.go
+++ b/server.go
@@ -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.")
}
diff --git a/uwsgi.go b/uwsgi.go
deleted file mode 100644
index d2cf269..0000000
--- a/uwsgi.go
+++ /dev/null
@@ -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
-}