Compare commits
No commits in common. 'lua' and 'master' have entirely different histories.
@ -1,53 +0,0 @@
|
|||||||
local http = require "http"
|
|
||||||
local json = require "json"
|
|
||||||
local mysql = require "mysql"
|
|
||||||
local redis = require "redis"
|
|
||||||
|
|
||||||
infolog(string.format("%s %s %s", request:GetIP(),request.Method,request.RequestURI))
|
|
||||||
|
|
||||||
-- response:Write(string.format("hello %s\n",request:GetIP()))
|
|
||||||
if request.URL.Path == "/api/ip" then
|
|
||||||
local resp = http.get("http://httpbin.org/ip")
|
|
||||||
local d = json.decode(resp.body)
|
|
||||||
print(d)
|
|
||||||
infolog(string.format("ip %s",d.origin))
|
|
||||||
local hdr = response:Header()
|
|
||||||
hdr:Set("content-type","application/json")
|
|
||||||
response:Write(resp.body)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if request.URL.Path == "/api/user" then
|
|
||||||
local c = mysql.new()
|
|
||||||
local ok, err = c:connect({host="127.0.0.1",user="root",password="112233",database="game"})
|
|
||||||
if not ok then
|
|
||||||
error(err)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local res, err = c:query("select * from `user` limit 3")
|
|
||||||
if err ~= nil then
|
|
||||||
error(err)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
for k,v in pairs(res) do
|
|
||||||
print(k,v)
|
|
||||||
for k1,v1 in pairs(v) do
|
|
||||||
print(k1,v1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local hdr = response:Header()
|
|
||||||
hdr:Set("content-type","application/json")
|
|
||||||
response:Write(json.encode(res))
|
|
||||||
c:close()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if request.URL.Path == "/api/user2" then
|
|
||||||
local c = redis.new({host="127.0.0.1"})
|
|
||||||
local keys = c:Do("keys", "wallet*"):Val()
|
|
||||||
for k, v in keys() do
|
|
||||||
response:Write(string.format("%s %s\n", k, v))
|
|
||||||
end
|
|
||||||
c:Close()
|
|
||||||
end
|
|
@ -1,82 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/fangdingjun/go-log"
|
|
||||||
lua "github.com/yuin/gopher-lua"
|
|
||||||
"github.com/yuin/gopher-lua/parse"
|
|
||||||
)
|
|
||||||
|
|
||||||
// from https://github.com/yuin/gophoer-lua
|
|
||||||
|
|
||||||
// CompileLua reads the passed lua file from disk and compiles it.
|
|
||||||
func CompileLua(filePath string) (*lua.FunctionProto, error) {
|
|
||||||
file, err := os.Open(filePath)
|
|
||||||
defer file.Close()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
reader := bufio.NewReader(file)
|
|
||||||
chunk, err := parse.Parse(reader, filePath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
proto, err := lua.Compile(chunk, filePath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return proto, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DoCompiledFile takes a FunctionProto, as returned by CompileLua, and runs it in the LState. It is equivalent
|
|
||||||
// to calling DoFile on the LState with the original source file.
|
|
||||||
func DoCompiledFile(L *lua.LState, proto *lua.FunctionProto) error {
|
|
||||||
lfunc := L.NewFunctionFromProto(proto)
|
|
||||||
L.Push(lfunc)
|
|
||||||
return L.PCall(0, lua.MultRet, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
type filecache struct {
|
|
||||||
filepath string
|
|
||||||
proto *lua.FunctionProto
|
|
||||||
lastMod int64
|
|
||||||
}
|
|
||||||
|
|
||||||
var cache = map[string]*filecache{}
|
|
||||||
var mu = new(sync.Mutex)
|
|
||||||
|
|
||||||
func runFile(vm *lua.LState, filepath string) error {
|
|
||||||
mu.Lock()
|
|
||||||
c, ok := cache[filepath]
|
|
||||||
if !ok {
|
|
||||||
c = &filecache{
|
|
||||||
filepath: filepath,
|
|
||||||
lastMod: 0,
|
|
||||||
}
|
|
||||||
cache[filepath] = c
|
|
||||||
}
|
|
||||||
|
|
||||||
fi, err := os.Stat(filepath)
|
|
||||||
if err != nil {
|
|
||||||
mu.Unlock()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
t := fi.ModTime().Unix()
|
|
||||||
if t > c.lastMod {
|
|
||||||
log.Debugf("file %s changed, reload", filepath)
|
|
||||||
proto, err := CompileLua(filepath)
|
|
||||||
if err != nil {
|
|
||||||
mu.Unlock()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.proto = proto
|
|
||||||
c.lastMod = t
|
|
||||||
}
|
|
||||||
mu.Unlock()
|
|
||||||
// log.Println(c.proto)
|
|
||||||
return DoCompiledFile(vm, c.proto)
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
# vim: set ft=yaml:
|
|
||||||
|
|
||||||
# when provide certficate file, server will listen https and enable http2
|
|
||||||
listen:
|
|
||||||
-
|
|
||||||
addr: 0.0.0.0
|
|
||||||
port: 9001
|
|
||||||
certificates:
|
|
||||||
|
|
||||||
# virtual host support
|
|
||||||
vhost:
|
|
||||||
-
|
|
||||||
hostname: www.ratafee.nl
|
|
||||||
docroot: .
|
|
||||||
# proxypass: http://nginx:80/
|
|
||||||
url_rules:
|
|
||||||
- prefix: /api/
|
|
||||||
lua_file: api.lua
|
|
||||||
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
|
|
@ -1,36 +1,145 @@
|
|||||||
# vim: set ft=yaml:
|
# vim: set ft=yaml:
|
||||||
|
|
||||||
# when provide certficate file, server will listen https and enable http2
|
# when provide certficate file, server will listen https and enable http2
|
||||||
listen:
|
|
||||||
-
|
|
||||||
addr: 0.0.0.0
|
# http config
|
||||||
|
-
|
||||||
|
# listen address
|
||||||
|
host: 0.0.0.0
|
||||||
|
|
||||||
|
# listen port
|
||||||
port: 9001
|
port: 9001
|
||||||
certificates:
|
|
||||||
-
|
# default document root
|
||||||
addr: 0.0.0.0
|
|
||||||
port: 9002
|
|
||||||
certificates:
|
|
||||||
-
|
|
||||||
certfile: /etc/letsencrypt/live/ratafee.nl/fullchain.pem
|
|
||||||
keyfile: /etc/letsencrypt/live/ratafee.nl/privkey.pem
|
|
||||||
|
|
||||||
# virtual host support
|
|
||||||
vhost:
|
|
||||||
-
|
|
||||||
hostname: www.ratafee.nl
|
|
||||||
docroot: /srv/www
|
docroot: /srv/www
|
||||||
proxypass: http://nginx:80/
|
|
||||||
url_rules:
|
enableproxy: true
|
||||||
- prefix: /api/
|
enableauth: true
|
||||||
lua_file: api.lua
|
passwdfile: ./passwdfile
|
||||||
proxy:
|
realm: example.com
|
||||||
http1-proxy: false
|
|
||||||
http2-proxy: true
|
# default host's url rule
|
||||||
# trust the follow domains as local virtual host
|
# urlrules:
|
||||||
# when http2 proxy enabled
|
# -
|
||||||
localdomains:
|
# urlprefix: /a
|
||||||
- localhost
|
# type: alias
|
||||||
- localdomain
|
# target:
|
||||||
- 127.0.0.1
|
# type: dir
|
||||||
- ratafee.nl
|
# path: /home/user1/a
|
||||||
- 98.142.138.194
|
# -
|
||||||
|
# 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
|
||||||
|
@ -0,0 +1,90 @@
|
|||||||
|
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 ""
|
||||||
|
}
|
@ -1,20 +0,0 @@
|
|||||||
module github.com/fangdingjun/gserver
|
|
||||||
|
|
||||||
go 1.13
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/cjoudrey/gluahttp v0.0.0-20190104103309-101c19a37344
|
|
||||||
github.com/fangdingjun/go-log v0.0.0-20190821073628-ae332053d6dc
|
|
||||||
github.com/fangdingjun/gopher-redis v0.0.0-20190823083833-93d88f74dd35
|
|
||||||
github.com/fangdingjun/protolistener v0.0.0-20190821093313-6d5d2138f296
|
|
||||||
github.com/go-sql-driver/mysql v1.4.1 // indirect
|
|
||||||
github.com/go-yaml/yaml v2.1.0+incompatible
|
|
||||||
github.com/gorilla/handlers v1.4.2
|
|
||||||
github.com/gorilla/mux v1.7.3
|
|
||||||
github.com/junhsieh/goexamples v0.0.0-20190721045834-1c67ae74caa6 // indirect
|
|
||||||
github.com/tengattack/gluasql v0.0.0-20181229041402-2e5ed630c4cf
|
|
||||||
github.com/yuin/gopher-lua v0.0.0-20190514113301-1cd887cd7036
|
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
|
|
||||||
layeh.com/gopher-json v0.0.0-20190114024228-97fed8db8427
|
|
||||||
layeh.com/gopher-luar v1.0.7
|
|
||||||
)
|
|
@ -1,49 +0,0 @@
|
|||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
|
||||||
github.com/cjoudrey/gluahttp v0.0.0-20190104103309-101c19a37344 h1:nTK6O2RY1nHC4jNEJd1nixVP7ygY3QE4CNxCX07dHKU=
|
|
||||||
github.com/cjoudrey/gluahttp v0.0.0-20190104103309-101c19a37344/go.mod h1:X97UjDTXp+7bayQSFZk2hPvCTmTZIicUjZQRtkwgAKY=
|
|
||||||
github.com/fangdingjun/go-log v0.0.0-20190821073628-ae332053d6dc h1:Tdk7VsmsFo3d0NqHTy3SRoRnkduOxwXgR65gQsq8kXY=
|
|
||||||
github.com/fangdingjun/go-log v0.0.0-20190821073628-ae332053d6dc/go.mod h1:oi7jbIScCbha6TbVzmrJP6igIHt+jcvvEgSJ7Ww1GkI=
|
|
||||||
github.com/fangdingjun/gopher-redis v0.0.0-20190823083833-93d88f74dd35 h1:ylhL3mOAVv+xPvF7ml4mPJkacGyc4hDAxBRl8/DGATk=
|
|
||||||
github.com/fangdingjun/gopher-redis v0.0.0-20190823083833-93d88f74dd35/go.mod h1:mJh0kXIkwwPbU3KnTswNRDtHUtA+xlFJRHnbxuFg33Y=
|
|
||||||
github.com/fangdingjun/protolistener v0.0.0-20190821093313-6d5d2138f296 h1:2c6agkdoPVSyvdJ0B+5DhOb1BQpso7a7zlBxXUnttmY=
|
|
||||||
github.com/fangdingjun/protolistener v0.0.0-20190821093313-6d5d2138f296/go.mod h1:RoT81rjdN8gQ1w/z7NiFkxV6VzkT4NZ43XIt0lu8tcc=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
|
||||||
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
|
||||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
|
||||||
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
|
|
||||||
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
|
||||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
|
||||||
github.com/junhsieh/goexamples v0.0.0-20190721045834-1c67ae74caa6 h1:oi85CfIzfVPMlTf6pteDMw0S3AjZ9b6Y0OaxfsLCU3M=
|
|
||||||
github.com/junhsieh/goexamples v0.0.0-20190721045834-1c67ae74caa6/go.mod h1:JNqB8Da6SnlJvmZusESDfgqUkJXO6+/a1by1etsVJ2M=
|
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/ginkgo v1.9.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/gomega v1.6.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
|
||||||
github.com/pires/go-proxyproto v0.0.0-20190111085350-4d51b51e3bfc/go.mod h1:6/gX3+E/IYGa0wMORlSMla999awQFdbaeQCHjSMKIzY=
|
|
||||||
github.com/tengattack/gluasql v0.0.0-20181229041402-2e5ed630c4cf h1:7zGSyMKHHwD0A8iJk0IlP8FhSIOZco4VyzemWYHP1Ck=
|
|
||||||
github.com/tengattack/gluasql v0.0.0-20181229041402-2e5ed630c4cf/go.mod h1:m4UsFo0sc87XS8WozZBD8HJPC2NKI/nB7w4N58HwemQ=
|
|
||||||
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
|
||||||
github.com/yuin/gopher-lua v0.0.0-20190514113301-1cd887cd7036/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
|
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
layeh.com/gopher-json v0.0.0-20190114024228-97fed8db8427 h1:RZkKxMR3jbQxdCEcglq3j7wY3PRJIopAwBlx1RE71X0=
|
|
||||||
layeh.com/gopher-json v0.0.0-20190114024228-97fed8db8427/go.mod h1:ivKkcY8Zxw5ba0jldhZCYYQfGdb2K6u9tbYK1AwMIBc=
|
|
||||||
layeh.com/gopher-luar v1.0.7 h1:53iv6CCkRs5wyofZ+qVXcyAYQOIG52s6pt4xkqZdq7k=
|
|
||||||
layeh.com/gopher-luar v1.0.7/go.mod h1:TPnIVCZ2RJBndm7ohXyaqfhzjlZ+OA2SZR/YwL8tECk=
|
|
@ -1,17 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/fangdingjun/go-log"
|
|
||||||
)
|
|
||||||
|
|
||||||
func infoLog(msg string) {
|
|
||||||
log.Println(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func errorLog(msg string) {
|
|
||||||
log.Errorln(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func debugLog(msg string) {
|
|
||||||
log.Debugln(msg)
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/fangdingjun/go-log"
|
|
||||||
luar "layeh.com/gopher-luar"
|
|
||||||
)
|
|
||||||
|
|
||||||
type luaHandler struct {
|
|
||||||
scriptFile string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *luaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
vm := luaPool.Get()
|
|
||||||
defer luaPool.Put(vm)
|
|
||||||
|
|
||||||
vm.SetGlobal("request", luar.New(vm, &req{r}))
|
|
||||||
vm.SetGlobal("response", luar.New(vm, w))
|
|
||||||
|
|
||||||
if err := runFile(vm, l.scriptFile); err != nil {
|
|
||||||
log.Errorln(err)
|
|
||||||
http.Error(w, "server error", http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type req struct {
|
|
||||||
*http.Request
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r1 *req) GetBody() (string, error) {
|
|
||||||
d, err := ioutil.ReadAll(r1.Body)
|
|
||||||
return string(d), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r1 *req) GetIP() string {
|
|
||||||
ip := r1.Header.Get("x-real-ip")
|
|
||||||
if ip != "" {
|
|
||||||
return ip
|
|
||||||
}
|
|
||||||
ip = r1.Header.Get("x-forwarded-for")
|
|
||||||
if ip != "" {
|
|
||||||
return ip
|
|
||||||
}
|
|
||||||
host, _, _ := net.SplitHostPort(r1.RemoteAddr)
|
|
||||||
return host
|
|
||||||
}
|
|
@ -0,0 +1,10 @@
|
|||||||
|
# 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
|
@ -1,68 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
gluahttp "github.com/cjoudrey/gluahttp"
|
|
||||||
lua "github.com/yuin/gopher-lua"
|
|
||||||
luajson "layeh.com/gopher-json"
|
|
||||||
luar "layeh.com/gopher-luar"
|
|
||||||
mysql "github.com/tengattack/gluasql/mysql"
|
|
||||||
redis "github.com/fangdingjun/gopher-redis"
|
|
||||||
)
|
|
||||||
|
|
||||||
// from https://github.com/yuin/gophoer-lua
|
|
||||||
|
|
||||||
type lStatePool struct {
|
|
||||||
m sync.Mutex
|
|
||||||
saved []*lua.LState
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pl *lStatePool) Get() *lua.LState {
|
|
||||||
pl.m.Lock()
|
|
||||||
defer pl.m.Unlock()
|
|
||||||
n := len(pl.saved)
|
|
||||||
if n == 0 {
|
|
||||||
return pl.New()
|
|
||||||
}
|
|
||||||
x := pl.saved[n-1]
|
|
||||||
pl.saved = pl.saved[0 : n-1]
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pl *lStatePool) New() *lua.LState {
|
|
||||||
L := lua.NewState()
|
|
||||||
|
|
||||||
luajson.Preload(L)
|
|
||||||
L.PreloadModule("http", gluahttp.NewHttpModule(&http.Client{}).Loader)
|
|
||||||
L.PreloadModule("mysql", mysql.Loader)
|
|
||||||
L.PreloadModule("redis", redis.Loader)
|
|
||||||
|
|
||||||
L.SetGlobal("infolog", luar.New(L, infoLog))
|
|
||||||
L.SetGlobal("errorlog", luar.New(L, errorLog))
|
|
||||||
L.SetGlobal("debuglog", luar.New(L, debugLog))
|
|
||||||
|
|
||||||
// setting the L up here.
|
|
||||||
// load scripts, set global variables, share channels, etc...
|
|
||||||
return L
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pl *lStatePool) Put(L *lua.LState) {
|
|
||||||
pl.m.Lock()
|
|
||||||
defer pl.m.Unlock()
|
|
||||||
pl.saved = append(pl.saved, L)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pl *lStatePool) Shutdown() {
|
|
||||||
pl.m.Lock()
|
|
||||||
defer pl.m.Unlock()
|
|
||||||
for _, L := range pl.saved {
|
|
||||||
L.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Global LState pool
|
|
||||||
var luaPool = &lStatePool{
|
|
||||||
saved: make([]*lua.LState, 0, 4),
|
|
||||||
}
|
|
@ -0,0 +1,72 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
//"bufio"
|
||||||
|
//"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
//"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type proxy struct {
|
||||||
|
transport http.RoundTripper
|
||||||
|
addr string
|
||||||
|
prefix string
|
||||||
|
dialer *net.Dialer
|
||||||
|
network string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newProxy(addr string, prefix string) *proxy {
|
||||||
|
p := &proxy{
|
||||||
|
addr: addr,
|
||||||
|
prefix: prefix,
|
||||||
|
dialer: &net.Dialer{Timeout: 2 * time.Second},
|
||||||
|
}
|
||||||
|
if addr[0] == '/' {
|
||||||
|
p.network = "unix"
|
||||||
|
} else {
|
||||||
|
p.network = "tcp"
|
||||||
|
}
|
||||||
|
p.transport = &http.Transport{
|
||||||
|
DialContext: p.dialContext,
|
||||||
|
MaxIdleConns: 5,
|
||||||
|
IdleConnTimeout: 30 * time.Second,
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *proxy) dialContext(ctx context.Context,
|
||||||
|
network, addr string) (net.Conn, error) {
|
||||||
|
return p.dialer.DialContext(ctx, p.network, p.addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *proxy) dial(network, addr string) (conn net.Conn, err error) {
|
||||||
|
return p.dialer.Dial(p.network, p.addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
host, _, _ := net.SplitHostPort(r.RemoteAddr)
|
||||||
|
r.Header.Add("X-Forwarded-For", host)
|
||||||
|
r.URL.Scheme = "http"
|
||||||
|
r.URL.Host = r.Host
|
||||||
|
resp, err := p.transport.RoundTrip(r)
|
||||||
|
if err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
w.WriteHeader(http.StatusBadGateway)
|
||||||
|
w.Write([]byte("<h1>502 Bad Gateway</h1>"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
header := w.Header()
|
||||||
|
for k, v := range resp.Header {
|
||||||
|
for _, v1 := range v {
|
||||||
|
header.Add(k, v1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.WriteHeader(resp.StatusCode)
|
||||||
|
io.Copy(w, resp.Body)
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
proxy_local*
|
|
@ -1,9 +0,0 @@
|
|||||||
proxy_local
|
|
||||||
===========
|
|
||||||
|
|
||||||
accept http proxy request and forward to upstream proxy server via http2
|
|
||||||
|
|
||||||
usage
|
|
||||||
====
|
|
||||||
|
|
||||||
use `./proxy_local -h` to see options
|
|
@ -0,0 +1,262 @@
|
|||||||
|
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,161 +1,23 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
//"fmt"
|
||||||
"net"
|
"log"
|
||||||
"net/http"
|
//"net/http"
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/fangdingjun/go-log"
|
|
||||||
"github.com/fangdingjun/protolistener"
|
|
||||||
"github.com/gorilla/handlers"
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
"golang.org/x/net/http2"
|
|
||||||
"golang.org/x/net/trace"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func initServer(c *conf) error {
|
var logfile string
|
||||||
|
|
||||||
mux := mux.NewRouter()
|
|
||||||
|
|
||||||
for _, vh := range c.Vhosts {
|
|
||||||
subroute := mux.Host(vh.Hostname)
|
|
||||||
for _, rule := range vh.URLRules {
|
|
||||||
subroute.PathPrefix(rule.Prefix).Handler(&luaHandler{rule.LuaFile})
|
|
||||||
}
|
|
||||||
subroute.PathPrefix("/").Handler(http.FileServer(http.Dir(vh.Docroot)))
|
|
||||||
}
|
|
||||||
|
|
||||||
mux.PathPrefix("/debug/").Handler(http.DefaultServeMux)
|
|
||||||
|
|
||||||
if len(c.Vhosts) > 0 {
|
|
||||||
rules := c.Vhosts[0].URLRules
|
|
||||||
for _, rule := range rules {
|
|
||||||
mux.PathPrefix(rule.Prefix).Handler(&luaHandler{rule.LuaFile})
|
|
||||||
}
|
|
||||||
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,
|
|
||||||
events: trace.NewEventLog("http", fmt.Sprintf("%s:%d", _l.Addr, _l.Port)),
|
|
||||||
}
|
|
||||||
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 = protolistener.New(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() {
|
func main() {
|
||||||
var configfile string
|
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(&configfile, "c", "config.yaml", "config file")
|
||||||
|
flag.StringVar(&logfile, "log", "", "log file")
|
||||||
flag.Parse()
|
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)
|
c, err := loadConfig(configfile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
initRouters(c)
|
||||||
log.Infof("%+v", c)
|
select {}
|
||||||
err = initServer(c)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
trace.AuthRequest = func(r *http.Request) (bool, bool) {
|
|
||||||
return true, true
|
|
||||||
}
|
|
||||||
|
|
||||||
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.")
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,107 @@
|
|||||||
|
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…
Reference in New Issue