forked from bfenetworks/bfe
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaction.go
194 lines (161 loc) · 4.65 KB
/
action.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
// Copyright (c) 2019 Baidu, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mod_errors
import (
"errors"
"fmt"
"io/ioutil"
"net/url"
"strconv"
"strings"
)
import (
"github.com/baidu/bfe/bfe_basic"
"github.com/baidu/bfe/bfe_http"
"github.com/baidu/bfe/bfe_util"
)
const (
RETURN = "RETURN"
REDIRECT = "REDIRECT"
)
type ActionFile struct {
Cmd *string // command of action
Params []string // params of action
}
type Action struct {
Cmd string // command of action
// for RETURN action
StatusCode int // status code
ContentType string // content type
ContentData string // content data
// for REDIRECT action
RedirectUrl string
}
type ActionFileList []ActionFile
// ActionFileCheck check ActionFile, return nil if check ok
func ActionFileCheck(conf ActionFile) error {
// check command
if conf.Cmd == nil {
return errors.New("no Cmd")
}
// check params
switch *conf.Cmd {
case RETURN:
// check number of params: statusCode, contentType, contentData
if len(conf.Params) != 3 {
return fmt.Errorf("params num should be 3 (%d)", len(conf.Params))
}
// check response code
responseCode, err := strconv.Atoi(conf.Params[0])
if err != nil {
return fmt.Errorf("Params[0]: invalid status code:%s", conf.Params[0])
}
if bfe_http.StatusTextGet(responseCode) == "" {
return fmt.Errorf("params[0]: invalid status code:%s", conf.Params[0])
}
codeClass := responseCode / 100
if codeClass != 2 && codeClass != 4 && codeClass != 5 {
return fmt.Errorf("params[0]: status code should be 2XX/4XX/5XX:%s", conf.Params[0])
}
// check content data
if err := bfe_util.CheckStaticFile(conf.Params[2], MaxPageSize); err != nil {
return fmt.Errorf("params[2] err:%s", err.Error())
}
case REDIRECT:
if len(conf.Params) != 1 {
return fmt.Errorf("params num should be 1 (%d)", len(conf.Params))
}
if _, err := url.Parse(conf.Params[0]); err != nil {
return fmt.Errorf("invalid url: %s", err)
}
default:
return fmt.Errorf("invalid command: %s", *conf.Cmd)
}
return nil
}
// ActionFileListCheck check ActionFileList, return nil if check ok
func ActionFileListCheck(actionList *ActionFileList) error {
if len(*actionList) != 1 {
return fmt.Errorf("ActionFileList: should contain 1 actions")
}
actions := *actionList
if err := ActionFileCheck(actions[0]); err != nil {
return fmt.Errorf("ActionFileList: %s", err)
}
return nil
}
func actionConvert(actionFile ActionFile) Action {
action := Action{}
action.Cmd = *actionFile.Cmd
switch action.Cmd {
case RETURN:
// convert status code
action.StatusCode, _ = strconv.Atoi(actionFile.Params[0])
// convert content type
action.ContentType = actionFile.Params[1]
// convert content data
rawData, _ := ioutil.ReadFile(actionFile.Params[2])
action.ContentData = string(rawData)
case REDIRECT:
action.RedirectUrl = actionFile.Params[0]
}
return action
}
func actionsConvert(actionFiles ActionFileList) []Action {
actions := make([]Action, 0)
for _, actionFile := range actionFiles {
action := actionConvert(actionFile)
actions = append(actions, action)
}
return actions
}
func ErrorsActionsDo(req *bfe_basic.Request, actions []Action) {
action := actions[0] // should contain 1 action
switch action.Cmd {
case RETURN:
doReturn(req, action)
case REDIRECT:
doRedirect(req, action)
}
}
func doReturn(req *bfe_basic.Request, action Action) {
prepareResponse(req)
res := req.HttpResponse
res.StatusCode = action.StatusCode
if len(action.ContentType) != 0 {
res.Header.Set("Content-Type", action.ContentType)
}
content := action.ContentData
res.Header.Set("Content-Length", strconv.Itoa(len(content)))
res.Body = ioutil.NopCloser(strings.NewReader(content))
}
func doRedirect(req *bfe_basic.Request, action Action) {
prepareResponse(req)
res := req.HttpResponse
res.StatusCode = 302
res.ContentLength = 0
res.Header.Set("Location", action.RedirectUrl)
res.Body = bfe_http.EofReader
}
func prepareResponse(req *bfe_basic.Request) {
res := req.HttpResponse
if res.Body != nil {
res.Body.Close()
}
res.Header = make(bfe_http.Header)
res.Header.Set("Server", "bfe")
res.Trailer = nil
res.TransferEncoding = nil
res.TLS = nil
}