Skip to content

Commit bed7401

Browse files
committed
feat: add hostname related rewrite options
1 parent c6d3756 commit bed7401

File tree

7 files changed

+144
-29
lines changed

7 files changed

+144
-29
lines changed

README.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ This means it is impossible to use legacy Go version to compile binaries for leg
2323
Only denly client access from specific IP or network.
2424
Unmatched client IP will be allowed to access.
2525
26+
--rewrite-host <separator><match><separator><replace>
27+
Transform a request host+URL (in the form of "host[:port]/request/path?param=value")
28+
into another one if it is matched by regular expression `match`.
29+
30+
The rewrite target is specified by `replace`.
31+
Use `$0` to represent the whole match in `match`.
32+
use `$1` - `$9` to represent sub matches in `match`.
33+
--rewrite-host-post <sep><match><sep><replace>
34+
Similar to --rewrite-host, but executes after redirects has no match.
35+
--rewrite-host-end <sep><match><sep><replace>
36+
Similar to --rewrite-host-post, but skip rest process if matched.
37+
2638
--rewrite <separator><match><separator><replace>
2739
Transform a request URL (in the form of "/request/path?param=value")
2840
into another one if it is matched by regular expression `match`.
@@ -75,10 +87,10 @@ This means it is impossible to use legacy Go version to compile binaries for leg
7587
- `--status-page` executed if status code matched, and stop processing.
7688
- if client IP match `--ip-deny` or `--ip-deny-file`, return status 403, and stop processing
7789
- `--status-page` executed if status code matched, and stop processing.
78-
- `--rewrite` executed to transform the URL if matched.
90+
- `--rewrite-host` and `--rewrite` executed to transform the URL if matched.
7991
- `--redirect` executed if URL matched, and stop processing.
80-
- `--rewrite-post` executed to transform the URL if matched.
81-
- `--rewrite-end` executed to transform the URL if matched, and skip rest of `--rewrite-end`, `--redirect`, `--proxy` and `--return`.
92+
- `--rewrite-host-post` and `--rewrite-post` executed to transform the URL if matched.
93+
- `--rewrite-host-end` and `--rewrite-end` executed to transform the URL if matched, and skip rest processes like `--rewrite[-host]-end`, `--proxy` `--return`, etc.
8294
- `--proxy` executed if URL matched, and stop processing.
8395
- `--header-add` and `--header-set` executed if URL matched, and stop processing.
8496
- `--return` executed if URL matched, and stop processing.

README.zh-CN.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ Extra HTTP File Server基于Go HTTP File Server,附带额外功能。
2323
只拒绝来自指定的IP或网络的客户端访问。
2424
不匹配的客户端IP会被允许访问。
2525
26+
--rewrite-host <分隔符><match><分隔符><replace>
27+
如果请求的host+URL(“host[:port]/request/path?param=value”的形式)匹配正则表达式`match`,
28+
将其重写为另一种形式。
29+
30+
重写的目标由`replace`指定。
31+
使用`$0`表示`match`的完整匹配。
32+
使用`$1`-`$9`来表示`match`中的子匹配。
33+
--rewrite-host-post <分隔符><match><分隔符><replace>
34+
与--rewrite-host相似,但在重定向无匹配后执行。
35+
--rewrite-host-end <分隔符><match><分隔符><replace>
36+
与--rewrite-host-post相似,但匹配后跳过后续处理流程。
37+
2638
--rewrite <分隔符><match><分隔符><replace>
2739
如果请求的URL(“/request/path?param=value”的形式)匹配正则表达式`match`,
2840
将其重写为另一种形式。
@@ -74,10 +86,10 @@ Extra HTTP File Server基于Go HTTP File Server,附带额外功能。
7486
- 如果状态码匹配,执行`--status-page`并停止处理。
7587
- 如果客户端IP匹配`--ip-deny``--ip-deny-file`,返回403状态并停止处理
7688
- 如果状态码匹配,执行`--status-page`并停止处理。
77-
- 如果URL匹配,执行`--rewrite`以转换URL。
89+
- 如果URL匹配,执行`--rewrite-host``--rewrite`以转换URL。
7890
- 如果URL匹配,执行`--redirect`并停止处理。
79-
- 如果URL匹配,执行`--rewrite-post`以转换URL。
80-
- 如果URL匹配,执行`--rewrite-end`以转换URL,跳过其余`--rewrite-end``--redirect``--proxy``--return`
91+
- 如果URL匹配,执行`--rewrite-host-post``--rewrite-post`以转换URL。
92+
- 如果URL匹配,执行`--rewrite-host-end``--rewrite-end`以转换URL,跳过其余处理流程,例如`--rewrite[-host]-end``--proxy``--return`
8193
- 如果URL匹配,执行`--proxy`并停止处理。
8294
- 如果URL匹配,执行`--header-add``--header-set`并停止处理。
8395
- 如果URL匹配,执行`--return`并停止处理。

src/middleware/main.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,36 @@ func ParamToMiddlewares(baseParam *baseParam.Param, param *param.Param) (preMids
6060
ipDenyMids = append(ipDenyMids, mid)
6161
}
6262

63+
// rewrite hosts
64+
rewriteHostMids := make([]middleware.Middleware, 0, len(param.RewriteHosts))
65+
for i := range param.RewriteHosts {
66+
mid, err = getRewriteHostMiddleware(param.RewriteHosts[i], middleware.GoNext)
67+
errs = serverError.AppendError(errs, err)
68+
if mid != nil {
69+
rewriteHostMids = append(rewriteHostMids, mid)
70+
}
71+
}
72+
73+
// rewrite hosts post
74+
rewriteHostPostMids := make([]middleware.Middleware, 0, len(param.RewriteHostsPost))
75+
for i := range param.RewriteHostsPost {
76+
mid, err = getRewriteHostMiddleware(param.RewriteHostsPost[i], middleware.GoNext)
77+
errs = serverError.AppendError(errs, err)
78+
if mid != nil {
79+
rewriteHostPostMids = append(rewriteHostPostMids, mid)
80+
}
81+
}
82+
83+
// rewrite hosts end
84+
rewriteHostEndMids := make([]middleware.Middleware, 0, len(param.RewriteHostsEnd))
85+
for i := range param.RewriteHostsEnd {
86+
mid, err = getRewriteHostMiddleware(param.RewriteHostsEnd[i], middleware.SkipRests)
87+
errs = serverError.AppendError(errs, err)
88+
if mid != nil {
89+
rewriteHostEndMids = append(rewriteHostEndMids, mid)
90+
}
91+
}
92+
6393
// rewrites
6494
rewriteMids := make([]middleware.Middleware, 0, len(param.Rewrites))
6595
for i := range param.Rewrites {
@@ -138,9 +168,12 @@ func ParamToMiddlewares(baseParam *baseParam.Param, param *param.Param) (preMids
138168
preMids = util.Concat(
139169
ipAllowMids,
140170
ipDenyMids,
171+
rewriteHostMids,
141172
rewriteMids,
142173
redirectMids,
174+
rewriteHostPostMids,
143175
rewritePostMids,
176+
rewriteHostEndMids,
144177
rewriteEndMids,
145178
proxyMids,
146179
returnMids,

src/middleware/rewrite.go

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,59 @@ import (
44
"mjpclab.dev/ehfs/src/util"
55
"mjpclab.dev/ghfs/src/middleware"
66
"net/http"
7+
"net/url"
78
"regexp"
89
)
910

11+
func rewriteUrl(r *http.Request, targetUrl *url.URL) {
12+
originalUrl := r.URL
13+
prefixLen := len(originalUrl.RawPath) - len(originalUrl.Path)
14+
if prefixLen < 0 {
15+
prefixLen = 0
16+
} else if prefixLen > len(originalUrl.RawPath) {
17+
prefixLen = len(originalUrl.RawPath)
18+
}
19+
prefix := originalUrl.RawPath[:prefixLen]
20+
21+
targetUrl = originalUrl.ResolveReference(targetUrl)
22+
if len(prefix) > 1 {
23+
targetUrl.RawPath = prefix + targetUrl.Path
24+
} else {
25+
targetUrl.RawPath = targetUrl.Path
26+
}
27+
28+
r.URL = targetUrl
29+
}
30+
31+
func getRewriteHostMiddleware(arg [2]string, rewrittenResult middleware.ProcessResult) (middleware.Middleware, error) {
32+
var err error
33+
var reMatch *regexp.Regexp
34+
var replace string
35+
36+
reMatch, err = regexp.Compile(arg[0])
37+
if err != nil {
38+
return nil, err
39+
}
40+
replace = arg[1]
41+
42+
return func(w http.ResponseWriter, r *http.Request, context *middleware.Context) (result middleware.ProcessResult) {
43+
requestURI := r.Host + r.URL.RequestURI() // request uri without prefix path
44+
if !reMatch.MatchString(requestURI) {
45+
return middleware.GoNext
46+
}
47+
48+
targetUrl, err := util.ReplaceUrl(reMatch, requestURI, replace)
49+
if err != nil {
50+
util.LogError(context.Logger, err)
51+
w.WriteHeader(http.StatusBadRequest)
52+
return middleware.Outputted
53+
} else {
54+
rewriteUrl(r, targetUrl)
55+
return rewrittenResult
56+
}
57+
}, nil
58+
}
59+
1060
func getRewriteMiddleware(arg [2]string, rewrittenResult middleware.ProcessResult) (middleware.Middleware, error) {
1161
var err error
1262
var reMatch *regexp.Regexp
@@ -30,23 +80,7 @@ func getRewriteMiddleware(arg [2]string, rewrittenResult middleware.ProcessResul
3080
w.WriteHeader(http.StatusBadRequest)
3181
return middleware.Outputted
3282
} else {
33-
originalUrl := r.URL
34-
prefixLen := len(originalUrl.RawPath) - len(originalUrl.Path)
35-
if prefixLen < 0 {
36-
prefixLen = 0
37-
} else if prefixLen > len(originalUrl.RawPath) {
38-
prefixLen = len(originalUrl.RawPath)
39-
}
40-
prefix := originalUrl.RawPath[:prefixLen]
41-
42-
targetUrl = originalUrl.ResolveReference(targetUrl)
43-
if len(prefix) > 1 {
44-
targetUrl.RawPath = prefix + targetUrl.Path
45-
} else {
46-
targetUrl.RawPath = targetUrl.Path
47-
}
48-
49-
r.URL = targetUrl
83+
rewriteUrl(r, targetUrl)
5084
return rewrittenResult
5185
}
5286
}, nil

src/param/cli.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ func NewCliCmd() *goNixArgParser.Command {
2828
err = options.AddFlagValues("ipdenyfiles", "--ip-deny-file", "", nil, "specify denied client IP from files, rests are allowed if no allow list")
2929
serverError.CheckFatal(err)
3030

31+
err = options.AddFlagValues("rewritehosts", "--rewrite-host", "", nil, "add rule to replace request URL by host+request_URL, format <sep><match><sep><replace>")
32+
serverError.CheckFatal(err)
33+
34+
err = options.AddFlagValues("rewritehostspost", "--rewrite-host-post", "", nil, "add rule to replace request URL by host+request_URL after redirects, format <sep><match><sep><replace>")
35+
serverError.CheckFatal(err)
36+
37+
err = options.AddFlagValues("rewritehostsend", "--rewrite-host-end", "", nil, "add rule to replace request URL by host+request_URL, and skip further actions, format <sep><match><sep><replace>")
38+
serverError.CheckFatal(err)
39+
3140
err = options.AddFlagValues("rewrites", "--rewrite", "", nil, "add rule to replace request URL, format <sep><match><sep><replace>")
3241
serverError.CheckFatal(err)
3342

@@ -73,6 +82,18 @@ func CmdResultsToParams(results []*goNixArgParser.ParseResult) (params []*Param,
7382
param.IPDenies, _ = result.GetStrings("ipdenies")
7483
param.IPDenyFiles, _ = result.GetStrings("ipdenyfiles")
7584

85+
// rewrite hosts
86+
rewriteHosts, _ := result.GetStrings("rewritehosts")
87+
param.RewriteHosts = baseParam.SplitAllKeyValue(rewriteHosts)
88+
89+
// rewrite hosts post
90+
rewritesHostsPost, _ := result.GetStrings("rewritehostspost")
91+
param.RewriteHostsPost = baseParam.SplitAllKeyValue(rewritesHostsPost)
92+
93+
// rewrite hosts end
94+
rewriteHostsEnd, _ := result.GetStrings("rewritehostsend")
95+
param.RewriteHostsEnd = baseParam.SplitAllKeyValue(rewriteHostsEnd)
96+
7697
// rewrites
7798
rewrites, _ := result.GetStrings("rewrites")
7899
param.Rewrites = baseParam.SplitAllKeyValue(rewrites)

src/param/main.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ type Param struct {
1212
IPDenies []string
1313
IPDenyFiles []string
1414
// value: [match, replace]
15-
Rewrites [][2]string
16-
RewritesPost [][2]string
17-
RewritesEnd [][2]string
15+
RewriteHosts [][2]string
16+
RewriteHostsPost [][2]string
17+
RewriteHostsEnd [][2]string
18+
Rewrites [][2]string
19+
RewritesPost [][2]string
20+
RewritesEnd [][2]string
1821
// value: [match, replace, code?]
1922
Redirects [][3]string
2023
// value: [match, replace]

src/util/url.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import (
88

99
var matchPlaceHolders = [...]string{"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9"}
1010

11-
func ReplaceUrl(reMatch *regexp.Regexp, find, replace string) (*url.URL, error) {
12-
matches := reMatch.FindStringSubmatch(find)
11+
func ReplaceUrl(reMatch *regexp.Regexp, toMatch, newUrl string) (*url.URL, error) {
12+
matches := reMatch.FindStringSubmatch(toMatch)
1313
if len(matches) > len(matchPlaceHolders) {
1414
matches = matches[:len(matchPlaceHolders)]
1515
}
@@ -19,7 +19,7 @@ func ReplaceUrl(reMatch *regexp.Regexp, find, replace string) (*url.URL, error)
1919
replacerParam = append(replacerParam, matchPlaceHolders[i], matches[i])
2020
}
2121
replacer := strings.NewReplacer(replacerParam...)
22-
target := replacer.Replace(replace)
22+
target := replacer.Replace(newUrl)
2323

2424
if len(target) == 0 {
2525
target = "/"

0 commit comments

Comments
 (0)