Skip to content

Commit c6d3756

Browse files
committed
feat: add header options
1 parent ab4a6ed commit c6d3756

File tree

9 files changed

+162
-28
lines changed

9 files changed

+162
-28
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ This means it is impossible to use legacy Go version to compile binaries for leg
6262
6363
--status-page <separator><status-code><separator><fs-path>
6464
When response status is `status-code`, respond with the file content from `fs-path`.
65+
66+
--header-add <separator><match><separator><name><separator><value>
67+
--header-set <separator><match><separator><name><separator><value>
68+
Add or set response header if URL(in the form of "/request/path?param=value")
69+
matches `match`.
6570
```
6671

6772
## Processing order
@@ -75,9 +80,12 @@ This means it is impossible to use legacy Go version to compile binaries for leg
7580
- `--rewrite-post` executed to transform the URL if matched.
7681
- `--rewrite-end` executed to transform the URL if matched, and skip rest of `--rewrite-end`, `--redirect`, `--proxy` and `--return`.
7782
- `--proxy` executed if URL matched, and stop processing.
83+
- `--header-add` and `--header-set` executed if URL matched, and stop processing.
7884
- `--return` executed if URL matched, and stop processing.
85+
- `--header-add` and `--header-set` executed if URL matched, and stop processing.
7986
- `--status-page` executed if status code matched, and stop processing.
8087
- ghfs internal process
88+
- `--header-add` and `--header-set` executed if URL matched.
8189
- `--to-status` executed if URL matched, and stop processing.
8290
- `--status-page` executed if status code matched, and stop processing.
8391
- `--status-page` executed if status code matched, and stop processing.

README.zh-CN.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ Extra HTTP File Server基于Go HTTP File Server,附带额外功能。
6161
6262
--status-page <分隔符><status-code><分隔符><fs-path>
6363
当响应状态码为`status-code`时,用文件`fs-path`的内容来响应。
64+
65+
--header-add <分隔符><match><分隔符><name><分隔符><value>
66+
--header-set <分隔符><match><分隔符><name><分隔符><value>
67+
当请求的URL(“/request/path?param=value”的形式)匹配正则表达式`match`时,
68+
添加或设置响应头。
6469
```
6570

6671
## 处理顺序
@@ -74,9 +79,12 @@ Extra HTTP File Server基于Go HTTP File Server,附带额外功能。
7479
- 如果URL匹配,执行`--rewrite-post`以转换URL。
7580
- 如果URL匹配,执行`--rewrite-end`以转换URL,跳过其余`--rewrite-end``--redirect``--proxy``--return`
7681
- 如果URL匹配,执行`--proxy`并停止处理。
82+
- 如果URL匹配,执行`--header-add``--header-set`并停止处理。
7783
- 如果URL匹配,执行`--return`并停止处理。
84+
- 如果URL匹配,执行`--header-add``--header-set`并停止处理。
7885
- 如果状态码匹配,执行`--status-page`并停止处理。
7986
- ghfs内部处理流程
87+
- 如果URL匹配,执行`--header-add``--header-set`
8088
- 如果URL匹配,执行`--to-status`并停止处理。
8189
- 如果状态码匹配,执行`--status-page`并停止处理。
8290
- 如果状态码匹配,执行`--status-page`并停止处理。

src/middleware/header.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package middleware
2+
3+
import (
4+
"mjpclab.dev/ghfs/src/middleware"
5+
"net/http"
6+
"regexp"
7+
)
8+
9+
func getHeaderAddMiddleware(arg [3]string) (middleware.Middleware, error) {
10+
var err error
11+
var reMatch *regexp.Regexp
12+
var name, value string
13+
14+
reMatch, err = regexp.Compile(arg[0])
15+
if err != nil {
16+
return nil, err
17+
}
18+
name = arg[1]
19+
value = arg[2]
20+
21+
return func(w http.ResponseWriter, r *http.Request, context *middleware.Context) (result middleware.ProcessResult) {
22+
result = middleware.GoNext
23+
24+
requestURI := r.URL.RequestURI() // request uri without prefix path
25+
if !reMatch.MatchString(requestURI) {
26+
return
27+
}
28+
29+
w.Header().Add(name, value)
30+
return
31+
}, nil
32+
}
33+
34+
func getHeaderSetMiddleware(arg [3]string) (middleware.Middleware, error) {
35+
var err error
36+
var reMatch *regexp.Regexp
37+
var name, value string
38+
39+
reMatch, err = regexp.Compile(arg[0])
40+
if err != nil {
41+
return nil, err
42+
}
43+
name = arg[1]
44+
value = arg[2]
45+
46+
return func(w http.ResponseWriter, r *http.Request, context *middleware.Context) (result middleware.ProcessResult) {
47+
result = middleware.GoNext
48+
49+
requestURI := r.URL.RequestURI() // request uri without prefix path
50+
if !reMatch.MatchString(requestURI) {
51+
return
52+
}
53+
54+
w.Header().Set(name, value)
55+
return
56+
}, nil
57+
}

src/middleware/main.go

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package middleware
33
import (
44
"errors"
55
"mjpclab.dev/ehfs/src/param"
6+
"mjpclab.dev/ehfs/src/util"
67
"mjpclab.dev/ghfs/src/middleware"
78
baseParam "mjpclab.dev/ghfs/src/param"
89
"mjpclab.dev/ghfs/src/serverError"
@@ -16,7 +17,24 @@ func ParamToMiddlewares(baseParam *baseParam.Param, param *param.Param) (preMids
1617
var err error
1718
var es []error
1819

19-
// status pages
20+
// headers
21+
headerMids := make([]middleware.Middleware, 0, len(param.HeaderAdds)+len(param.HeaderSets))
22+
for i := range param.HeaderAdds {
23+
mid, err = getHeaderAddMiddleware(param.HeaderAdds[i])
24+
errs = serverError.AppendError(errs, err)
25+
if mid != nil {
26+
headerMids = append(headerMids, mid)
27+
}
28+
}
29+
for i := range param.HeaderSets {
30+
mid, err = getHeaderSetMiddleware(param.HeaderSets[i])
31+
errs = serverError.AppendError(errs, err)
32+
if mid != nil {
33+
headerMids = append(headerMids, mid)
34+
}
35+
}
36+
37+
// dependent: status pages
2038
statusPageMids := make([]middleware.Middleware, 0, len(param.StatusPages))
2139
for i := range param.StatusPages {
2240
mid, err = getStatusPageMiddleware(param.StatusPages[i])
@@ -85,7 +103,7 @@ func ParamToMiddlewares(baseParam *baseParam.Param, param *param.Param) (preMids
85103
// proxies
86104
proxyMids := make([]middleware.Middleware, 0, len(param.Proxies))
87105
for i := range param.Proxies {
88-
mid, err = getProxyMiddleware(param.Proxies[i])
106+
mid, err = getProxyMiddleware(param.Proxies[i], headerMids)
89107
errs = serverError.AppendError(errs, err)
90108
if mid != nil {
91109
proxyMids = append(proxyMids, mid)
@@ -95,13 +113,15 @@ func ParamToMiddlewares(baseParam *baseParam.Param, param *param.Param) (preMids
95113
// returns
96114
returnMids := make([]middleware.Middleware, 0, len(param.Returns))
97115
for i := range param.Returns {
98-
mid, err = getReturnStatusMiddleware(param.Returns[i], statusPageMids)
116+
mid, err = getReturnStatusMiddleware(param.Returns[i], util.Concat(headerMids, statusPageMids))
99117
errs = serverError.AppendError(errs, err)
100118
if mid != nil {
101119
returnMids = append(returnMids, mid)
102120
}
103121
}
104122

123+
// headers (moved to dependent)
124+
105125
// to statuses
106126
toStatusMids := make([]middleware.Middleware, 0, len(param.ToStatuses))
107127
for i := range param.ToStatuses {
@@ -112,32 +132,25 @@ func ParamToMiddlewares(baseParam *baseParam.Param, param *param.Param) (preMids
112132
}
113133
}
114134

115-
// combine all mids
116-
preMids = make([]middleware.Middleware, 0, 0+
117-
len(ipAllowMids)+
118-
len(ipDenyMids)+
119-
len(rewriteMids)+
120-
len(rewritePostMids)+
121-
len(rewriteEndMids)+
122-
len(redirectMids)+
123-
len(proxyMids)+
124-
len(returnMids),
135+
// status pages (moved to dependent)
136+
137+
// combine mids
138+
preMids = util.Concat(
139+
ipAllowMids,
140+
ipDenyMids,
141+
rewriteMids,
142+
redirectMids,
143+
rewritePostMids,
144+
rewriteEndMids,
145+
proxyMids,
146+
returnMids,
125147
)
126-
preMids = append(preMids, ipAllowMids...)
127-
preMids = append(preMids, ipDenyMids...)
128-
preMids = append(preMids, rewriteMids...)
129-
preMids = append(preMids, redirectMids...)
130-
preMids = append(preMids, rewritePostMids...)
131-
preMids = append(preMids, rewriteEndMids...)
132-
preMids = append(preMids, proxyMids...)
133-
preMids = append(preMids, returnMids...)
134-
135-
postMids = make([]middleware.Middleware, 0, 0+
136-
len(toStatusMids)+
137-
len(statusPageMids),
148+
149+
postMids = util.Concat(
150+
headerMids,
151+
toStatusMids,
152+
statusPageMids,
138153
)
139-
postMids = append(postMids, toStatusMids...)
140-
postMids = append(postMids, statusPageMids...)
141154

142155
return
143156
}

src/middleware/proxy.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"regexp"
99
)
1010

11-
func getProxyMiddleware(arg [2]string) (middleware.Middleware, error) {
11+
func getProxyMiddleware(arg [2]string, preOutputMids []middleware.Middleware) (middleware.Middleware, error) {
1212
var err error
1313
var reMatch *regexp.Regexp
1414
var replace string
@@ -30,6 +30,10 @@ func getProxyMiddleware(arg [2]string) (middleware.Middleware, error) {
3030
}
3131

3232
result = middleware.Outputted
33+
for i := range preOutputMids {
34+
preOutputMids[i](w, r, context)
35+
}
36+
3337
targetUrl, err := util.ReplaceUrl(reMatch, requestURI, replace)
3438
if err != nil {
3539
util.LogError(context.Logger, err)

src/param/cli.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ func NewCliCmd() *goNixArgParser.Command {
4646
err = options.AddFlagValues("returns", "--return", "", nil, "add rule to return status code, format <sep><match><sep><code>")
4747
serverError.CheckFatal(err)
4848

49+
err = options.AddFlagValues("headeradds", "--header-add", "", nil, "add response header, format <sep><match><sep><name><sep><value>")
50+
serverError.CheckFatal(err)
51+
52+
err = options.AddFlagValues("headersets", "--header-set", "", nil, "set response header, format <sep><match><sep><name><sep><value>")
53+
serverError.CheckFatal(err)
54+
4955
err = options.AddFlagValues("tostatuses", "--to-status", "", nil, "add rule to move to status code after ghfs internal process, format <sep><match><sep><code>")
5056
serverError.CheckFatal(err)
5157

@@ -91,6 +97,12 @@ func CmdResultsToParams(results []*goNixArgParser.ParseResult) (params []*Param,
9197
returns, _ := result.GetStrings("returns")
9298
param.Returns = baseParam.SplitAllKeyValue(returns)
9399

100+
// headers
101+
headerAdds, _ := result.GetStrings("headeradds")
102+
param.HeaderAdds = toString3s(headerAdds)
103+
headerSets, _ := result.GetStrings("headersets")
104+
param.HeaderSets = toString3s(headerSets)
105+
94106
// to statuses
95107
toStatuses, _ := result.GetStrings("tostatuses")
96108
param.ToStatuses = baseParam.SplitAllKeyValue(toStatuses)

src/param/main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ type Param struct {
2222
// value: [match, code]
2323
Returns [][2]string
2424

25+
// value: [match, name, value]
26+
HeaderAdds [][3]string
27+
// value: [match, name, value]
28+
HeaderSets [][3]string
2529
// value: [match, code]
2630
ToStatuses [][2]string
2731
// value: [code, file]
@@ -55,6 +59,8 @@ func (param *Param) normalize() {
5559
param.Proxies = util.Filter(param.Proxies, nonEmptyKeyString2)
5660
param.Returns = util.Filter(param.Returns, nonEmptyKeyString2)
5761

62+
param.HeaderAdds = util.Filter(param.HeaderAdds, nonEmptyString3)
63+
param.HeaderSets = util.Filter(param.HeaderSets, nonEmptyString3)
5864
param.ToStatuses = util.Filter(param.ToStatuses, nonEmptyKeyString2)
5965
param.StatusPages = util.Filter(param.StatusPages, nonEmptyKeyString2)
6066

src/param/util.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ func nonEmptyString(item string) bool {
88
return len(item) > 0
99
}
1010

11+
func nonEmptyString2(item [2]string) bool {
12+
return len(item[0]) > 0 && len(item[1]) > 0
13+
}
14+
15+
func nonEmptyString3(item [3]string) bool {
16+
return len(item[0]) > 0 && len(item[1]) > 0 && len(item[2]) > 0
17+
}
18+
1119
func nonEmptyKeyString2(item [2]string) bool {
1220
return len(item[0]) > 0
1321
}
@@ -16,6 +24,10 @@ func nonEmptyKeyString3(item [3]string) bool {
1624
return len(item[0]) > 0
1725
}
1826

27+
func nonEmptyKeysString3(item [3]string) bool {
28+
return len(item[0]) > 0 && len(item[1]) > 0
29+
}
30+
1931
func toString3s(inputs []string) (outputs [][3]string) {
2032
allKeyValues := baseParam.SplitAllKeyValues(inputs)
2133
outputs = make([][3]string, len(allKeyValues))

src/util/slice.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,17 @@ func Filter[T any](inputs []T, filterFunc func(T) bool) (outputs []T) {
99
}
1010
return
1111
}
12+
13+
func Concat[T any](inputs ...[]T) (outputs []T) {
14+
allLen := 0
15+
for i, length := 0, len(inputs); i < length; i++ {
16+
allLen += len(inputs[i])
17+
}
18+
19+
outputs = make([]T, 0, allLen)
20+
for i := range inputs {
21+
outputs = append(outputs, inputs[i]...)
22+
}
23+
24+
return
25+
}

0 commit comments

Comments
 (0)