/
plugin.go
141 lines (114 loc) · 2.97 KB
/
plugin.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package plugin
import (
"errors"
"fmt"
"net"
"net/http"
"sync"
hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
flatbuffers "github.com/google/flatbuffers/go"
inHTTP "github.com/finecloud/apisix-oauth2-plugin/internal/http"
"github.com/finecloud/apisix-oauth2-plugin/internal/util"
pkgHTTP "github.com/finecloud/apisix-oauth2-plugin/pkg/http"
"github.com/finecloud/apisix-oauth2-plugin/pkg/log"
)
type ParseConfFunc func(in []byte) (conf interface{}, err error)
type FilterFunc func(conf interface{}, w http.ResponseWriter, r pkgHTTP.Request)
type pluginOpts struct {
ParseConf ParseConfFunc
Filter FilterFunc
}
type pluginRegistries struct {
sync.Mutex
opts map[string]*pluginOpts
}
type ErrPluginRegistered struct {
name string
}
func (err ErrPluginRegistered) Error() string {
return fmt.Sprintf("plugin %s registered", err.name)
}
var (
pluginRegistry = pluginRegistries{opts: map[string]*pluginOpts{}}
ErrMissingName = errors.New("missing name")
ErrMissingParseConfMethod = errors.New("missing ParseConf method")
ErrMissingFilterMethod = errors.New("missing Filter method")
)
func RegisterPlugin(name string, pc ParseConfFunc, sv FilterFunc) error {
log.Infof("register plugin %s", name)
if name == "" {
return ErrMissingName
}
if pc == nil {
return ErrMissingParseConfMethod
}
if sv == nil {
return ErrMissingFilterMethod
}
opt := &pluginOpts{
ParseConf: pc,
Filter: sv,
}
pluginRegistry.Lock()
defer pluginRegistry.Unlock()
if _, found := pluginRegistry.opts[name]; found {
return ErrPluginRegistered{name}
}
pluginRegistry.opts[name] = opt
return nil
}
func findPlugin(name string) *pluginOpts {
if opt, found := pluginRegistry.opts[name]; found {
return opt
}
return nil
}
func filter(conf RuleConf, w *inHTTP.Response, r pkgHTTP.Request) error {
for _, c := range conf {
plugin := findPlugin(c.Name)
if plugin == nil {
log.Warnf("can't find plugin %s, skip", c.Name)
continue
}
log.Infof("run plugin %s", c.Name)
plugin.Filter(c.Value, w, r)
if w.HasChange() {
// response is generated, no need to continue
break
}
}
return nil
}
func reportAction(id uint32, req *inHTTP.Request, resp *inHTTP.Response) *flatbuffers.Builder {
builder := util.GetBuilder()
if resp != nil && resp.FetchChanges(id, builder) {
return builder
}
if req != nil && req.FetchChanges(id, builder) {
return builder
}
hrc.RespStart(builder)
hrc.RespAddId(builder, id)
res := hrc.RespEnd(builder)
builder.Finish(res)
return builder
}
func HTTPReqCall(buf []byte, conn net.Conn) (*flatbuffers.Builder, error) {
req := inHTTP.CreateRequest(buf)
req.BindConn(conn)
defer inHTTP.ReuseRequest(req)
resp := inHTTP.CreateResponse()
defer inHTTP.ReuseResponse(resp)
token := req.ConfToken()
conf, err := GetRuleConf(token)
if err != nil {
return nil, err
}
err = filter(conf, resp, req)
if err != nil {
return nil, err
}
id := req.ID()
builder := reportAction(id, req, resp)
return builder, nil
}