Files
remark42/vendor/github.com/pkg4go/rewrite/rewrite.go
T
2018-02-18 14:53:51 -06:00

135 lines
2.2 KiB
Go

package rewrite
import "net/http"
import "net/url"
import "strings"
import "regexp"
import "path"
import "fmt"
const headerField = "X-Rewrite-Original-URI"
type Rule struct {
Pattern string
To string
*regexp.Regexp
}
var regfmt = regexp.MustCompile(`:[^/#?()\.\\]+`)
func NewRule(pattern, to string) (*Rule, error) {
pattern = regfmt.ReplaceAllStringFunc(pattern, func(m string) string {
return fmt.Sprintf(`(?P<%s>[^/#?]+)`, m[1:])
})
reg, err := regexp.Compile(pattern)
if err != nil {
return nil, err
}
return &Rule{
pattern,
to,
reg,
}, nil
}
func (r *Rule) Rewrite(req *http.Request) bool {
oriPath := req.URL.Path
if !r.MatchString(oriPath) {
return false
}
to := path.Clean(r.Replace(req.URL))
u, e := url.Parse(to)
if e != nil {
return false
}
req.Header.Set(headerField, req.URL.RequestURI())
req.URL.Path = u.Path
req.URL.RawPath = u.RawPath
if u.RawQuery != "" {
req.URL.RawQuery = u.RawQuery
}
return true
}
func (r *Rule) Replace(u *url.URL) string {
if !hit("\\$|\\:", r.To) {
return r.To
}
uri := u.RequestURI()
regFrom := regexp.MustCompile(r.Pattern)
match := regFrom.FindStringSubmatchIndex(uri)
result := regFrom.ExpandString([]byte(""), r.To, uri, match)
str := string(result[:])
if hit("\\:", str) {
return r.replaceNamedParams(uri, str)
}
return str
}
var urlreg = regexp.MustCompile(`:[^/#?()\.\\]+|\(\?P<[a-zA-Z0-9]+>.*\)`)
func (r *Rule) replaceNamedParams(from, to string) string {
fromMatches := r.FindStringSubmatch(from)
if len(fromMatches) > 0 {
for i, name := range r.SubexpNames() {
if len(name) > 0 {
to = strings.Replace(to, ":"+name, fromMatches[i], -1)
}
}
}
return to
}
func NewHandler(rules map[string]string) RewriteHandler {
var h RewriteHandler
for key, val := range rules {
r, e := NewRule(key, val)
if e != nil {
panic(e)
}
h.rules = append(h.rules, r)
}
return h
}
type RewriteHandler struct {
rules []*Rule
}
func (h *RewriteHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
for _, r := range h.rules {
ok := r.Rewrite(req)
if ok {
break
}
}
}
func hit(pattern, str string) bool {
r, e := regexp.MatchString(pattern, str)
if e != nil {
return false
}
return r
}