正在显示
21 个修改的文件
包含
0 行增加
和
4895 行删除
1 | -language: go | ||
2 | - | ||
3 | -go: | ||
4 | - - "1.9.2" | ||
5 | - - "1.10.3" | ||
6 | -services: | ||
7 | - - redis-server | ||
8 | - - mysql | ||
9 | - - postgresql | ||
10 | - - memcached | ||
11 | -env: | ||
12 | - - ORM_DRIVER=sqlite3 ORM_SOURCE=$TRAVIS_BUILD_DIR/orm_test.db | ||
13 | - - ORM_DRIVER=postgres ORM_SOURCE="user=postgres dbname=orm_test sslmode=disable" | ||
14 | -before_install: | ||
15 | - - git clone git://github.com/ideawu/ssdb.git | ||
16 | - - cd ssdb | ||
17 | - - make | ||
18 | - - cd .. | ||
19 | -install: | ||
20 | - - go get github.com/lib/pq | ||
21 | - - go get github.com/go-sql-driver/mysql | ||
22 | - - go get github.com/mattn/go-sqlite3 | ||
23 | - - go get github.com/bradfitz/gomemcache/memcache | ||
24 | - - go get github.com/gomodule/redigo/redis | ||
25 | - - go get github.com/beego/x2j | ||
26 | - - go get github.com/couchbase/go-couchbase | ||
27 | - - go get github.com/beego/goyaml2 | ||
28 | - - go get gopkg.in/yaml.v2 | ||
29 | - - go get github.com/belogik/goes | ||
30 | - - go get github.com/siddontang/ledisdb/config | ||
31 | - - go get github.com/siddontang/ledisdb/ledis | ||
32 | - - go get github.com/ssdb/gossdb/ssdb | ||
33 | - - go get github.com/cloudflare/golz4 | ||
34 | - - go get github.com/gogo/protobuf/proto | ||
35 | - - go get github.com/Knetic/govaluate | ||
36 | - - go get github.com/casbin/casbin | ||
37 | - - go get -u honnef.co/go/tools/cmd/gosimple | ||
38 | - - go get -u github.com/mdempsky/unconvert | ||
39 | - - go get -u github.com/gordonklaus/ineffassign | ||
40 | - - go get -u github.com/golang/lint/golint | ||
41 | - - go get -u github.com/go-redis/redis | ||
42 | -before_script: | ||
43 | - - psql --version | ||
44 | - - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" | ||
45 | - - sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi" | ||
46 | - - sh -c "if [ '$ORM_DRIVER' = 'sqlite' ]; then touch $TRAVIS_BUILD_DIR/orm_test.db; fi" | ||
47 | - - sh -c "if [ $(go version) == *1.[5-9]* ]; then go get github.com/golang/lint/golint; golint ./...; fi" | ||
48 | - - sh -c "if [ $(go version) == *1.[5-9]* ]; then go tool vet .; fi" | ||
49 | - - mkdir -p res/var | ||
50 | - - ./ssdb/ssdb-server ./ssdb/ssdb.conf -d | ||
51 | -after_script: | ||
52 | - -killall -w ssdb-server | ||
53 | - - rm -rf ./res/var/* | ||
54 | -script: | ||
55 | - - go test -v ./... | ||
56 | - - gosimple -ignore "$(cat .gosimpleignore)" $(go list ./... | grep -v /vendor/) | ||
57 | - - unconvert $(go list ./... | grep -v /vendor/) | ||
58 | - - ineffassign . | ||
59 | - - find . ! \( -path './vendor' -prune \) -type f -name '*.go' -print0 | xargs -0 gofmt -l -s | ||
60 | - - golint ./... | ||
61 | -addons: | ||
62 | - postgresql: "9.4" |
1 | -# Contributing to beego | ||
2 | - | ||
3 | -beego is an open source project. | ||
4 | - | ||
5 | -It is the work of hundreds of contributors. We appreciate your help! | ||
6 | - | ||
7 | -Here are instructions to get you started. They are probably not perfect, | ||
8 | -please let us know if anything feels wrong or incomplete. | ||
9 | - | ||
10 | -## Contribution guidelines | ||
11 | - | ||
12 | -### Pull requests | ||
13 | - | ||
14 | -First of all. beego follow the gitflow. So please send you pull request | ||
15 | -to **develop** branch. We will close the pull request to master branch. | ||
16 | - | ||
17 | -We are always happy to receive pull requests, and do our best to | ||
18 | -review them as fast as possible. Not sure if that typo is worth a pull | ||
19 | -request? Do it! We will appreciate it. | ||
20 | - | ||
21 | -If your pull request is not accepted on the first try, don't be | ||
22 | -discouraged! Sometimes we can make a mistake, please do more explaining | ||
23 | -for us. We will appreciate it. | ||
24 | - | ||
25 | -We're trying very hard to keep beego simple and fast. We don't want it | ||
26 | -to do everything for everybody. This means that we might decide against | ||
27 | -incorporating a new feature. But we will give you some advice on how to | ||
28 | -do it in other way. | ||
29 | - | ||
30 | -### Create issues | ||
31 | - | ||
32 | -Any significant improvement should be documented as [a GitHub | ||
33 | -issue](https://github.com/astaxie/beego/issues) before anybody | ||
34 | -starts working on it. | ||
35 | - | ||
36 | -Also when filing an issue, make sure to answer these five questions: | ||
37 | - | ||
38 | -- What version of beego are you using (bee version)? | ||
39 | -- What operating system and processor architecture are you using? | ||
40 | -- What did you do? | ||
41 | -- What did you expect to see? | ||
42 | -- What did you see instead? | ||
43 | - | ||
44 | -### but check existing issues and docs first! | ||
45 | - | ||
46 | -Please take a moment to check that an issue doesn't already exist | ||
47 | -documenting your bug report or improvement proposal. If it does, it | ||
48 | -never hurts to add a quick "+1" or "I have this problem too". This will | ||
49 | -help prioritize the most common problems and requests. | ||
50 | - | ||
51 | -Also if you don't know how to use it. please make sure you have read though | ||
52 | -the docs in http://beego.me/docs |
vendor/github.com/astaxie/beego/LICENSE
已删除
100644 → 0
1 | -Copyright 2014 astaxie | ||
2 | - | ||
3 | -Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | -you may not use this file except in compliance with the License. | ||
5 | -You may obtain a copy of the License at | ||
6 | - | ||
7 | - http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | - | ||
9 | -Unless required by applicable law or agreed to in writing, software | ||
10 | -distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | -See the License for the specific language governing permissions and | ||
13 | -limitations under the License. |
1 | -# Beego [![Build Status](https://travis-ci.org/astaxie/beego.svg?branch=master)](https://travis-ci.org/astaxie/beego) [![GoDoc](http://godoc.org/github.com/astaxie/beego?status.svg)](http://godoc.org/github.com/astaxie/beego) [![Foundation](https://img.shields.io/badge/Golang-Foundation-green.svg)](http://golangfoundation.org) [![Go Report Card](https://goreportcard.com/badge/github.com/astaxie/beego)](https://goreportcard.com/report/github.com/astaxie/beego) | ||
2 | - | ||
3 | - | ||
4 | -beego is used for rapid development of RESTful APIs, web apps and backend services in Go. | ||
5 | -It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific features such as interfaces and struct embedding. | ||
6 | - | ||
7 | -###### More info at [beego.me](http://beego.me). | ||
8 | - | ||
9 | -## Quick Start | ||
10 | - | ||
11 | -#### Download and install | ||
12 | - | ||
13 | - go get github.com/astaxie/beego | ||
14 | - | ||
15 | -#### Create file `hello.go` | ||
16 | -```go | ||
17 | -package main | ||
18 | - | ||
19 | -import "github.com/astaxie/beego" | ||
20 | - | ||
21 | -func main(){ | ||
22 | - beego.Run() | ||
23 | -} | ||
24 | -``` | ||
25 | -#### Build and run | ||
26 | - | ||
27 | - go build hello.go | ||
28 | - ./hello | ||
29 | - | ||
30 | -#### Go to [http://localhost:8080](http://localhost:8080) | ||
31 | - | ||
32 | -Congratulations! You've just built your first **beego** app. | ||
33 | - | ||
34 | -###### Please see [Documentation](http://beego.me/docs) for more. | ||
35 | - | ||
36 | -## Features | ||
37 | - | ||
38 | -* RESTful support | ||
39 | -* MVC architecture | ||
40 | -* Modularity | ||
41 | -* Auto API documents | ||
42 | -* Annotation router | ||
43 | -* Namespace | ||
44 | -* Powerful development tools | ||
45 | -* Full stack for Web & API | ||
46 | - | ||
47 | -## Documentation | ||
48 | - | ||
49 | -* [English](http://beego.me/docs/intro/) | ||
50 | -* [中文文档](http://beego.me/docs/intro/) | ||
51 | -* [Русский](http://beego.me/docs/intro/) | ||
52 | - | ||
53 | -## Community | ||
54 | - | ||
55 | -* [http://beego.me/community](http://beego.me/community) | ||
56 | -* Welcome to join us in Slack: [https://beego.slack.com](https://beego.slack.com), you can get invited from [here](https://github.com/beego/beedoc/issues/232) | ||
57 | - | ||
58 | -## License | ||
59 | - | ||
60 | -beego source code is licensed under the Apache Licence, Version 2.0 | ||
61 | -(http://www.apache.org/licenses/LICENSE-2.0.html). |
vendor/github.com/astaxie/beego/admin.go
已删除
100644 → 0
1 | -// Copyright 2014 beego Author. All Rights Reserved. | ||
2 | -// | ||
3 | -// Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | -// you may not use this file except in compliance with the License. | ||
5 | -// You may obtain a copy of the License at | ||
6 | -// | ||
7 | -// http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | -// | ||
9 | -// Unless required by applicable law or agreed to in writing, software | ||
10 | -// distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | -// See the License for the specific language governing permissions and | ||
13 | -// limitations under the License. | ||
14 | - | ||
15 | -package beego | ||
16 | - | ||
17 | -import ( | ||
18 | - "bytes" | ||
19 | - "encoding/json" | ||
20 | - "fmt" | ||
21 | - "net/http" | ||
22 | - "os" | ||
23 | - "text/template" | ||
24 | - "time" | ||
25 | - | ||
26 | - "reflect" | ||
27 | - | ||
28 | - "github.com/astaxie/beego/grace" | ||
29 | - "github.com/astaxie/beego/logs" | ||
30 | - "github.com/astaxie/beego/toolbox" | ||
31 | - "github.com/astaxie/beego/utils" | ||
32 | -) | ||
33 | - | ||
34 | -// BeeAdminApp is the default adminApp used by admin module. | ||
35 | -var beeAdminApp *adminApp | ||
36 | - | ||
37 | -// FilterMonitorFunc is default monitor filter when admin module is enable. | ||
38 | -// if this func returns, admin module records qbs for this request by condition of this function logic. | ||
39 | -// usage: | ||
40 | -// func MyFilterMonitor(method, requestPath string, t time.Duration, pattern string, statusCode int) bool { | ||
41 | -// if method == "POST" { | ||
42 | -// return false | ||
43 | -// } | ||
44 | -// if t.Nanoseconds() < 100 { | ||
45 | -// return false | ||
46 | -// } | ||
47 | -// if strings.HasPrefix(requestPath, "/astaxie") { | ||
48 | -// return false | ||
49 | -// } | ||
50 | -// return true | ||
51 | -// } | ||
52 | -// beego.FilterMonitorFunc = MyFilterMonitor. | ||
53 | -var FilterMonitorFunc func(string, string, time.Duration, string, int) bool | ||
54 | - | ||
55 | -func init() { | ||
56 | - beeAdminApp = &adminApp{ | ||
57 | - routers: make(map[string]http.HandlerFunc), | ||
58 | - } | ||
59 | - beeAdminApp.Route("/", adminIndex) | ||
60 | - beeAdminApp.Route("/qps", qpsIndex) | ||
61 | - beeAdminApp.Route("/prof", profIndex) | ||
62 | - beeAdminApp.Route("/healthcheck", healthcheck) | ||
63 | - beeAdminApp.Route("/task", taskStatus) | ||
64 | - beeAdminApp.Route("/listconf", listConf) | ||
65 | - FilterMonitorFunc = func(string, string, time.Duration, string, int) bool { return true } | ||
66 | -} | ||
67 | - | ||
68 | -// AdminIndex is the default http.Handler for admin module. | ||
69 | -// it matches url pattern "/". | ||
70 | -func adminIndex(rw http.ResponseWriter, r *http.Request) { | ||
71 | - execTpl(rw, map[interface{}]interface{}{}, indexTpl, defaultScriptsTpl) | ||
72 | -} | ||
73 | - | ||
74 | -// QpsIndex is the http.Handler for writing qbs statistics map result info in http.ResponseWriter. | ||
75 | -// it's registered with url pattern "/qbs" in admin module. | ||
76 | -func qpsIndex(rw http.ResponseWriter, r *http.Request) { | ||
77 | - data := make(map[interface{}]interface{}) | ||
78 | - data["Content"] = toolbox.StatisticsMap.GetMap() | ||
79 | - | ||
80 | - // do html escape before display path, avoid xss | ||
81 | - if content, ok := (data["Content"]).(map[string]interface{}); ok { | ||
82 | - if resultLists, ok := (content["Data"]).([][]string); ok { | ||
83 | - for i := range resultLists { | ||
84 | - if len(resultLists[i]) > 0 { | ||
85 | - resultLists[i][0] = template.HTMLEscapeString(resultLists[i][0]) | ||
86 | - } | ||
87 | - } | ||
88 | - } | ||
89 | - } | ||
90 | - | ||
91 | - execTpl(rw, data, qpsTpl, defaultScriptsTpl) | ||
92 | -} | ||
93 | - | ||
94 | -// ListConf is the http.Handler of displaying all beego configuration values as key/value pair. | ||
95 | -// it's registered with url pattern "/listconf" in admin module. | ||
96 | -func listConf(rw http.ResponseWriter, r *http.Request) { | ||
97 | - r.ParseForm() | ||
98 | - command := r.Form.Get("command") | ||
99 | - if command == "" { | ||
100 | - rw.Write([]byte("command not support")) | ||
101 | - return | ||
102 | - } | ||
103 | - | ||
104 | - data := make(map[interface{}]interface{}) | ||
105 | - switch command { | ||
106 | - case "conf": | ||
107 | - m := make(map[string]interface{}) | ||
108 | - list("BConfig", BConfig, m) | ||
109 | - m["AppConfigPath"] = appConfigPath | ||
110 | - m["AppConfigProvider"] = appConfigProvider | ||
111 | - tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) | ||
112 | - tmpl = template.Must(tmpl.Parse(configTpl)) | ||
113 | - tmpl = template.Must(tmpl.Parse(defaultScriptsTpl)) | ||
114 | - | ||
115 | - data["Content"] = m | ||
116 | - | ||
117 | - tmpl.Execute(rw, data) | ||
118 | - | ||
119 | - case "router": | ||
120 | - content := PrintTree() | ||
121 | - content["Fields"] = []string{ | ||
122 | - "Router Pattern", | ||
123 | - "Methods", | ||
124 | - "Controller", | ||
125 | - } | ||
126 | - data["Content"] = content | ||
127 | - data["Title"] = "Routers" | ||
128 | - execTpl(rw, data, routerAndFilterTpl, defaultScriptsTpl) | ||
129 | - case "filter": | ||
130 | - var ( | ||
131 | - content = map[string]interface{}{ | ||
132 | - "Fields": []string{ | ||
133 | - "Router Pattern", | ||
134 | - "Filter Function", | ||
135 | - }, | ||
136 | - } | ||
137 | - filterTypes = []string{} | ||
138 | - filterTypeData = make(map[string]interface{}) | ||
139 | - ) | ||
140 | - | ||
141 | - if BeeApp.Handlers.enableFilter { | ||
142 | - var filterType string | ||
143 | - for k, fr := range map[int]string{ | ||
144 | - BeforeStatic: "Before Static", | ||
145 | - BeforeRouter: "Before Router", | ||
146 | - BeforeExec: "Before Exec", | ||
147 | - AfterExec: "After Exec", | ||
148 | - FinishRouter: "Finish Router"} { | ||
149 | - if bf := BeeApp.Handlers.filters[k]; len(bf) > 0 { | ||
150 | - filterType = fr | ||
151 | - filterTypes = append(filterTypes, filterType) | ||
152 | - resultList := new([][]string) | ||
153 | - for _, f := range bf { | ||
154 | - var result = []string{ | ||
155 | - f.pattern, | ||
156 | - utils.GetFuncName(f.filterFunc), | ||
157 | - } | ||
158 | - *resultList = append(*resultList, result) | ||
159 | - } | ||
160 | - filterTypeData[filterType] = resultList | ||
161 | - } | ||
162 | - } | ||
163 | - } | ||
164 | - | ||
165 | - content["Data"] = filterTypeData | ||
166 | - content["Methods"] = filterTypes | ||
167 | - | ||
168 | - data["Content"] = content | ||
169 | - data["Title"] = "Filters" | ||
170 | - execTpl(rw, data, routerAndFilterTpl, defaultScriptsTpl) | ||
171 | - default: | ||
172 | - rw.Write([]byte("command not support")) | ||
173 | - } | ||
174 | -} | ||
175 | - | ||
176 | -func list(root string, p interface{}, m map[string]interface{}) { | ||
177 | - pt := reflect.TypeOf(p) | ||
178 | - pv := reflect.ValueOf(p) | ||
179 | - if pt.Kind() == reflect.Ptr { | ||
180 | - pt = pt.Elem() | ||
181 | - pv = pv.Elem() | ||
182 | - } | ||
183 | - for i := 0; i < pv.NumField(); i++ { | ||
184 | - var key string | ||
185 | - if root == "" { | ||
186 | - key = pt.Field(i).Name | ||
187 | - } else { | ||
188 | - key = root + "." + pt.Field(i).Name | ||
189 | - } | ||
190 | - if pv.Field(i).Kind() == reflect.Struct { | ||
191 | - list(key, pv.Field(i).Interface(), m) | ||
192 | - } else { | ||
193 | - m[key] = pv.Field(i).Interface() | ||
194 | - } | ||
195 | - } | ||
196 | -} | ||
197 | - | ||
198 | -// PrintTree prints all registered routers. | ||
199 | -func PrintTree() map[string]interface{} { | ||
200 | - var ( | ||
201 | - content = map[string]interface{}{} | ||
202 | - methods = []string{} | ||
203 | - methodsData = make(map[string]interface{}) | ||
204 | - ) | ||
205 | - for method, t := range BeeApp.Handlers.routers { | ||
206 | - | ||
207 | - resultList := new([][]string) | ||
208 | - | ||
209 | - printTree(resultList, t) | ||
210 | - | ||
211 | - methods = append(methods, method) | ||
212 | - methodsData[method] = resultList | ||
213 | - } | ||
214 | - | ||
215 | - content["Data"] = methodsData | ||
216 | - content["Methods"] = methods | ||
217 | - return content | ||
218 | -} | ||
219 | - | ||
220 | -func printTree(resultList *[][]string, t *Tree) { | ||
221 | - for _, tr := range t.fixrouters { | ||
222 | - printTree(resultList, tr) | ||
223 | - } | ||
224 | - if t.wildcard != nil { | ||
225 | - printTree(resultList, t.wildcard) | ||
226 | - } | ||
227 | - for _, l := range t.leaves { | ||
228 | - if v, ok := l.runObject.(*ControllerInfo); ok { | ||
229 | - if v.routerType == routerTypeBeego { | ||
230 | - var result = []string{ | ||
231 | - v.pattern, | ||
232 | - fmt.Sprintf("%s", v.methods), | ||
233 | - v.controllerType.String(), | ||
234 | - } | ||
235 | - *resultList = append(*resultList, result) | ||
236 | - } else if v.routerType == routerTypeRESTFul { | ||
237 | - var result = []string{ | ||
238 | - v.pattern, | ||
239 | - fmt.Sprintf("%s", v.methods), | ||
240 | - "", | ||
241 | - } | ||
242 | - *resultList = append(*resultList, result) | ||
243 | - } else if v.routerType == routerTypeHandler { | ||
244 | - var result = []string{ | ||
245 | - v.pattern, | ||
246 | - "", | ||
247 | - "", | ||
248 | - } | ||
249 | - *resultList = append(*resultList, result) | ||
250 | - } | ||
251 | - } | ||
252 | - } | ||
253 | -} | ||
254 | - | ||
255 | -// ProfIndex is a http.Handler for showing profile command. | ||
256 | -// it's in url pattern "/prof" in admin module. | ||
257 | -func profIndex(rw http.ResponseWriter, r *http.Request) { | ||
258 | - r.ParseForm() | ||
259 | - command := r.Form.Get("command") | ||
260 | - if command == "" { | ||
261 | - return | ||
262 | - } | ||
263 | - | ||
264 | - var ( | ||
265 | - format = r.Form.Get("format") | ||
266 | - data = make(map[interface{}]interface{}) | ||
267 | - result bytes.Buffer | ||
268 | - ) | ||
269 | - toolbox.ProcessInput(command, &result) | ||
270 | - data["Content"] = result.String() | ||
271 | - | ||
272 | - if format == "json" && command == "gc summary" { | ||
273 | - dataJSON, err := json.Marshal(data) | ||
274 | - if err != nil { | ||
275 | - http.Error(rw, err.Error(), http.StatusInternalServerError) | ||
276 | - return | ||
277 | - } | ||
278 | - | ||
279 | - rw.Header().Set("Content-Type", "application/json") | ||
280 | - rw.Write(dataJSON) | ||
281 | - return | ||
282 | - } | ||
283 | - | ||
284 | - data["Title"] = command | ||
285 | - defaultTpl := defaultScriptsTpl | ||
286 | - if command == "gc summary" { | ||
287 | - defaultTpl = gcAjaxTpl | ||
288 | - } | ||
289 | - execTpl(rw, data, profillingTpl, defaultTpl) | ||
290 | -} | ||
291 | - | ||
292 | -// Healthcheck is a http.Handler calling health checking and showing the result. | ||
293 | -// it's in "/healthcheck" pattern in admin module. | ||
294 | -func healthcheck(rw http.ResponseWriter, req *http.Request) { | ||
295 | - var ( | ||
296 | - result []string | ||
297 | - data = make(map[interface{}]interface{}) | ||
298 | - resultList = new([][]string) | ||
299 | - content = map[string]interface{}{ | ||
300 | - "Fields": []string{"Name", "Message", "Status"}, | ||
301 | - } | ||
302 | - ) | ||
303 | - | ||
304 | - for name, h := range toolbox.AdminCheckList { | ||
305 | - if err := h.Check(); err != nil { | ||
306 | - result = []string{ | ||
307 | - "error", | ||
308 | - name, | ||
309 | - err.Error(), | ||
310 | - } | ||
311 | - } else { | ||
312 | - result = []string{ | ||
313 | - "success", | ||
314 | - name, | ||
315 | - "OK", | ||
316 | - } | ||
317 | - } | ||
318 | - *resultList = append(*resultList, result) | ||
319 | - } | ||
320 | - | ||
321 | - content["Data"] = resultList | ||
322 | - data["Content"] = content | ||
323 | - data["Title"] = "Health Check" | ||
324 | - execTpl(rw, data, healthCheckTpl, defaultScriptsTpl) | ||
325 | -} | ||
326 | - | ||
327 | -// TaskStatus is a http.Handler with running task status (task name, status and the last execution). | ||
328 | -// it's in "/task" pattern in admin module. | ||
329 | -func taskStatus(rw http.ResponseWriter, req *http.Request) { | ||
330 | - data := make(map[interface{}]interface{}) | ||
331 | - | ||
332 | - // Run Task | ||
333 | - req.ParseForm() | ||
334 | - taskname := req.Form.Get("taskname") | ||
335 | - if taskname != "" { | ||
336 | - if t, ok := toolbox.AdminTaskList[taskname]; ok { | ||
337 | - if err := t.Run(); err != nil { | ||
338 | - data["Message"] = []string{"error", fmt.Sprintf("%s", err)} | ||
339 | - } | ||
340 | - data["Message"] = []string{"success", fmt.Sprintf("%s run success,Now the Status is <br>%s", taskname, t.GetStatus())} | ||
341 | - } else { | ||
342 | - data["Message"] = []string{"warning", fmt.Sprintf("there's no task which named: %s", taskname)} | ||
343 | - } | ||
344 | - } | ||
345 | - | ||
346 | - // List Tasks | ||
347 | - content := make(map[string]interface{}) | ||
348 | - resultList := new([][]string) | ||
349 | - var fields = []string{ | ||
350 | - "Task Name", | ||
351 | - "Task Spec", | ||
352 | - "Task Status", | ||
353 | - "Last Time", | ||
354 | - "", | ||
355 | - } | ||
356 | - for tname, tk := range toolbox.AdminTaskList { | ||
357 | - result := []string{ | ||
358 | - tname, | ||
359 | - tk.GetSpec(), | ||
360 | - tk.GetStatus(), | ||
361 | - tk.GetPrev().String(), | ||
362 | - } | ||
363 | - *resultList = append(*resultList, result) | ||
364 | - } | ||
365 | - | ||
366 | - content["Fields"] = fields | ||
367 | - content["Data"] = resultList | ||
368 | - data["Content"] = content | ||
369 | - data["Title"] = "Tasks" | ||
370 | - execTpl(rw, data, tasksTpl, defaultScriptsTpl) | ||
371 | -} | ||
372 | - | ||
373 | -func execTpl(rw http.ResponseWriter, data map[interface{}]interface{}, tpls ...string) { | ||
374 | - tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) | ||
375 | - for _, tpl := range tpls { | ||
376 | - tmpl = template.Must(tmpl.Parse(tpl)) | ||
377 | - } | ||
378 | - tmpl.Execute(rw, data) | ||
379 | -} | ||
380 | - | ||
381 | -// adminApp is an http.HandlerFunc map used as beeAdminApp. | ||
382 | -type adminApp struct { | ||
383 | - routers map[string]http.HandlerFunc | ||
384 | -} | ||
385 | - | ||
386 | -// Route adds http.HandlerFunc to adminApp with url pattern. | ||
387 | -func (admin *adminApp) Route(pattern string, f http.HandlerFunc) { | ||
388 | - admin.routers[pattern] = f | ||
389 | -} | ||
390 | - | ||
391 | -// Run adminApp http server. | ||
392 | -// Its addr is defined in configuration file as adminhttpaddr and adminhttpport. | ||
393 | -func (admin *adminApp) Run() { | ||
394 | - if len(toolbox.AdminTaskList) > 0 { | ||
395 | - toolbox.StartTask() | ||
396 | - } | ||
397 | - addr := BConfig.Listen.AdminAddr | ||
398 | - | ||
399 | - if BConfig.Listen.AdminPort != 0 { | ||
400 | - addr = fmt.Sprintf("%s:%d", BConfig.Listen.AdminAddr, BConfig.Listen.AdminPort) | ||
401 | - } | ||
402 | - for p, f := range admin.routers { | ||
403 | - http.Handle(p, f) | ||
404 | - } | ||
405 | - logs.Info("Admin server Running on %s", addr) | ||
406 | - | ||
407 | - var err error | ||
408 | - if BConfig.Listen.Graceful { | ||
409 | - err = grace.ListenAndServe(addr, nil) | ||
410 | - } else { | ||
411 | - err = http.ListenAndServe(addr, nil) | ||
412 | - } | ||
413 | - if err != nil { | ||
414 | - logs.Critical("Admin ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid())) | ||
415 | - } | ||
416 | -} |
1 | -// Copyright 2014 beego Author. All Rights Reserved. | ||
2 | -// | ||
3 | -// Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | -// you may not use this file except in compliance with the License. | ||
5 | -// You may obtain a copy of the License at | ||
6 | -// | ||
7 | -// http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | -// | ||
9 | -// Unless required by applicable law or agreed to in writing, software | ||
10 | -// distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | -// See the License for the specific language governing permissions and | ||
13 | -// limitations under the License. | ||
14 | - | ||
15 | -package beego | ||
16 | - | ||
17 | -var indexTpl = ` | ||
18 | -{{define "content"}} | ||
19 | -<h1>Beego Admin Dashboard</h1> | ||
20 | -<p> | ||
21 | -For detail usage please check our document: | ||
22 | -</p> | ||
23 | -<p> | ||
24 | -<a target="_blank" href="http://beego.me/docs/module/toolbox.md">Toolbox</a> | ||
25 | -</p> | ||
26 | -<p> | ||
27 | -<a target="_blank" href="http://beego.me/docs/advantage/monitor.md">Live Monitor</a> | ||
28 | -</p> | ||
29 | -{{.Content}} | ||
30 | -{{end}}` | ||
31 | - | ||
32 | -var profillingTpl = ` | ||
33 | -{{define "content"}} | ||
34 | -<h1>{{.Title}}</h1> | ||
35 | -<pre id="content"> | ||
36 | -<div>{{.Content}}</div> | ||
37 | -</pre> | ||
38 | -{{end}}` | ||
39 | - | ||
40 | -var defaultScriptsTpl = `` | ||
41 | - | ||
42 | -var gcAjaxTpl = ` | ||
43 | -{{define "scripts"}} | ||
44 | -<script type="text/javascript"> | ||
45 | - var app = app || {}; | ||
46 | -(function() { | ||
47 | - app.$el = $('#content'); | ||
48 | - app.getGc = function() { | ||
49 | - var that = this; | ||
50 | - $.ajax("/prof?command=gc%20summary&format=json").done(function(data) { | ||
51 | - that.$el.append($('<p>' + data.Content + '</p>')); | ||
52 | - }); | ||
53 | - }; | ||
54 | - $(document).ready(function() { | ||
55 | - setInterval(function() { | ||
56 | - app.getGc(); | ||
57 | - }, 3000); | ||
58 | - }); | ||
59 | -})(); | ||
60 | -</script> | ||
61 | -{{end}} | ||
62 | -` | ||
63 | - | ||
64 | -var qpsTpl = `{{define "content"}} | ||
65 | -<h1>Requests statistics</h1> | ||
66 | -<table class="table table-striped table-hover "> | ||
67 | - <thead> | ||
68 | - <tr> | ||
69 | - {{range .Content.Fields}} | ||
70 | - <th> | ||
71 | - {{.}} | ||
72 | - </th> | ||
73 | - {{end}} | ||
74 | - </tr> | ||
75 | - </thead> | ||
76 | - | ||
77 | - <tbody> | ||
78 | - {{range $i, $elem := .Content.Data}} | ||
79 | - | ||
80 | - <tr> | ||
81 | - <td>{{index $elem 0}}</td> | ||
82 | - <td>{{index $elem 1}}</td> | ||
83 | - <td>{{index $elem 2}}</td> | ||
84 | - <td data-order="{{index $elem 3}}">{{index $elem 4}}</td> | ||
85 | - <td data-order="{{index $elem 5}}">{{index $elem 6}}</td> | ||
86 | - <td data-order="{{index $elem 7}}">{{index $elem 8}}</td> | ||
87 | - <td data-order="{{index $elem 9}}">{{index $elem 10}}</td> | ||
88 | - </tr> | ||
89 | - {{end}} | ||
90 | - </tbody> | ||
91 | - | ||
92 | -</table> | ||
93 | -{{end}}` | ||
94 | - | ||
95 | -var configTpl = ` | ||
96 | -{{define "content"}} | ||
97 | -<h1>Configurations</h1> | ||
98 | -<pre> | ||
99 | -{{range $index, $elem := .Content}} | ||
100 | -{{$index}}={{$elem}} | ||
101 | -{{end}} | ||
102 | -</pre> | ||
103 | -{{end}} | ||
104 | -` | ||
105 | - | ||
106 | -var routerAndFilterTpl = `{{define "content"}} | ||
107 | - | ||
108 | - | ||
109 | -<h1>{{.Title}}</h1> | ||
110 | - | ||
111 | -{{range .Content.Methods}} | ||
112 | - | ||
113 | -<div class="panel panel-default"> | ||
114 | -<div class="panel-heading lead success"><strong>{{.}}</strong></div> | ||
115 | -<div class="panel-body"> | ||
116 | -<table class="table table-striped table-hover "> | ||
117 | - <thead> | ||
118 | - <tr> | ||
119 | - {{range $.Content.Fields}} | ||
120 | - <th> | ||
121 | - {{.}} | ||
122 | - </th> | ||
123 | - {{end}} | ||
124 | - </tr> | ||
125 | - </thead> | ||
126 | - | ||
127 | - <tbody> | ||
128 | - {{$slice := index $.Content.Data .}} | ||
129 | - {{range $i, $elem := $slice}} | ||
130 | - | ||
131 | - <tr> | ||
132 | - {{range $elem}} | ||
133 | - <td> | ||
134 | - {{.}} | ||
135 | - </td> | ||
136 | - {{end}} | ||
137 | - </tr> | ||
138 | - | ||
139 | - {{end}} | ||
140 | - </tbody> | ||
141 | - | ||
142 | -</table> | ||
143 | -</div> | ||
144 | -</div> | ||
145 | -{{end}} | ||
146 | - | ||
147 | - | ||
148 | -{{end}}` | ||
149 | - | ||
150 | -var tasksTpl = `{{define "content"}} | ||
151 | - | ||
152 | -<h1>{{.Title}}</h1> | ||
153 | - | ||
154 | -{{if .Message }} | ||
155 | -{{ $messageType := index .Message 0}} | ||
156 | -<p class="message | ||
157 | -{{if eq "error" $messageType}} | ||
158 | -bg-danger | ||
159 | -{{else if eq "success" $messageType}} | ||
160 | -bg-success | ||
161 | -{{else}} | ||
162 | -bg-warning | ||
163 | -{{end}} | ||
164 | -"> | ||
165 | -{{index .Message 1}} | ||
166 | -</p> | ||
167 | -{{end}} | ||
168 | - | ||
169 | - | ||
170 | -<table class="table table-striped table-hover "> | ||
171 | -<thead> | ||
172 | -<tr> | ||
173 | -{{range .Content.Fields}} | ||
174 | -<th> | ||
175 | -{{.}} | ||
176 | -</th> | ||
177 | -{{end}} | ||
178 | -</tr> | ||
179 | -</thead> | ||
180 | - | ||
181 | -<tbody> | ||
182 | -{{range $i, $slice := .Content.Data}} | ||
183 | -<tr> | ||
184 | - {{range $slice}} | ||
185 | - <td> | ||
186 | - {{.}} | ||
187 | - </td> | ||
188 | - {{end}} | ||
189 | - <td> | ||
190 | - <a class="btn btn-primary btn-sm" href="/task?taskname={{index $slice 0}}">Run</a> | ||
191 | - </td> | ||
192 | -</tr> | ||
193 | -{{end}} | ||
194 | -</tbody> | ||
195 | -</table> | ||
196 | - | ||
197 | -{{end}}` | ||
198 | - | ||
199 | -var healthCheckTpl = ` | ||
200 | -{{define "content"}} | ||
201 | - | ||
202 | -<h1>{{.Title}}</h1> | ||
203 | -<table class="table table-striped table-hover "> | ||
204 | -<thead> | ||
205 | -<tr> | ||
206 | -{{range .Content.Fields}} | ||
207 | - <th> | ||
208 | - {{.}} | ||
209 | - </th> | ||
210 | -{{end}} | ||
211 | -</tr> | ||
212 | -</thead> | ||
213 | -<tbody> | ||
214 | -{{range $i, $slice := .Content.Data}} | ||
215 | - {{ $header := index $slice 0}} | ||
216 | - {{ if eq "success" $header}} | ||
217 | - <tr class="success"> | ||
218 | - {{else if eq "error" $header}} | ||
219 | - <tr class="danger"> | ||
220 | - {{else}} | ||
221 | - <tr> | ||
222 | - {{end}} | ||
223 | - {{range $j, $elem := $slice}} | ||
224 | - {{if ne $j 0}} | ||
225 | - <td> | ||
226 | - {{$elem}} | ||
227 | - </td> | ||
228 | - {{end}} | ||
229 | - {{end}} | ||
230 | - <td> | ||
231 | - {{$header}} | ||
232 | - </td> | ||
233 | - </tr> | ||
234 | -{{end}} | ||
235 | - | ||
236 | -</tbody> | ||
237 | -</table> | ||
238 | -{{end}}` | ||
239 | - | ||
240 | -// The base dashboardTpl | ||
241 | -var dashboardTpl = ` | ||
242 | -<!DOCTYPE html> | ||
243 | -<html lang="en"> | ||
244 | -<head> | ||
245 | -<!-- Meta, title, CSS, favicons, etc. --> | ||
246 | -<meta charset="utf-8"> | ||
247 | -<meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||
248 | -<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
249 | - | ||
250 | -<title> | ||
251 | - | ||
252 | -Welcome to Beego Admin Dashboard | ||
253 | - | ||
254 | -</title> | ||
255 | - | ||
256 | -<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet"> | ||
257 | -<link href="//cdn.datatables.net/plug-ins/725b2a2115b/integration/bootstrap/3/dataTables.bootstrap.css" rel="stylesheet"> | ||
258 | - | ||
259 | -<style type="text/css"> | ||
260 | -ul.nav li.dropdown:hover > ul.dropdown-menu { | ||
261 | - display: block; | ||
262 | -} | ||
263 | -#logo { | ||
264 | - width: 102px; | ||
265 | - height: 32px; | ||
266 | - margin-top: 5px; | ||
267 | -} | ||
268 | -.message { | ||
269 | - padding: 15px; | ||
270 | -} | ||
271 | -</style> | ||
272 | - | ||
273 | -</head> | ||
274 | -<body> | ||
275 | - | ||
276 | -<header class="navbar navbar-default navbar-static-top bs-docs-nav" id="top" role="banner"> | ||
277 | -<div class="container"> | ||
278 | -<div class="navbar-header"> | ||
279 | -<button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".bs-navbar-collapse"> | ||
280 | -<span class="sr-only">Toggle navigation</span> | ||
281 | -<span class="icon-bar"></span> | ||
282 | -<span class="icon-bar"></span> | ||
283 | -<span class="icon-bar"></span> | ||
284 | -</button> | ||
285 | - | ||
286 | -<a href="/"> | ||
287 | -<img id="logo" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPYAAABNCAYAAACVH5l+AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAV/QAAFf0BzXBRYQAAABZ0RVh0Q3JlYXRpb24gVGltZQAxMi8xMy8xM+ovEHIAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAQAklEQVR4nO2de7RcVXnAfzM3MckmhLdKtZYqoimtERVtXSjFNvYE6rsnFMFKy2MJC4tGdNECalFsKxRQ5GGDClUjzS6lltcuUmiryxRqFaEaCkgVqAkSakKSneTm3rn949uHOTNzzp1zZs5j7mT/1pqVmzMze39z73xnf/vb36OBx+OZFRuEvwusBp4fu7wROE0ZfUs9UiUzMzMDQLNmOTyeucB1dCo17v/XVS5JRrxiezz9OSDn9drxiu3xjCFesT2eMcQrtsczhnjF9njGEK/YHs8Y4hXb4xlDvGJ7PGOIV2yPZwzxiu3x9OfpnNdrxyu2x9Ofk5HY8Dgb3fWRpFG3AB6Ppzh8EojHM8Z4xfZ4xhCv2B7PGOIV2+MZQ+bVLYDHUzU2CE8AXg+8GHguMAW0gOmEn6PH7q6fdwOTsceurp+fca+1wJPAz4GfKaM3V/EZvVfcs0dhg/AC4D3AgcAixGrNqgczOZ9ruOuTiGLfBVygjH4is8A5ibziXrE9eww2CI8C1gL7INZq9P2PFLBIorGjcacRBf82sFIZvbXg+WQyp9jzbBBuRj7osDwFPALcA9wC3K2MbhUw7rMUKGsWHgMuUUZfMcib55Ksg2CDcCnwR8CbgJcCe2d5G3AzcJYyelOJ4vVOHISLgEuB/YAJqlvUonkmgAXAa4HfR4ojDo0NwiXAIcAPldFT0fUinWcHAb8BfAC4E3jQBuHxBY5fNS8CPmuD8Ji6BclAZbLaIFxgg/AzwH8B5wCvIptSAyjgeOCvShIvkW1vflcDkfXltL/zMxU/QJR8EXCWDcIDh/lMNgjn2SD8MLAB+D6w3gbhC6Lny/SKvxS4wQbhGhuEqsR5yua36xYgB6XK6v6OtwN/zHDfnaOLkSgbzWbz5cDpwHySla5VwCNpzDTlPgSxdgbCBuGrgXuBTyM3S4BDgS/tWLGyAdV4xU8AltggfJsyerqC+YrG1i1ADkqT1QbhBLI/LcIq2FnAGJlwJviFwL7uUlzJQH5n6921pntM9Pk3crg1ux646w3apvd8es3++cApNgi/pox+PMdnUcAngLPd+N0sB04FVld13HUc8FHgYxXNVxSTwI11C5GRsmW9APk7FsHagsbJwnGIhRApQuQom0FuMOcpo68pY2IbhPsD/wwcRvtmECn5wcCHEesny1i/A1yDrPazcfGOFSu/1khx8rSABzJJL+znBJ0/y2t2A0uV0T/KMW4HBcmahUngIeAKZfQ9gwwwl2Tthw3Co5GjmjTz+xngx/T3LD8J/CNwTRXWm9vH3gr8Cr2KPQ3co4wue/tyKvAXtE3m+I1lM3CsMvr7s7z/AOBy4KQc0y5LW7G3KqNfmWOgyExYDnwcSHrvfMSBcUaecTOQW9YamUuyAs8qxxrSlXo14uWerE6qzKyivVpGRHvfzYhJWzZrgROB19DpuANYDPypDcL3KqN7tic2COcDdwO/lmO+B4D1hTnPlNFWGf115AOkmVrvtkG4oKg5PeWydfk7G8D1wC+kvOTfgDNGUaltEL4GCUSZR69DaxdwgzL6B2XLoYx+BnFybaftaIP2nv4NwG+lvH0p+ZR6DXDMotvX7i7cK+5MrFPoTUwHWAIcVfScnnKYmJhYBRyb8vTTwAmj6BC1QbgYcZhFx3BxpZ4GfgJcVqFIdyJe7Gl6veQK+IA7j+7mUcSy6MdPgBXK6BMX3b72aSjpuEsZvY30hmWvL2NOT7HYIDwS+PNZXnKyMvqnVcmTk5XAEXRGlEXKZBF/RGWyK6N3A+cjvojuVbuBrMpvSXjfNuCDswzdQm5QhyujTfyJMs+x70i5fniJc3oKwAbhPsANpDtDLx+19rERLkjjTGAhvWGdU8B/Al+tWi5l9P3A3zsZIpkiL/lC4P1Jq7Yy+jrgtoQh7wNep4xepYze3v1kmYqdtn/5pRLn9BTD55HMpyS+B5xboSx5ORuJxGvSuVq3ELN2VY0+gUuRLWp38EoDCTA5JeV9pyHh2iAWx7nAkcro76RNVJpiK6N/hhxxdXNQWXN6hscG4WlI2GcS24HjldG7KhQpMzYIXwmEtCPMoK08u4AvKKMfqkk8lNGPIdbCLto3G2g70k63Qdiz8Lltw1JgGXCwMvov43HhSZRdaCEpEsrngI8oNggPBT4zy0vOUEY/XJU8ebBBuBA5L47HrUf72WngYQpKvBiSaxFnV7cjrYGkkp7lovw6UEZPKaPvd172vtRRQeU5Nczp6YNLlPhrJEkhia8oo79coUh5eTfwCnq/05HD7GpnRdaKk+FqJLAortQgQTTvQFbnoShNsW0QNklOW6wsTtiTnWazeRLpceCPUHxgUWHYIDwYOIvORSPax04B6xDH1aiwBniQ3r02yJHwh1xwysCUuWKneb+fKnFOzwC41fqClKcnkX31tgpFysu5SEhzPFwzOrP+OXCRMnpHfeJ14nwUH0csiUi5ob3XPgZJhx2YMhU7LWHgkZTrnppoNptvQNJsk/gzZfR3q5QnDy7C7DjEjI0UJFKW3cAXZ4vFrgtl9L8C36RdYy1elGQRcN4w45ei2DYI9yU9a+XeMub0DEWQcv1x4JIqBcmDDcJ5wEVIzHX8zDoywR8ErqpHukx8EthCr0neBF5tgzDt79KXwhXbBTesRUyjJG4tek7P0CxLuX79KMaBxzgZ2fLFTfBo9dsGXFpWbbEiUEavR8qITdF7/DUBfMLlk+emMMW2QXiYDcKzkeyS5Skvu0sZ7U3x0eOQlOv/VKUQebBB+DzEKoyKEsbDR6eRNNNv1CNdLi5D4u67U16byOL4vkEGTTtT3sflE2dlr1nGivMnOcbMShZZp5B84S8ro2c7py2bUZV1r5TrP6xo/kE4Ddif5Hjwp4BPj2ogTRxl9BM2CK9DYsKjwJroM80D3mOD8AZl9IY8486mjEVX2LxIGV3W/jqLrAcg+5bNyujrS5IjC6Moa1Ixwkll9P9VMPegHE1bAeLKPQWsbrVaAxf0qIGrkGi/F9Kbs30gUl7s0jwDVhWgsobRKYv0jroFyEFVsibVzxqZ46EUor1nd8HA7a1W68rFd9zYr5rLyOCO4i6kvdeOWyAN4DfzjlmVYttWq1VojXHPHk8UudXNvGaz+dqqhSmAbyA30+7Chw3St0qpVKXYpzabzTL214NwU90C5GAuyVo162gfE8X/XQCc547C5hLLkfTNpPLIuX0Fs334LTnG2Zv+N4kLbRDeWlKwQD9Z4w6pOvfXMLdk7YsNwrcAHwFeRvY8gC3K6GHTd/8GeBtSVrg773op8FZGK4w0FZeHfS6iQy16Pfyp6ZlppCn2FmX0vinPpQl3CFKw/iMkRzFNAJ+iuBK2EbllrZG5JGtfbBC+CvgH6kkmegT4OlK9M4o6ixR8AZICeWfWbKiaORN4Acke/i0MUBiiyGKGP1ZGXwv8KtKfKYkVNgh/sag5PbVzLDX1WHe11r6InAEnpUC+GHhXHbLlweVfn0D75hTfWuxGbpy5Yz/KKGY4iTQdS+pw0KD4Fduzh9JqtR4F/o7OPTbu5wXAScP2yKqA85GMLuhcracRHbpskIKRZRUztEhCeRKvK2NOTy3cRmfyQqW4I60vAP9Lsof8RUhFlZHEtfU9is72QHGH2SeV0XkCxZ6lTDPq9pTrh5Y4p6dCXNbX24FvIdFeWxIeZcvwJLIHjRcuiJR8HnD8KK7arsHGxxBPeES8RPK/K6MHDokt80jgwZTrI/dL9gyOMvpm0n0qVfUJ10gwz6H0Nsd7IfCHwMUly5AZV4Tk/UiMfpLDbCuzl37uS5nFDLcixe+6GShbxeNJQxm9CVm1d9J7BtxEVu1Rqo77y8DvkZxDPgXcpIxOWxgzUbZHM6mSom/x4ymDmxDvcdyBBrIi7guckVQksGpc4MwHkUaW3VFmLeCnwGeHnadsxV6YcG3kM248cw93Xr0aWbW7yw01gDcDL6lHug7e6B5xEzzKIZ8Eriwi+abMYoYHkbw6D+Tl83gyYJAm9klFAhcjgSC1YYNwb2S1jm9H42fX31NGF9I7vMwV+00p1x8tcU7PYFRtRZWSeeV6ZH0KSaboPtduAEfbIDysjLkzciLi4Euq+LIFKZVUCKUotmu/mtZM7D/KmNMzFElOziU2CIuoAZ9URre0YzB3BPct0jtbripr7tlwIdd/QHrRxduU0YUVtihcsbcuf2djYmLiYtIDUUaymdseTtKeroEUMxgYG4TLEGXq5slhxs3A5ciRUbQaxpX7FTYIjyh5/g5cjfDIYQadN5xppJ/XlUXOWWTNs4U2CIOJiYm7gA+lvOxeZfQDRc3pKYy0aiNXOOXMjQ3Cw5EMrCTuG2TMrLj+XN+k1+RvIOGbv17m/Am8keQIMxCH2bUu0KYw0gJU9rZBmOeXvxjpotkv4KWMKip5Zc3CJPAQ0kf5ngLHHVVZ70B6SnfzMuA+G4QbgKztcZpIEFJalVqYJaClQK5CCu93x01MIJ+rElzV3vfRtlzi3voW0lPsxqLnTVPEJuklaQfl+u7m3AVRhqwARwKhDcJlwwYLxBhVWf8WcTo9N+X5g5ldUfPwMMn9novmUeAJekOYZyjus2Th7Ugac7w+W7Q92IbUAizceVlVyt3d1HzUMCDPYQ6k/jkGltW176ni7zMDnKmMLj1xxGVEbSL56CspvqJwXE+x99LZ1jceYWbK6rJSRfmYrwCnj1LvpJwkOX9GlYFlVUbfaIPwTMrrnNFClPrOksZPIjr26o7w6vneu7iLw5Fwz+cjyr8L6a+13Y21M/bvM4iDbguy8u6I96x2EWbnIFZQd+XRGUpwmMUpU7HvB853SQJzmSq/iMMylKzK6KttED6OpEKmmeWD8CPk5n5XgWNmIR47HhHV6wbABuEBiH/hWOB5iEJHCSTx9yTRMa4NwvhcDcSK6h5nBvGLfFUZvTHn58lMkYq9EcnoWgfcrIxeV+DYdfAYcIky+u66BclAYbIqo2+xQfgSxIRcARyBKHme78pOYAPwbaSlk46vZhUSrdjdit10ZvJKZA+8P+JU617ZI9KuZ6F77hYS0164wyzOMAJ7PCONDcKPIllUcV/SDHLjsUhySJNOPYgfRQ1L92rdcvOeX9aWZGZGRJ9rJVo9njx0r9iRib0QyWOIVzft7tZZBN2r9W7gX6rwM3jF9owzu+hVLkhW3CRPfZqC57V0W4hS/w9QST82r9ieccaSrIRpjrG4uRx15ZhAzPXoEa360f+hM6Ksm0kko3E98Lm8zfUGxSu2Z5x5Glkp59OrdElm8n8jOd3fUUYnJcYk4o62FrrHXu6hEP2yyNHYJhcvUAlesT3jzEbkDHoJnUdYcZN8J3IcN3BIrvP4b3OPTcMIXBResT3jzONIqaGFtE3qiB3AD5AAqnUul3ts8IrtGWc2IDHw5yAtdOYjoZzfRRoN3FdGnPYo4M+xPWONK2C4H+1FbArYXFPATOlE59j/D6WId7YitGZUAAAAAElFTkSuQmCC"/> | ||
288 | -</a> | ||
289 | - | ||
290 | -</div> | ||
291 | -<nav class="collapse navbar-collapse bs-navbar-collapse" role="navigation"> | ||
292 | -<ul class="nav navbar-nav"> | ||
293 | -<li> | ||
294 | -<a href="/qps"> | ||
295 | -Requests statistics | ||
296 | -</a> | ||
297 | -</li> | ||
298 | -<li> | ||
299 | - | ||
300 | -<li class="dropdown"> | ||
301 | -<a href="#" class="dropdown-toggle disabled" data-toggle="dropdown">Performance profiling<span class="caret"></span></a> | ||
302 | -<ul class="dropdown-menu" role="menu"> | ||
303 | - | ||
304 | -<li><a href="/prof?command=lookup goroutine">lookup goroutine</a></li> | ||
305 | -<li><a href="/prof?command=lookup heap">lookup heap</a></li> | ||
306 | -<li><a href="/prof?command=lookup threadcreate">lookup threadcreate</a></li> | ||
307 | -<li><a href="/prof?command=lookup block">lookup block</a></li> | ||
308 | -<li><a href="/prof?command=get cpuprof">get cpuprof</a></li> | ||
309 | -<li><a href="/prof?command=get memprof">get memprof</a></li> | ||
310 | -<li><a href="/prof?command=gc summary">gc summary</a></li> | ||
311 | - | ||
312 | -</ul> | ||
313 | -</li> | ||
314 | - | ||
315 | -<li> | ||
316 | -<a href="/healthcheck"> | ||
317 | -Healthcheck | ||
318 | -</a> | ||
319 | -</li> | ||
320 | - | ||
321 | -<li> | ||
322 | -<a href="/task" class="dropdown-toggle disabled" data-toggle="dropdown">Tasks</a> | ||
323 | -</li> | ||
324 | - | ||
325 | -<li class="dropdown"> | ||
326 | -<a href="#" class="dropdown-toggle disabled" data-toggle="dropdown">Config Status<span class="caret"></span></a> | ||
327 | -<ul class="dropdown-menu" role="menu"> | ||
328 | -<li><a href="/listconf?command=conf">Configs</a></li> | ||
329 | -<li><a href="/listconf?command=router">Routers</a></li> | ||
330 | -<li><a href="/listconf?command=filter">Filters</a></li> | ||
331 | -</ul> | ||
332 | -</li> | ||
333 | -</ul> | ||
334 | -</nav> | ||
335 | -</div> | ||
336 | -</header> | ||
337 | - | ||
338 | -<div class="container"> | ||
339 | -{{template "content" .}} | ||
340 | -</div> | ||
341 | - | ||
342 | -<script src="//code.jquery.com/jquery-1.11.1.min.js"></script> | ||
343 | -<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script> | ||
344 | -<script src="//cdn.datatables.net/1.10.2/js/jquery.dataTables.min.js"></script> | ||
345 | -<script src="//cdn.datatables.net/plug-ins/725b2a2115b/integration/bootstrap/3/dataTables.bootstrap.js | ||
346 | -"></script> | ||
347 | - | ||
348 | -<script type="text/javascript"> | ||
349 | -$(document).ready(function() { | ||
350 | - $('.table').dataTable(); | ||
351 | -}); | ||
352 | -</script> | ||
353 | -{{template "scripts" .}} | ||
354 | -</body> | ||
355 | -</html> | ||
356 | -` |
vendor/github.com/astaxie/beego/app.go
已删除
100644 → 0
1 | -// Copyright 2014 beego Author. All Rights Reserved. | ||
2 | -// | ||
3 | -// Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | -// you may not use this file except in compliance with the License. | ||
5 | -// You may obtain a copy of the License at | ||
6 | -// | ||
7 | -// http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | -// | ||
9 | -// Unless required by applicable law or agreed to in writing, software | ||
10 | -// distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | -// See the License for the specific language governing permissions and | ||
13 | -// limitations under the License. | ||
14 | - | ||
15 | -package beego | ||
16 | - | ||
17 | -import ( | ||
18 | - "crypto/tls" | ||
19 | - "crypto/x509" | ||
20 | - "fmt" | ||
21 | - "io/ioutil" | ||
22 | - "net" | ||
23 | - "net/http" | ||
24 | - "net/http/fcgi" | ||
25 | - "os" | ||
26 | - "path" | ||
27 | - "strings" | ||
28 | - "time" | ||
29 | - | ||
30 | - "github.com/astaxie/beego/grace" | ||
31 | - "github.com/astaxie/beego/logs" | ||
32 | - "github.com/astaxie/beego/utils" | ||
33 | - "golang.org/x/crypto/acme/autocert" | ||
34 | -) | ||
35 | - | ||
36 | -var ( | ||
37 | - // BeeApp is an application instance | ||
38 | - BeeApp *App | ||
39 | -) | ||
40 | - | ||
41 | -func init() { | ||
42 | - // create beego application | ||
43 | - BeeApp = NewApp() | ||
44 | -} | ||
45 | - | ||
46 | -// App defines beego application with a new PatternServeMux. | ||
47 | -type App struct { | ||
48 | - Handlers *ControllerRegister | ||
49 | - Server *http.Server | ||
50 | -} | ||
51 | - | ||
52 | -// NewApp returns a new beego application. | ||
53 | -func NewApp() *App { | ||
54 | - cr := NewControllerRegister() | ||
55 | - app := &App{Handlers: cr, Server: &http.Server{}} | ||
56 | - return app | ||
57 | -} | ||
58 | - | ||
59 | -// MiddleWare function for http.Handler | ||
60 | -type MiddleWare func(http.Handler) http.Handler | ||
61 | - | ||
62 | -// Run beego application. | ||
63 | -func (app *App) Run(mws ...MiddleWare) { | ||
64 | - addr := BConfig.Listen.HTTPAddr | ||
65 | - | ||
66 | - if BConfig.Listen.HTTPPort != 0 { | ||
67 | - addr = fmt.Sprintf("%s:%d", BConfig.Listen.HTTPAddr, BConfig.Listen.HTTPPort) | ||
68 | - } | ||
69 | - | ||
70 | - var ( | ||
71 | - err error | ||
72 | - l net.Listener | ||
73 | - endRunning = make(chan bool, 1) | ||
74 | - ) | ||
75 | - | ||
76 | - // run cgi server | ||
77 | - if BConfig.Listen.EnableFcgi { | ||
78 | - if BConfig.Listen.EnableStdIo { | ||
79 | - if err = fcgi.Serve(nil, app.Handlers); err == nil { // standard I/O | ||
80 | - logs.Info("Use FCGI via standard I/O") | ||
81 | - } else { | ||
82 | - logs.Critical("Cannot use FCGI via standard I/O", err) | ||
83 | - } | ||
84 | - return | ||
85 | - } | ||
86 | - if BConfig.Listen.HTTPPort == 0 { | ||
87 | - // remove the Socket file before start | ||
88 | - if utils.FileExists(addr) { | ||
89 | - os.Remove(addr) | ||
90 | - } | ||
91 | - l, err = net.Listen("unix", addr) | ||
92 | - } else { | ||
93 | - l, err = net.Listen("tcp", addr) | ||
94 | - } | ||
95 | - if err != nil { | ||
96 | - logs.Critical("Listen: ", err) | ||
97 | - } | ||
98 | - if err = fcgi.Serve(l, app.Handlers); err != nil { | ||
99 | - logs.Critical("fcgi.Serve: ", err) | ||
100 | - } | ||
101 | - return | ||
102 | - } | ||
103 | - | ||
104 | - app.Server.Handler = app.Handlers | ||
105 | - for i := len(mws) - 1; i >= 0; i-- { | ||
106 | - if mws[i] == nil { | ||
107 | - continue | ||
108 | - } | ||
109 | - app.Server.Handler = mws[i](app.Server.Handler) | ||
110 | - } | ||
111 | - app.Server.ReadTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second | ||
112 | - app.Server.WriteTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second | ||
113 | - app.Server.ErrorLog = logs.GetLogger("HTTP") | ||
114 | - | ||
115 | - // run graceful mode | ||
116 | - if BConfig.Listen.Graceful { | ||
117 | - httpsAddr := BConfig.Listen.HTTPSAddr | ||
118 | - app.Server.Addr = httpsAddr | ||
119 | - if BConfig.Listen.EnableHTTPS || BConfig.Listen.EnableMutualHTTPS { | ||
120 | - go func() { | ||
121 | - time.Sleep(1000 * time.Microsecond) | ||
122 | - if BConfig.Listen.HTTPSPort != 0 { | ||
123 | - httpsAddr = fmt.Sprintf("%s:%d", BConfig.Listen.HTTPSAddr, BConfig.Listen.HTTPSPort) | ||
124 | - app.Server.Addr = httpsAddr | ||
125 | - } | ||
126 | - server := grace.NewServer(httpsAddr, app.Handlers) | ||
127 | - server.Server.ReadTimeout = app.Server.ReadTimeout | ||
128 | - server.Server.WriteTimeout = app.Server.WriteTimeout | ||
129 | - if BConfig.Listen.EnableMutualHTTPS { | ||
130 | - if err := server.ListenAndServeMutualTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile, BConfig.Listen.TrustCaFile); err != nil { | ||
131 | - logs.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid())) | ||
132 | - time.Sleep(100 * time.Microsecond) | ||
133 | - endRunning <- true | ||
134 | - } | ||
135 | - } else { | ||
136 | - if BConfig.Listen.AutoTLS { | ||
137 | - m := autocert.Manager{ | ||
138 | - Prompt: autocert.AcceptTOS, | ||
139 | - HostPolicy: autocert.HostWhitelist(BConfig.Listen.Domains...), | ||
140 | - Cache: autocert.DirCache(BConfig.Listen.TLSCacheDir), | ||
141 | - } | ||
142 | - app.Server.TLSConfig = &tls.Config{GetCertificate: m.GetCertificate} | ||
143 | - BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile = "", "" | ||
144 | - } | ||
145 | - if err := server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil { | ||
146 | - logs.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid())) | ||
147 | - time.Sleep(100 * time.Microsecond) | ||
148 | - endRunning <- true | ||
149 | - } | ||
150 | - } | ||
151 | - }() | ||
152 | - } | ||
153 | - if BConfig.Listen.EnableHTTP { | ||
154 | - go func() { | ||
155 | - server := grace.NewServer(addr, app.Handlers) | ||
156 | - server.Server.ReadTimeout = app.Server.ReadTimeout | ||
157 | - server.Server.WriteTimeout = app.Server.WriteTimeout | ||
158 | - if BConfig.Listen.ListenTCP4 { | ||
159 | - server.Network = "tcp4" | ||
160 | - } | ||
161 | - if err := server.ListenAndServe(); err != nil { | ||
162 | - logs.Critical("ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid())) | ||
163 | - time.Sleep(100 * time.Microsecond) | ||
164 | - endRunning <- true | ||
165 | - } | ||
166 | - }() | ||
167 | - } | ||
168 | - <-endRunning | ||
169 | - return | ||
170 | - } | ||
171 | - | ||
172 | - // run normal mode | ||
173 | - if BConfig.Listen.EnableHTTPS || BConfig.Listen.EnableMutualHTTPS { | ||
174 | - go func() { | ||
175 | - time.Sleep(1000 * time.Microsecond) | ||
176 | - if BConfig.Listen.HTTPSPort != 0 { | ||
177 | - app.Server.Addr = fmt.Sprintf("%s:%d", BConfig.Listen.HTTPSAddr, BConfig.Listen.HTTPSPort) | ||
178 | - } else if BConfig.Listen.EnableHTTP { | ||
179 | - BeeLogger.Info("Start https server error, conflict with http. Please reset https port") | ||
180 | - return | ||
181 | - } | ||
182 | - logs.Info("https server Running on https://%s", app.Server.Addr) | ||
183 | - if BConfig.Listen.AutoTLS { | ||
184 | - m := autocert.Manager{ | ||
185 | - Prompt: autocert.AcceptTOS, | ||
186 | - HostPolicy: autocert.HostWhitelist(BConfig.Listen.Domains...), | ||
187 | - Cache: autocert.DirCache(BConfig.Listen.TLSCacheDir), | ||
188 | - } | ||
189 | - app.Server.TLSConfig = &tls.Config{GetCertificate: m.GetCertificate} | ||
190 | - BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile = "", "" | ||
191 | - } else if BConfig.Listen.EnableMutualHTTPS { | ||
192 | - pool := x509.NewCertPool() | ||
193 | - data, err := ioutil.ReadFile(BConfig.Listen.TrustCaFile) | ||
194 | - if err != nil { | ||
195 | - BeeLogger.Info("MutualHTTPS should provide TrustCaFile") | ||
196 | - return | ||
197 | - } | ||
198 | - pool.AppendCertsFromPEM(data) | ||
199 | - app.Server.TLSConfig = &tls.Config{ | ||
200 | - ClientCAs: pool, | ||
201 | - ClientAuth: tls.RequireAndVerifyClientCert, | ||
202 | - } | ||
203 | - } | ||
204 | - if err := app.Server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil { | ||
205 | - logs.Critical("ListenAndServeTLS: ", err) | ||
206 | - time.Sleep(100 * time.Microsecond) | ||
207 | - endRunning <- true | ||
208 | - } | ||
209 | - }() | ||
210 | - | ||
211 | - } | ||
212 | - if BConfig.Listen.EnableHTTP { | ||
213 | - go func() { | ||
214 | - app.Server.Addr = addr | ||
215 | - logs.Info("http server Running on http://%s", app.Server.Addr) | ||
216 | - if BConfig.Listen.ListenTCP4 { | ||
217 | - ln, err := net.Listen("tcp4", app.Server.Addr) | ||
218 | - if err != nil { | ||
219 | - logs.Critical("ListenAndServe: ", err) | ||
220 | - time.Sleep(100 * time.Microsecond) | ||
221 | - endRunning <- true | ||
222 | - return | ||
223 | - } | ||
224 | - if err = app.Server.Serve(ln); err != nil { | ||
225 | - logs.Critical("ListenAndServe: ", err) | ||
226 | - time.Sleep(100 * time.Microsecond) | ||
227 | - endRunning <- true | ||
228 | - return | ||
229 | - } | ||
230 | - } else { | ||
231 | - if err := app.Server.ListenAndServe(); err != nil { | ||
232 | - logs.Critical("ListenAndServe: ", err) | ||
233 | - time.Sleep(100 * time.Microsecond) | ||
234 | - endRunning <- true | ||
235 | - } | ||
236 | - } | ||
237 | - }() | ||
238 | - } | ||
239 | - <-endRunning | ||
240 | -} | ||
241 | - | ||
242 | -// Router adds a patterned controller handler to BeeApp. | ||
243 | -// it's an alias method of App.Router. | ||
244 | -// usage: | ||
245 | -// simple router | ||
246 | -// beego.Router("/admin", &admin.UserController{}) | ||
247 | -// beego.Router("/admin/index", &admin.ArticleController{}) | ||
248 | -// | ||
249 | -// regex router | ||
250 | -// | ||
251 | -// beego.Router("/api/:id([0-9]+)", &controllers.RController{}) | ||
252 | -// | ||
253 | -// custom rules | ||
254 | -// beego.Router("/api/list",&RestController{},"*:ListFood") | ||
255 | -// beego.Router("/api/create",&RestController{},"post:CreateFood") | ||
256 | -// beego.Router("/api/update",&RestController{},"put:UpdateFood") | ||
257 | -// beego.Router("/api/delete",&RestController{},"delete:DeleteFood") | ||
258 | -func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *App { | ||
259 | - BeeApp.Handlers.Add(rootpath, c, mappingMethods...) | ||
260 | - return BeeApp | ||
261 | -} | ||
262 | - | ||
263 | -// UnregisterFixedRoute unregisters the route with the specified fixedRoute. It is particularly useful | ||
264 | -// in web applications that inherit most routes from a base webapp via the underscore | ||
265 | -// import, and aim to overwrite only certain paths. | ||
266 | -// The method parameter can be empty or "*" for all HTTP methods, or a particular | ||
267 | -// method type (e.g. "GET" or "POST") for selective removal. | ||
268 | -// | ||
269 | -// Usage (replace "GET" with "*" for all methods): | ||
270 | -// beego.UnregisterFixedRoute("/yourpreviouspath", "GET") | ||
271 | -// beego.Router("/yourpreviouspath", yourControllerAddress, "get:GetNewPage") | ||
272 | -func UnregisterFixedRoute(fixedRoute string, method string) *App { | ||
273 | - subPaths := splitPath(fixedRoute) | ||
274 | - if method == "" || method == "*" { | ||
275 | - for m := range HTTPMETHOD { | ||
276 | - if _, ok := BeeApp.Handlers.routers[m]; !ok { | ||
277 | - continue | ||
278 | - } | ||
279 | - if BeeApp.Handlers.routers[m].prefix == strings.Trim(fixedRoute, "/ ") { | ||
280 | - findAndRemoveSingleTree(BeeApp.Handlers.routers[m]) | ||
281 | - continue | ||
282 | - } | ||
283 | - findAndRemoveTree(subPaths, BeeApp.Handlers.routers[m], m) | ||
284 | - } | ||
285 | - return BeeApp | ||
286 | - } | ||
287 | - // Single HTTP method | ||
288 | - um := strings.ToUpper(method) | ||
289 | - if _, ok := BeeApp.Handlers.routers[um]; ok { | ||
290 | - if BeeApp.Handlers.routers[um].prefix == strings.Trim(fixedRoute, "/ ") { | ||
291 | - findAndRemoveSingleTree(BeeApp.Handlers.routers[um]) | ||
292 | - return BeeApp | ||
293 | - } | ||
294 | - findAndRemoveTree(subPaths, BeeApp.Handlers.routers[um], um) | ||
295 | - } | ||
296 | - return BeeApp | ||
297 | -} | ||
298 | - | ||
299 | -func findAndRemoveTree(paths []string, entryPointTree *Tree, method string) { | ||
300 | - for i := range entryPointTree.fixrouters { | ||
301 | - if entryPointTree.fixrouters[i].prefix == paths[0] { | ||
302 | - if len(paths) == 1 { | ||
303 | - if len(entryPointTree.fixrouters[i].fixrouters) > 0 { | ||
304 | - // If the route had children subtrees, remove just the functional leaf, | ||
305 | - // to allow children to function as before | ||
306 | - if len(entryPointTree.fixrouters[i].leaves) > 0 { | ||
307 | - entryPointTree.fixrouters[i].leaves[0] = nil | ||
308 | - entryPointTree.fixrouters[i].leaves = entryPointTree.fixrouters[i].leaves[1:] | ||
309 | - } | ||
310 | - } else { | ||
311 | - // Remove the *Tree from the fixrouters slice | ||
312 | - entryPointTree.fixrouters[i] = nil | ||
313 | - | ||
314 | - if i == len(entryPointTree.fixrouters)-1 { | ||
315 | - entryPointTree.fixrouters = entryPointTree.fixrouters[:i] | ||
316 | - } else { | ||
317 | - entryPointTree.fixrouters = append(entryPointTree.fixrouters[:i], entryPointTree.fixrouters[i+1:len(entryPointTree.fixrouters)]...) | ||
318 | - } | ||
319 | - } | ||
320 | - return | ||
321 | - } | ||
322 | - findAndRemoveTree(paths[1:], entryPointTree.fixrouters[i], method) | ||
323 | - } | ||
324 | - } | ||
325 | -} | ||
326 | - | ||
327 | -func findAndRemoveSingleTree(entryPointTree *Tree) { | ||
328 | - if entryPointTree == nil { | ||
329 | - return | ||
330 | - } | ||
331 | - if len(entryPointTree.fixrouters) > 0 { | ||
332 | - // If the route had children subtrees, remove just the functional leaf, | ||
333 | - // to allow children to function as before | ||
334 | - if len(entryPointTree.leaves) > 0 { | ||
335 | - entryPointTree.leaves[0] = nil | ||
336 | - entryPointTree.leaves = entryPointTree.leaves[1:] | ||
337 | - } | ||
338 | - } | ||
339 | -} | ||
340 | - | ||
341 | -// Include will generate router file in the router/xxx.go from the controller's comments | ||
342 | -// usage: | ||
343 | -// beego.Include(&BankAccount{}, &OrderController{},&RefundController{},&ReceiptController{}) | ||
344 | -// type BankAccount struct{ | ||
345 | -// beego.Controller | ||
346 | -// } | ||
347 | -// | ||
348 | -// register the function | ||
349 | -// func (b *BankAccount)Mapping(){ | ||
350 | -// b.Mapping("ShowAccount" , b.ShowAccount) | ||
351 | -// b.Mapping("ModifyAccount", b.ModifyAccount) | ||
352 | -//} | ||
353 | -// | ||
354 | -// //@router /account/:id [get] | ||
355 | -// func (b *BankAccount) ShowAccount(){ | ||
356 | -// //logic | ||
357 | -// } | ||
358 | -// | ||
359 | -// | ||
360 | -// //@router /account/:id [post] | ||
361 | -// func (b *BankAccount) ModifyAccount(){ | ||
362 | -// //logic | ||
363 | -// } | ||
364 | -// | ||
365 | -// the comments @router url methodlist | ||
366 | -// url support all the function Router's pattern | ||
367 | -// methodlist [get post head put delete options *] | ||
368 | -func Include(cList ...ControllerInterface) *App { | ||
369 | - BeeApp.Handlers.Include(cList...) | ||
370 | - return BeeApp | ||
371 | -} | ||
372 | - | ||
373 | -// RESTRouter adds a restful controller handler to BeeApp. | ||
374 | -// its' controller implements beego.ControllerInterface and | ||
375 | -// defines a param "pattern/:objectId" to visit each resource. | ||
376 | -func RESTRouter(rootpath string, c ControllerInterface) *App { | ||
377 | - Router(rootpath, c) | ||
378 | - Router(path.Join(rootpath, ":objectId"), c) | ||
379 | - return BeeApp | ||
380 | -} | ||
381 | - | ||
382 | -// AutoRouter adds defined controller handler to BeeApp. | ||
383 | -// it's same to App.AutoRouter. | ||
384 | -// if beego.AddAuto(&MainContorlller{}) and MainController has methods List and Page, | ||
385 | -// visit the url /main/list to exec List function or /main/page to exec Page function. | ||
386 | -func AutoRouter(c ControllerInterface) *App { | ||
387 | - BeeApp.Handlers.AddAuto(c) | ||
388 | - return BeeApp | ||
389 | -} | ||
390 | - | ||
391 | -// AutoPrefix adds controller handler to BeeApp with prefix. | ||
392 | -// it's same to App.AutoRouterWithPrefix. | ||
393 | -// if beego.AutoPrefix("/admin",&MainContorlller{}) and MainController has methods List and Page, | ||
394 | -// visit the url /admin/main/list to exec List function or /admin/main/page to exec Page function. | ||
395 | -func AutoPrefix(prefix string, c ControllerInterface) *App { | ||
396 | - BeeApp.Handlers.AddAutoPrefix(prefix, c) | ||
397 | - return BeeApp | ||
398 | -} | ||
399 | - | ||
400 | -// Get used to register router for Get method | ||
401 | -// usage: | ||
402 | -// beego.Get("/", func(ctx *context.Context){ | ||
403 | -// ctx.Output.Body("hello world") | ||
404 | -// }) | ||
405 | -func Get(rootpath string, f FilterFunc) *App { | ||
406 | - BeeApp.Handlers.Get(rootpath, f) | ||
407 | - return BeeApp | ||
408 | -} | ||
409 | - | ||
410 | -// Post used to register router for Post method | ||
411 | -// usage: | ||
412 | -// beego.Post("/api", func(ctx *context.Context){ | ||
413 | -// ctx.Output.Body("hello world") | ||
414 | -// }) | ||
415 | -func Post(rootpath string, f FilterFunc) *App { | ||
416 | - BeeApp.Handlers.Post(rootpath, f) | ||
417 | - return BeeApp | ||
418 | -} | ||
419 | - | ||
420 | -// Delete used to register router for Delete method | ||
421 | -// usage: | ||
422 | -// beego.Delete("/api", func(ctx *context.Context){ | ||
423 | -// ctx.Output.Body("hello world") | ||
424 | -// }) | ||
425 | -func Delete(rootpath string, f FilterFunc) *App { | ||
426 | - BeeApp.Handlers.Delete(rootpath, f) | ||
427 | - return BeeApp | ||
428 | -} | ||
429 | - | ||
430 | -// Put used to register router for Put method | ||
431 | -// usage: | ||
432 | -// beego.Put("/api", func(ctx *context.Context){ | ||
433 | -// ctx.Output.Body("hello world") | ||
434 | -// }) | ||
435 | -func Put(rootpath string, f FilterFunc) *App { | ||
436 | - BeeApp.Handlers.Put(rootpath, f) | ||
437 | - return BeeApp | ||
438 | -} | ||
439 | - | ||
440 | -// Head used to register router for Head method | ||
441 | -// usage: | ||
442 | -// beego.Head("/api", func(ctx *context.Context){ | ||
443 | -// ctx.Output.Body("hello world") | ||
444 | -// }) | ||
445 | -func Head(rootpath string, f FilterFunc) *App { | ||
446 | - BeeApp.Handlers.Head(rootpath, f) | ||
447 | - return BeeApp | ||
448 | -} | ||
449 | - | ||
450 | -// Options used to register router for Options method | ||
451 | -// usage: | ||
452 | -// beego.Options("/api", func(ctx *context.Context){ | ||
453 | -// ctx.Output.Body("hello world") | ||
454 | -// }) | ||
455 | -func Options(rootpath string, f FilterFunc) *App { | ||
456 | - BeeApp.Handlers.Options(rootpath, f) | ||
457 | - return BeeApp | ||
458 | -} | ||
459 | - | ||
460 | -// Patch used to register router for Patch method | ||
461 | -// usage: | ||
462 | -// beego.Patch("/api", func(ctx *context.Context){ | ||
463 | -// ctx.Output.Body("hello world") | ||
464 | -// }) | ||
465 | -func Patch(rootpath string, f FilterFunc) *App { | ||
466 | - BeeApp.Handlers.Patch(rootpath, f) | ||
467 | - return BeeApp | ||
468 | -} | ||
469 | - | ||
470 | -// Any used to register router for all methods | ||
471 | -// usage: | ||
472 | -// beego.Any("/api", func(ctx *context.Context){ | ||
473 | -// ctx.Output.Body("hello world") | ||
474 | -// }) | ||
475 | -func Any(rootpath string, f FilterFunc) *App { | ||
476 | - BeeApp.Handlers.Any(rootpath, f) | ||
477 | - return BeeApp | ||
478 | -} | ||
479 | - | ||
480 | -// Handler used to register a Handler router | ||
481 | -// usage: | ||
482 | -// beego.Handler("/api", http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) { | ||
483 | -// fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) | ||
484 | -// })) | ||
485 | -func Handler(rootpath string, h http.Handler, options ...interface{}) *App { | ||
486 | - BeeApp.Handlers.Handler(rootpath, h, options...) | ||
487 | - return BeeApp | ||
488 | -} | ||
489 | - | ||
490 | -// InsertFilter adds a FilterFunc with pattern condition and action constant. | ||
491 | -// The pos means action constant including | ||
492 | -// beego.BeforeStatic, beego.BeforeRouter, beego.BeforeExec, beego.AfterExec and beego.FinishRouter. | ||
493 | -// The bool params is for setting the returnOnOutput value (false allows multiple filters to execute) | ||
494 | -func InsertFilter(pattern string, pos int, filter FilterFunc, params ...bool) *App { | ||
495 | - BeeApp.Handlers.InsertFilter(pattern, pos, filter, params...) | ||
496 | - return BeeApp | ||
497 | -} |
vendor/github.com/astaxie/beego/beego.go
已删除
100644 → 0
1 | -// Copyright 2014 beego Author. All Rights Reserved. | ||
2 | -// | ||
3 | -// Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | -// you may not use this file except in compliance with the License. | ||
5 | -// You may obtain a copy of the License at | ||
6 | -// | ||
7 | -// http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | -// | ||
9 | -// Unless required by applicable law or agreed to in writing, software | ||
10 | -// distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | -// See the License for the specific language governing permissions and | ||
13 | -// limitations under the License. | ||
14 | - | ||
15 | -package beego | ||
16 | - | ||
17 | -import ( | ||
18 | - "os" | ||
19 | - "path/filepath" | ||
20 | - "strconv" | ||
21 | - "strings" | ||
22 | -) | ||
23 | - | ||
24 | -const ( | ||
25 | - // VERSION represent beego web framework version. | ||
26 | - VERSION = "1.10.0" | ||
27 | - | ||
28 | - // DEV is for develop | ||
29 | - DEV = "dev" | ||
30 | - // PROD is for production | ||
31 | - PROD = "prod" | ||
32 | -) | ||
33 | - | ||
34 | -//hook function to run | ||
35 | -type hookfunc func() error | ||
36 | - | ||
37 | -var ( | ||
38 | - hooks = make([]hookfunc, 0) //hook function slice to store the hookfunc | ||
39 | -) | ||
40 | - | ||
41 | -// AddAPPStartHook is used to register the hookfunc | ||
42 | -// The hookfuncs will run in beego.Run() | ||
43 | -// such as initiating session , starting middleware , building template, starting admin control and so on. | ||
44 | -func AddAPPStartHook(hf ...hookfunc) { | ||
45 | - hooks = append(hooks, hf...) | ||
46 | -} | ||
47 | - | ||
48 | -// Run beego application. | ||
49 | -// beego.Run() default run on HttpPort | ||
50 | -// beego.Run("localhost") | ||
51 | -// beego.Run(":8089") | ||
52 | -// beego.Run("127.0.0.1:8089") | ||
53 | -func Run(params ...string) { | ||
54 | - | ||
55 | - initBeforeHTTPRun() | ||
56 | - | ||
57 | - if len(params) > 0 && params[0] != "" { | ||
58 | - strs := strings.Split(params[0], ":") | ||
59 | - if len(strs) > 0 && strs[0] != "" { | ||
60 | - BConfig.Listen.HTTPAddr = strs[0] | ||
61 | - } | ||
62 | - if len(strs) > 1 && strs[1] != "" { | ||
63 | - BConfig.Listen.HTTPPort, _ = strconv.Atoi(strs[1]) | ||
64 | - } | ||
65 | - | ||
66 | - BConfig.Listen.Domains = params | ||
67 | - } | ||
68 | - | ||
69 | - BeeApp.Run() | ||
70 | -} | ||
71 | - | ||
72 | -// RunWithMiddleWares Run beego application with middlewares. | ||
73 | -func RunWithMiddleWares(addr string, mws ...MiddleWare) { | ||
74 | - initBeforeHTTPRun() | ||
75 | - | ||
76 | - strs := strings.Split(addr, ":") | ||
77 | - if len(strs) > 0 && strs[0] != "" { | ||
78 | - BConfig.Listen.HTTPAddr = strs[0] | ||
79 | - BConfig.Listen.Domains = []string{strs[0]} | ||
80 | - } | ||
81 | - if len(strs) > 1 && strs[1] != "" { | ||
82 | - BConfig.Listen.HTTPPort, _ = strconv.Atoi(strs[1]) | ||
83 | - } | ||
84 | - | ||
85 | - BeeApp.Run(mws...) | ||
86 | -} | ||
87 | - | ||
88 | -func initBeforeHTTPRun() { | ||
89 | - //init hooks | ||
90 | - AddAPPStartHook( | ||
91 | - registerMime, | ||
92 | - registerDefaultErrorHandler, | ||
93 | - registerSession, | ||
94 | - registerTemplate, | ||
95 | - registerAdmin, | ||
96 | - registerGzip, | ||
97 | - ) | ||
98 | - | ||
99 | - for _, hk := range hooks { | ||
100 | - if err := hk(); err != nil { | ||
101 | - panic(err) | ||
102 | - } | ||
103 | - } | ||
104 | -} | ||
105 | - | ||
106 | -// TestBeegoInit is for test package init | ||
107 | -func TestBeegoInit(ap string) { | ||
108 | - path := filepath.Join(ap, "conf", "app.conf") | ||
109 | - os.Chdir(ap) | ||
110 | - InitBeegoBeforeTest(path) | ||
111 | -} | ||
112 | - | ||
113 | -// InitBeegoBeforeTest is for test package init | ||
114 | -func InitBeegoBeforeTest(appConfigPath string) { | ||
115 | - if err := LoadAppConfig(appConfigProvider, appConfigPath); err != nil { | ||
116 | - panic(err) | ||
117 | - } | ||
118 | - BConfig.RunMode = "test" | ||
119 | - initBeforeHTTPRun() | ||
120 | -} |
1 | -// Copyright 2014 beego Author. All Rights Reserved. | ||
2 | -// | ||
3 | -// Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | -// you may not use this file except in compliance with the License. | ||
5 | -// You may obtain a copy of the License at | ||
6 | -// | ||
7 | -// http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | -// | ||
9 | -// Unless required by applicable law or agreed to in writing, software | ||
10 | -// distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | -// See the License for the specific language governing permissions and | ||
13 | -// limitations under the License. | ||
14 | - | ||
15 | -package beego | ||
16 | - | ||
17 | -import ( | ||
18 | - "fmt" | ||
19 | - "os" | ||
20 | - "path/filepath" | ||
21 | - "reflect" | ||
22 | - "runtime" | ||
23 | - "strings" | ||
24 | - | ||
25 | - "github.com/astaxie/beego/config" | ||
26 | - "github.com/astaxie/beego/context" | ||
27 | - "github.com/astaxie/beego/logs" | ||
28 | - "github.com/astaxie/beego/session" | ||
29 | - "github.com/astaxie/beego/utils" | ||
30 | -) | ||
31 | - | ||
32 | -// Config is the main struct for BConfig | ||
33 | -type Config struct { | ||
34 | - AppName string //Application name | ||
35 | - RunMode string //Running Mode: dev | prod | ||
36 | - RouterCaseSensitive bool | ||
37 | - ServerName string | ||
38 | - RecoverPanic bool | ||
39 | - RecoverFunc func(*context.Context) | ||
40 | - CopyRequestBody bool | ||
41 | - EnableGzip bool | ||
42 | - MaxMemory int64 | ||
43 | - EnableErrorsShow bool | ||
44 | - EnableErrorsRender bool | ||
45 | - Listen Listen | ||
46 | - WebConfig WebConfig | ||
47 | - Log LogConfig | ||
48 | -} | ||
49 | - | ||
50 | -// Listen holds for http and https related config | ||
51 | -type Listen struct { | ||
52 | - Graceful bool // Graceful means use graceful module to start the server | ||
53 | - ServerTimeOut int64 | ||
54 | - ListenTCP4 bool | ||
55 | - EnableHTTP bool | ||
56 | - HTTPAddr string | ||
57 | - HTTPPort int | ||
58 | - AutoTLS bool | ||
59 | - Domains []string | ||
60 | - TLSCacheDir string | ||
61 | - EnableHTTPS bool | ||
62 | - EnableMutualHTTPS bool | ||
63 | - HTTPSAddr string | ||
64 | - HTTPSPort int | ||
65 | - HTTPSCertFile string | ||
66 | - HTTPSKeyFile string | ||
67 | - TrustCaFile string | ||
68 | - EnableAdmin bool | ||
69 | - AdminAddr string | ||
70 | - AdminPort int | ||
71 | - EnableFcgi bool | ||
72 | - EnableStdIo bool // EnableStdIo works with EnableFcgi Use FCGI via standard I/O | ||
73 | -} | ||
74 | - | ||
75 | -// WebConfig holds web related config | ||
76 | -type WebConfig struct { | ||
77 | - AutoRender bool | ||
78 | - EnableDocs bool | ||
79 | - FlashName string | ||
80 | - FlashSeparator string | ||
81 | - DirectoryIndex bool | ||
82 | - StaticDir map[string]string | ||
83 | - StaticExtensionsToGzip []string | ||
84 | - TemplateLeft string | ||
85 | - TemplateRight string | ||
86 | - ViewsPath string | ||
87 | - EnableXSRF bool | ||
88 | - XSRFKey string | ||
89 | - XSRFExpire int | ||
90 | - Session SessionConfig | ||
91 | -} | ||
92 | - | ||
93 | -// SessionConfig holds session related config | ||
94 | -type SessionConfig struct { | ||
95 | - SessionOn bool | ||
96 | - SessionProvider string | ||
97 | - SessionName string | ||
98 | - SessionGCMaxLifetime int64 | ||
99 | - SessionProviderConfig string | ||
100 | - SessionCookieLifeTime int | ||
101 | - SessionAutoSetCookie bool | ||
102 | - SessionDomain string | ||
103 | - SessionDisableHTTPOnly bool // used to allow for cross domain cookies/javascript cookies. | ||
104 | - SessionEnableSidInHTTPHeader bool // enable store/get the sessionId into/from http headers | ||
105 | - SessionNameInHTTPHeader string | ||
106 | - SessionEnableSidInURLQuery bool // enable get the sessionId from Url Query params | ||
107 | -} | ||
108 | - | ||
109 | -// LogConfig holds Log related config | ||
110 | -type LogConfig struct { | ||
111 | - AccessLogs bool | ||
112 | - EnableStaticLogs bool //log static files requests default: false | ||
113 | - AccessLogsFormat string //access log format: JSON_FORMAT, APACHE_FORMAT or empty string | ||
114 | - FileLineNum bool | ||
115 | - Outputs map[string]string // Store Adaptor : config | ||
116 | -} | ||
117 | - | ||
118 | -var ( | ||
119 | - // BConfig is the default config for Application | ||
120 | - BConfig *Config | ||
121 | - // AppConfig is the instance of Config, store the config information from file | ||
122 | - AppConfig *beegoAppConfig | ||
123 | - // AppPath is the absolute path to the app | ||
124 | - AppPath string | ||
125 | - // GlobalSessions is the instance for the session manager | ||
126 | - GlobalSessions *session.Manager | ||
127 | - | ||
128 | - // appConfigPath is the path to the config files | ||
129 | - appConfigPath string | ||
130 | - // appConfigProvider is the provider for the config, default is ini | ||
131 | - appConfigProvider = "ini" | ||
132 | -) | ||
133 | - | ||
134 | -func init() { | ||
135 | - BConfig = newBConfig() | ||
136 | - var err error | ||
137 | - if AppPath, err = filepath.Abs(filepath.Dir(os.Args[0])); err != nil { | ||
138 | - panic(err) | ||
139 | - } | ||
140 | - workPath, err := os.Getwd() | ||
141 | - if err != nil { | ||
142 | - panic(err) | ||
143 | - } | ||
144 | - var filename = "app.conf" | ||
145 | - if os.Getenv("BEEGO_RUNMODE") != "" { | ||
146 | - filename = os.Getenv("BEEGO_RUNMODE") + ".app.conf" | ||
147 | - } | ||
148 | - appConfigPath = filepath.Join(workPath, "conf", filename) | ||
149 | - if !utils.FileExists(appConfigPath) { | ||
150 | - appConfigPath = filepath.Join(AppPath, "conf", filename) | ||
151 | - if !utils.FileExists(appConfigPath) { | ||
152 | - AppConfig = &beegoAppConfig{innerConfig: config.NewFakeConfig()} | ||
153 | - return | ||
154 | - } | ||
155 | - } | ||
156 | - if err = parseConfig(appConfigPath); err != nil { | ||
157 | - panic(err) | ||
158 | - } | ||
159 | -} | ||
160 | - | ||
161 | -func recoverPanic(ctx *context.Context) { | ||
162 | - if err := recover(); err != nil { | ||
163 | - if err == ErrAbort { | ||
164 | - return | ||
165 | - } | ||
166 | - if !BConfig.RecoverPanic { | ||
167 | - panic(err) | ||
168 | - } | ||
169 | - if BConfig.EnableErrorsShow { | ||
170 | - if _, ok := ErrorMaps[fmt.Sprint(err)]; ok { | ||
171 | - exception(fmt.Sprint(err), ctx) | ||
172 | - return | ||
173 | - } | ||
174 | - } | ||
175 | - var stack string | ||
176 | - logs.Critical("the request url is ", ctx.Input.URL()) | ||
177 | - logs.Critical("Handler crashed with error", err) | ||
178 | - for i := 1; ; i++ { | ||
179 | - _, file, line, ok := runtime.Caller(i) | ||
180 | - if !ok { | ||
181 | - break | ||
182 | - } | ||
183 | - logs.Critical(fmt.Sprintf("%s:%d", file, line)) | ||
184 | - stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line)) | ||
185 | - } | ||
186 | - if BConfig.RunMode == DEV && BConfig.EnableErrorsRender { | ||
187 | - showErr(err, ctx, stack) | ||
188 | - } | ||
189 | - if ctx.Output.Status != 0 { | ||
190 | - ctx.ResponseWriter.WriteHeader(ctx.Output.Status) | ||
191 | - } else { | ||
192 | - ctx.ResponseWriter.WriteHeader(500) | ||
193 | - } | ||
194 | - } | ||
195 | -} | ||
196 | - | ||
197 | -func newBConfig() *Config { | ||
198 | - return &Config{ | ||
199 | - AppName: "beego", | ||
200 | - RunMode: PROD, | ||
201 | - RouterCaseSensitive: true, | ||
202 | - ServerName: "beegoServer:" + VERSION, | ||
203 | - RecoverPanic: true, | ||
204 | - RecoverFunc: recoverPanic, | ||
205 | - CopyRequestBody: false, | ||
206 | - EnableGzip: false, | ||
207 | - MaxMemory: 1 << 26, //64MB | ||
208 | - EnableErrorsShow: true, | ||
209 | - EnableErrorsRender: true, | ||
210 | - Listen: Listen{ | ||
211 | - Graceful: false, | ||
212 | - ServerTimeOut: 0, | ||
213 | - ListenTCP4: false, | ||
214 | - EnableHTTP: true, | ||
215 | - AutoTLS: false, | ||
216 | - Domains: []string{}, | ||
217 | - TLSCacheDir: ".", | ||
218 | - HTTPAddr: "", | ||
219 | - HTTPPort: 8080, | ||
220 | - EnableHTTPS: false, | ||
221 | - HTTPSAddr: "", | ||
222 | - HTTPSPort: 10443, | ||
223 | - HTTPSCertFile: "", | ||
224 | - HTTPSKeyFile: "", | ||
225 | - EnableAdmin: false, | ||
226 | - AdminAddr: "", | ||
227 | - AdminPort: 8088, | ||
228 | - EnableFcgi: false, | ||
229 | - EnableStdIo: false, | ||
230 | - }, | ||
231 | - WebConfig: WebConfig{ | ||
232 | - AutoRender: true, | ||
233 | - EnableDocs: false, | ||
234 | - FlashName: "BEEGO_FLASH", | ||
235 | - FlashSeparator: "BEEGOFLASH", | ||
236 | - DirectoryIndex: false, | ||
237 | - StaticDir: map[string]string{"/static": "static"}, | ||
238 | - StaticExtensionsToGzip: []string{".css", ".js"}, | ||
239 | - TemplateLeft: "{{", | ||
240 | - TemplateRight: "}}", | ||
241 | - ViewsPath: "views", | ||
242 | - EnableXSRF: false, | ||
243 | - XSRFKey: "beegoxsrf", | ||
244 | - XSRFExpire: 0, | ||
245 | - Session: SessionConfig{ | ||
246 | - SessionOn: false, | ||
247 | - SessionProvider: "memory", | ||
248 | - SessionName: "beegosessionID", | ||
249 | - SessionGCMaxLifetime: 3600, | ||
250 | - SessionProviderConfig: "", | ||
251 | - SessionDisableHTTPOnly: false, | ||
252 | - SessionCookieLifeTime: 0, //set cookie default is the browser life | ||
253 | - SessionAutoSetCookie: true, | ||
254 | - SessionDomain: "", | ||
255 | - SessionEnableSidInHTTPHeader: false, // enable store/get the sessionId into/from http headers | ||
256 | - SessionNameInHTTPHeader: "Beegosessionid", | ||
257 | - SessionEnableSidInURLQuery: false, // enable get the sessionId from Url Query params | ||
258 | - }, | ||
259 | - }, | ||
260 | - Log: LogConfig{ | ||
261 | - AccessLogs: false, | ||
262 | - EnableStaticLogs: false, | ||
263 | - AccessLogsFormat: "APACHE_FORMAT", | ||
264 | - FileLineNum: true, | ||
265 | - Outputs: map[string]string{"console": ""}, | ||
266 | - }, | ||
267 | - } | ||
268 | -} | ||
269 | - | ||
270 | -// now only support ini, next will support json. | ||
271 | -func parseConfig(appConfigPath string) (err error) { | ||
272 | - AppConfig, err = newAppConfig(appConfigProvider, appConfigPath) | ||
273 | - if err != nil { | ||
274 | - return err | ||
275 | - } | ||
276 | - return assignConfig(AppConfig) | ||
277 | -} | ||
278 | - | ||
279 | -func assignConfig(ac config.Configer) error { | ||
280 | - for _, i := range []interface{}{BConfig, &BConfig.Listen, &BConfig.WebConfig, &BConfig.Log, &BConfig.WebConfig.Session} { | ||
281 | - assignSingleConfig(i, ac) | ||
282 | - } | ||
283 | - // set the run mode first | ||
284 | - if envRunMode := os.Getenv("BEEGO_RUNMODE"); envRunMode != "" { | ||
285 | - BConfig.RunMode = envRunMode | ||
286 | - } else if runMode := ac.String("RunMode"); runMode != "" { | ||
287 | - BConfig.RunMode = runMode | ||
288 | - } | ||
289 | - | ||
290 | - if sd := ac.String("StaticDir"); sd != "" { | ||
291 | - BConfig.WebConfig.StaticDir = map[string]string{} | ||
292 | - sds := strings.Fields(sd) | ||
293 | - for _, v := range sds { | ||
294 | - if url2fsmap := strings.SplitN(v, ":", 2); len(url2fsmap) == 2 { | ||
295 | - BConfig.WebConfig.StaticDir["/"+strings.Trim(url2fsmap[0], "/")] = url2fsmap[1] | ||
296 | - } else { | ||
297 | - BConfig.WebConfig.StaticDir["/"+strings.Trim(url2fsmap[0], "/")] = url2fsmap[0] | ||
298 | - } | ||
299 | - } | ||
300 | - } | ||
301 | - | ||
302 | - if sgz := ac.String("StaticExtensionsToGzip"); sgz != "" { | ||
303 | - extensions := strings.Split(sgz, ",") | ||
304 | - fileExts := []string{} | ||
305 | - for _, ext := range extensions { | ||
306 | - ext = strings.TrimSpace(ext) | ||
307 | - if ext == "" { | ||
308 | - continue | ||
309 | - } | ||
310 | - if !strings.HasPrefix(ext, ".") { | ||
311 | - ext = "." + ext | ||
312 | - } | ||
313 | - fileExts = append(fileExts, ext) | ||
314 | - } | ||
315 | - if len(fileExts) > 0 { | ||
316 | - BConfig.WebConfig.StaticExtensionsToGzip = fileExts | ||
317 | - } | ||
318 | - } | ||
319 | - | ||
320 | - if lo := ac.String("LogOutputs"); lo != "" { | ||
321 | - // if lo is not nil or empty | ||
322 | - // means user has set his own LogOutputs | ||
323 | - // clear the default setting to BConfig.Log.Outputs | ||
324 | - BConfig.Log.Outputs = make(map[string]string) | ||
325 | - los := strings.Split(lo, ";") | ||
326 | - for _, v := range los { | ||
327 | - if logType2Config := strings.SplitN(v, ",", 2); len(logType2Config) == 2 { | ||
328 | - BConfig.Log.Outputs[logType2Config[0]] = logType2Config[1] | ||
329 | - } else { | ||
330 | - continue | ||
331 | - } | ||
332 | - } | ||
333 | - } | ||
334 | - | ||
335 | - //init log | ||
336 | - logs.Reset() | ||
337 | - for adaptor, config := range BConfig.Log.Outputs { | ||
338 | - err := logs.SetLogger(adaptor, config) | ||
339 | - if err != nil { | ||
340 | - fmt.Fprintln(os.Stderr, fmt.Sprintf("%s with the config %q got err:%s", adaptor, config, err.Error())) | ||
341 | - } | ||
342 | - } | ||
343 | - logs.SetLogFuncCall(BConfig.Log.FileLineNum) | ||
344 | - | ||
345 | - return nil | ||
346 | -} | ||
347 | - | ||
348 | -func assignSingleConfig(p interface{}, ac config.Configer) { | ||
349 | - pt := reflect.TypeOf(p) | ||
350 | - if pt.Kind() != reflect.Ptr { | ||
351 | - return | ||
352 | - } | ||
353 | - pt = pt.Elem() | ||
354 | - if pt.Kind() != reflect.Struct { | ||
355 | - return | ||
356 | - } | ||
357 | - pv := reflect.ValueOf(p).Elem() | ||
358 | - | ||
359 | - for i := 0; i < pt.NumField(); i++ { | ||
360 | - pf := pv.Field(i) | ||
361 | - if !pf.CanSet() { | ||
362 | - continue | ||
363 | - } | ||
364 | - name := pt.Field(i).Name | ||
365 | - switch pf.Kind() { | ||
366 | - case reflect.String: | ||
367 | - pf.SetString(ac.DefaultString(name, pf.String())) | ||
368 | - case reflect.Int, reflect.Int64: | ||
369 | - pf.SetInt(ac.DefaultInt64(name, pf.Int())) | ||
370 | - case reflect.Bool: | ||
371 | - pf.SetBool(ac.DefaultBool(name, pf.Bool())) | ||
372 | - case reflect.Struct: | ||
373 | - default: | ||
374 | - //do nothing here | ||
375 | - } | ||
376 | - } | ||
377 | - | ||
378 | -} | ||
379 | - | ||
380 | -// LoadAppConfig allow developer to apply a config file | ||
381 | -func LoadAppConfig(adapterName, configPath string) error { | ||
382 | - absConfigPath, err := filepath.Abs(configPath) | ||
383 | - if err != nil { | ||
384 | - return err | ||
385 | - } | ||
386 | - | ||
387 | - if !utils.FileExists(absConfigPath) { | ||
388 | - return fmt.Errorf("the target config file: %s don't exist", configPath) | ||
389 | - } | ||
390 | - | ||
391 | - appConfigPath = absConfigPath | ||
392 | - appConfigProvider = adapterName | ||
393 | - | ||
394 | - return parseConfig(appConfigPath) | ||
395 | -} | ||
396 | - | ||
397 | -type beegoAppConfig struct { | ||
398 | - innerConfig config.Configer | ||
399 | -} | ||
400 | - | ||
401 | -func newAppConfig(appConfigProvider, appConfigPath string) (*beegoAppConfig, error) { | ||
402 | - ac, err := config.NewConfig(appConfigProvider, appConfigPath) | ||
403 | - if err != nil { | ||
404 | - return nil, err | ||
405 | - } | ||
406 | - return &beegoAppConfig{ac}, nil | ||
407 | -} | ||
408 | - | ||
409 | -func (b *beegoAppConfig) Set(key, val string) error { | ||
410 | - if err := b.innerConfig.Set(BConfig.RunMode+"::"+key, val); err != nil { | ||
411 | - return err | ||
412 | - } | ||
413 | - return b.innerConfig.Set(key, val) | ||
414 | -} | ||
415 | - | ||
416 | -func (b *beegoAppConfig) String(key string) string { | ||
417 | - if v := b.innerConfig.String(BConfig.RunMode + "::" + key); v != "" { | ||
418 | - return v | ||
419 | - } | ||
420 | - return b.innerConfig.String(key) | ||
421 | -} | ||
422 | - | ||
423 | -func (b *beegoAppConfig) Strings(key string) []string { | ||
424 | - if v := b.innerConfig.Strings(BConfig.RunMode + "::" + key); len(v) > 0 { | ||
425 | - return v | ||
426 | - } | ||
427 | - return b.innerConfig.Strings(key) | ||
428 | -} | ||
429 | - | ||
430 | -func (b *beegoAppConfig) Int(key string) (int, error) { | ||
431 | - if v, err := b.innerConfig.Int(BConfig.RunMode + "::" + key); err == nil { | ||
432 | - return v, nil | ||
433 | - } | ||
434 | - return b.innerConfig.Int(key) | ||
435 | -} | ||
436 | - | ||
437 | -func (b *beegoAppConfig) Int64(key string) (int64, error) { | ||
438 | - if v, err := b.innerConfig.Int64(BConfig.RunMode + "::" + key); err == nil { | ||
439 | - return v, nil | ||
440 | - } | ||
441 | - return b.innerConfig.Int64(key) | ||
442 | -} | ||
443 | - | ||
444 | -func (b *beegoAppConfig) Bool(key string) (bool, error) { | ||
445 | - if v, err := b.innerConfig.Bool(BConfig.RunMode + "::" + key); err == nil { | ||
446 | - return v, nil | ||
447 | - } | ||
448 | - return b.innerConfig.Bool(key) | ||
449 | -} | ||
450 | - | ||
451 | -func (b *beegoAppConfig) Float(key string) (float64, error) { | ||
452 | - if v, err := b.innerConfig.Float(BConfig.RunMode + "::" + key); err == nil { | ||
453 | - return v, nil | ||
454 | - } | ||
455 | - return b.innerConfig.Float(key) | ||
456 | -} | ||
457 | - | ||
458 | -func (b *beegoAppConfig) DefaultString(key string, defaultVal string) string { | ||
459 | - if v := b.String(key); v != "" { | ||
460 | - return v | ||
461 | - } | ||
462 | - return defaultVal | ||
463 | -} | ||
464 | - | ||
465 | -func (b *beegoAppConfig) DefaultStrings(key string, defaultVal []string) []string { | ||
466 | - if v := b.Strings(key); len(v) != 0 { | ||
467 | - return v | ||
468 | - } | ||
469 | - return defaultVal | ||
470 | -} | ||
471 | - | ||
472 | -func (b *beegoAppConfig) DefaultInt(key string, defaultVal int) int { | ||
473 | - if v, err := b.Int(key); err == nil { | ||
474 | - return v | ||
475 | - } | ||
476 | - return defaultVal | ||
477 | -} | ||
478 | - | ||
479 | -func (b *beegoAppConfig) DefaultInt64(key string, defaultVal int64) int64 { | ||
480 | - if v, err := b.Int64(key); err == nil { | ||
481 | - return v | ||
482 | - } | ||
483 | - return defaultVal | ||
484 | -} | ||
485 | - | ||
486 | -func (b *beegoAppConfig) DefaultBool(key string, defaultVal bool) bool { | ||
487 | - if v, err := b.Bool(key); err == nil { | ||
488 | - return v | ||
489 | - } | ||
490 | - return defaultVal | ||
491 | -} | ||
492 | - | ||
493 | -func (b *beegoAppConfig) DefaultFloat(key string, defaultVal float64) float64 { | ||
494 | - if v, err := b.Float(key); err == nil { | ||
495 | - return v | ||
496 | - } | ||
497 | - return defaultVal | ||
498 | -} | ||
499 | - | ||
500 | -func (b *beegoAppConfig) DIY(key string) (interface{}, error) { | ||
501 | - return b.innerConfig.DIY(key) | ||
502 | -} | ||
503 | - | ||
504 | -func (b *beegoAppConfig) GetSection(section string) (map[string]string, error) { | ||
505 | - return b.innerConfig.GetSection(section) | ||
506 | -} | ||
507 | - | ||
508 | -func (b *beegoAppConfig) SaveConfigFile(filename string) error { | ||
509 | - return b.innerConfig.SaveConfigFile(filename) | ||
510 | -} |
1 | -// Copyright 2014 beego Author. All Rights Reserved. | ||
2 | -// | ||
3 | -// Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | -// you may not use this file except in compliance with the License. | ||
5 | -// You may obtain a copy of the License at | ||
6 | -// | ||
7 | -// http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | -// | ||
9 | -// Unless required by applicable law or agreed to in writing, software | ||
10 | -// distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | -// See the License for the specific language governing permissions and | ||
13 | -// limitations under the License. | ||
14 | - | ||
15 | -// Package config is used to parse config. | ||
16 | -// Usage: | ||
17 | -// import "github.com/astaxie/beego/config" | ||
18 | -//Examples. | ||
19 | -// | ||
20 | -// cnf, err := config.NewConfig("ini", "config.conf") | ||
21 | -// | ||
22 | -// cnf APIS: | ||
23 | -// | ||
24 | -// cnf.Set(key, val string) error | ||
25 | -// cnf.String(key string) string | ||
26 | -// cnf.Strings(key string) []string | ||
27 | -// cnf.Int(key string) (int, error) | ||
28 | -// cnf.Int64(key string) (int64, error) | ||
29 | -// cnf.Bool(key string) (bool, error) | ||
30 | -// cnf.Float(key string) (float64, error) | ||
31 | -// cnf.DefaultString(key string, defaultVal string) string | ||
32 | -// cnf.DefaultStrings(key string, defaultVal []string) []string | ||
33 | -// cnf.DefaultInt(key string, defaultVal int) int | ||
34 | -// cnf.DefaultInt64(key string, defaultVal int64) int64 | ||
35 | -// cnf.DefaultBool(key string, defaultVal bool) bool | ||
36 | -// cnf.DefaultFloat(key string, defaultVal float64) float64 | ||
37 | -// cnf.DIY(key string) (interface{}, error) | ||
38 | -// cnf.GetSection(section string) (map[string]string, error) | ||
39 | -// cnf.SaveConfigFile(filename string) error | ||
40 | -//More docs http://beego.me/docs/module/config.md | ||
41 | -package config | ||
42 | - | ||
43 | -import ( | ||
44 | - "fmt" | ||
45 | - "os" | ||
46 | - "reflect" | ||
47 | - "time" | ||
48 | -) | ||
49 | - | ||
50 | -// Configer defines how to get and set value from configuration raw data. | ||
51 | -type Configer interface { | ||
52 | - Set(key, val string) error //support section::key type in given key when using ini type. | ||
53 | - String(key string) string //support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same. | ||
54 | - Strings(key string) []string //get string slice | ||
55 | - Int(key string) (int, error) | ||
56 | - Int64(key string) (int64, error) | ||
57 | - Bool(key string) (bool, error) | ||
58 | - Float(key string) (float64, error) | ||
59 | - DefaultString(key string, defaultVal string) string // support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same. | ||
60 | - DefaultStrings(key string, defaultVal []string) []string //get string slice | ||
61 | - DefaultInt(key string, defaultVal int) int | ||
62 | - DefaultInt64(key string, defaultVal int64) int64 | ||
63 | - DefaultBool(key string, defaultVal bool) bool | ||
64 | - DefaultFloat(key string, defaultVal float64) float64 | ||
65 | - DIY(key string) (interface{}, error) | ||
66 | - GetSection(section string) (map[string]string, error) | ||
67 | - SaveConfigFile(filename string) error | ||
68 | -} | ||
69 | - | ||
70 | -// Config is the adapter interface for parsing config file to get raw data to Configer. | ||
71 | -type Config interface { | ||
72 | - Parse(key string) (Configer, error) | ||
73 | - ParseData(data []byte) (Configer, error) | ||
74 | -} | ||
75 | - | ||
76 | -var adapters = make(map[string]Config) | ||
77 | - | ||
78 | -// Register makes a config adapter available by the adapter name. | ||
79 | -// If Register is called twice with the same name or if driver is nil, | ||
80 | -// it panics. | ||
81 | -func Register(name string, adapter Config) { | ||
82 | - if adapter == nil { | ||
83 | - panic("config: Register adapter is nil") | ||
84 | - } | ||
85 | - if _, ok := adapters[name]; ok { | ||
86 | - panic("config: Register called twice for adapter " + name) | ||
87 | - } | ||
88 | - adapters[name] = adapter | ||
89 | -} | ||
90 | - | ||
91 | -// NewConfig adapterName is ini/json/xml/yaml. | ||
92 | -// filename is the config file path. | ||
93 | -func NewConfig(adapterName, filename string) (Configer, error) { | ||
94 | - adapter, ok := adapters[adapterName] | ||
95 | - if !ok { | ||
96 | - return nil, fmt.Errorf("config: unknown adaptername %q (forgotten import?)", adapterName) | ||
97 | - } | ||
98 | - return adapter.Parse(filename) | ||
99 | -} | ||
100 | - | ||
101 | -// NewConfigData adapterName is ini/json/xml/yaml. | ||
102 | -// data is the config data. | ||
103 | -func NewConfigData(adapterName string, data []byte) (Configer, error) { | ||
104 | - adapter, ok := adapters[adapterName] | ||
105 | - if !ok { | ||
106 | - return nil, fmt.Errorf("config: unknown adaptername %q (forgotten import?)", adapterName) | ||
107 | - } | ||
108 | - return adapter.ParseData(data) | ||
109 | -} | ||
110 | - | ||
111 | -// ExpandValueEnvForMap convert all string value with environment variable. | ||
112 | -func ExpandValueEnvForMap(m map[string]interface{}) map[string]interface{} { | ||
113 | - for k, v := range m { | ||
114 | - switch value := v.(type) { | ||
115 | - case string: | ||
116 | - m[k] = ExpandValueEnv(value) | ||
117 | - case map[string]interface{}: | ||
118 | - m[k] = ExpandValueEnvForMap(value) | ||
119 | - case map[string]string: | ||
120 | - for k2, v2 := range value { | ||
121 | - value[k2] = ExpandValueEnv(v2) | ||
122 | - } | ||
123 | - m[k] = value | ||
124 | - } | ||
125 | - } | ||
126 | - return m | ||
127 | -} | ||
128 | - | ||
129 | -// ExpandValueEnv returns value of convert with environment variable. | ||
130 | -// | ||
131 | -// Return environment variable if value start with "${" and end with "}". | ||
132 | -// Return default value if environment variable is empty or not exist. | ||
133 | -// | ||
134 | -// It accept value formats "${env}" , "${env||}}" , "${env||defaultValue}" , "defaultvalue". | ||
135 | -// Examples: | ||
136 | -// v1 := config.ExpandValueEnv("${GOPATH}") // return the GOPATH environment variable. | ||
137 | -// v2 := config.ExpandValueEnv("${GOAsta||/usr/local/go}") // return the default value "/usr/local/go/". | ||
138 | -// v3 := config.ExpandValueEnv("Astaxie") // return the value "Astaxie". | ||
139 | -func ExpandValueEnv(value string) (realValue string) { | ||
140 | - realValue = value | ||
141 | - | ||
142 | - vLen := len(value) | ||
143 | - // 3 = ${} | ||
144 | - if vLen < 3 { | ||
145 | - return | ||
146 | - } | ||
147 | - // Need start with "${" and end with "}", then return. | ||
148 | - if value[0] != '$' || value[1] != '{' || value[vLen-1] != '}' { | ||
149 | - return | ||
150 | - } | ||
151 | - | ||
152 | - key := "" | ||
153 | - defaultV := "" | ||
154 | - // value start with "${" | ||
155 | - for i := 2; i < vLen; i++ { | ||
156 | - if value[i] == '|' && (i+1 < vLen && value[i+1] == '|') { | ||
157 | - key = value[2:i] | ||
158 | - defaultV = value[i+2 : vLen-1] // other string is default value. | ||
159 | - break | ||
160 | - } else if value[i] == '}' { | ||
161 | - key = value[2:i] | ||
162 | - break | ||
163 | - } | ||
164 | - } | ||
165 | - | ||
166 | - realValue = os.Getenv(key) | ||
167 | - if realValue == "" { | ||
168 | - realValue = defaultV | ||
169 | - } | ||
170 | - | ||
171 | - return | ||
172 | -} | ||
173 | - | ||
174 | -// ParseBool returns the boolean value represented by the string. | ||
175 | -// | ||
176 | -// It accepts 1, 1.0, t, T, TRUE, true, True, YES, yes, Yes,Y, y, ON, on, On, | ||
177 | -// 0, 0.0, f, F, FALSE, false, False, NO, no, No, N,n, OFF, off, Off. | ||
178 | -// Any other value returns an error. | ||
179 | -func ParseBool(val interface{}) (value bool, err error) { | ||
180 | - if val != nil { | ||
181 | - switch v := val.(type) { | ||
182 | - case bool: | ||
183 | - return v, nil | ||
184 | - case string: | ||
185 | - switch v { | ||
186 | - case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "Y", "y", "ON", "on", "On": | ||
187 | - return true, nil | ||
188 | - case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "N", "n", "OFF", "off", "Off": | ||
189 | - return false, nil | ||
190 | - } | ||
191 | - case int8, int32, int64: | ||
192 | - strV := fmt.Sprintf("%d", v) | ||
193 | - if strV == "1" { | ||
194 | - return true, nil | ||
195 | - } else if strV == "0" { | ||
196 | - return false, nil | ||
197 | - } | ||
198 | - case float64: | ||
199 | - if v == 1.0 { | ||
200 | - return true, nil | ||
201 | - } else if v == 0.0 { | ||
202 | - return false, nil | ||
203 | - } | ||
204 | - } | ||
205 | - return false, fmt.Errorf("parsing %q: invalid syntax", val) | ||
206 | - } | ||
207 | - return false, fmt.Errorf("parsing <nil>: invalid syntax") | ||
208 | -} | ||
209 | - | ||
210 | -// ToString converts values of any type to string. | ||
211 | -func ToString(x interface{}) string { | ||
212 | - switch y := x.(type) { | ||
213 | - | ||
214 | - // Handle dates with special logic | ||
215 | - // This needs to come above the fmt.Stringer | ||
216 | - // test since time.Time's have a .String() | ||
217 | - // method | ||
218 | - case time.Time: | ||
219 | - return y.Format("A Monday") | ||
220 | - | ||
221 | - // Handle type string | ||
222 | - case string: | ||
223 | - return y | ||
224 | - | ||
225 | - // Handle type with .String() method | ||
226 | - case fmt.Stringer: | ||
227 | - return y.String() | ||
228 | - | ||
229 | - // Handle type with .Error() method | ||
230 | - case error: | ||
231 | - return y.Error() | ||
232 | - | ||
233 | - } | ||
234 | - | ||
235 | - // Handle named string type | ||
236 | - if v := reflect.ValueOf(x); v.Kind() == reflect.String { | ||
237 | - return v.String() | ||
238 | - } | ||
239 | - | ||
240 | - // Fallback to fmt package for anything else like numeric types | ||
241 | - return fmt.Sprint(x) | ||
242 | -} |
1 | -// Copyright 2014 beego Author. All Rights Reserved. | ||
2 | -// | ||
3 | -// Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | -// you may not use this file except in compliance with the License. | ||
5 | -// You may obtain a copy of the License at | ||
6 | -// | ||
7 | -// http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | -// | ||
9 | -// Unless required by applicable law or agreed to in writing, software | ||
10 | -// distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | -// See the License for the specific language governing permissions and | ||
13 | -// limitations under the License. | ||
14 | - | ||
15 | -package config | ||
16 | - | ||
17 | -import ( | ||
18 | - "errors" | ||
19 | - "strconv" | ||
20 | - "strings" | ||
21 | -) | ||
22 | - | ||
23 | -type fakeConfigContainer struct { | ||
24 | - data map[string]string | ||
25 | -} | ||
26 | - | ||
27 | -func (c *fakeConfigContainer) getData(key string) string { | ||
28 | - return c.data[strings.ToLower(key)] | ||
29 | -} | ||
30 | - | ||
31 | -func (c *fakeConfigContainer) Set(key, val string) error { | ||
32 | - c.data[strings.ToLower(key)] = val | ||
33 | - return nil | ||
34 | -} | ||
35 | - | ||
36 | -func (c *fakeConfigContainer) String(key string) string { | ||
37 | - return c.getData(key) | ||
38 | -} | ||
39 | - | ||
40 | -func (c *fakeConfigContainer) DefaultString(key string, defaultval string) string { | ||
41 | - v := c.String(key) | ||
42 | - if v == "" { | ||
43 | - return defaultval | ||
44 | - } | ||
45 | - return v | ||
46 | -} | ||
47 | - | ||
48 | -func (c *fakeConfigContainer) Strings(key string) []string { | ||
49 | - v := c.String(key) | ||
50 | - if v == "" { | ||
51 | - return nil | ||
52 | - } | ||
53 | - return strings.Split(v, ";") | ||
54 | -} | ||
55 | - | ||
56 | -func (c *fakeConfigContainer) DefaultStrings(key string, defaultval []string) []string { | ||
57 | - v := c.Strings(key) | ||
58 | - if v == nil { | ||
59 | - return defaultval | ||
60 | - } | ||
61 | - return v | ||
62 | -} | ||
63 | - | ||
64 | -func (c *fakeConfigContainer) Int(key string) (int, error) { | ||
65 | - return strconv.Atoi(c.getData(key)) | ||
66 | -} | ||
67 | - | ||
68 | -func (c *fakeConfigContainer) DefaultInt(key string, defaultval int) int { | ||
69 | - v, err := c.Int(key) | ||
70 | - if err != nil { | ||
71 | - return defaultval | ||
72 | - } | ||
73 | - return v | ||
74 | -} | ||
75 | - | ||
76 | -func (c *fakeConfigContainer) Int64(key string) (int64, error) { | ||
77 | - return strconv.ParseInt(c.getData(key), 10, 64) | ||
78 | -} | ||
79 | - | ||
80 | -func (c *fakeConfigContainer) DefaultInt64(key string, defaultval int64) int64 { | ||
81 | - v, err := c.Int64(key) | ||
82 | - if err != nil { | ||
83 | - return defaultval | ||
84 | - } | ||
85 | - return v | ||
86 | -} | ||
87 | - | ||
88 | -func (c *fakeConfigContainer) Bool(key string) (bool, error) { | ||
89 | - return ParseBool(c.getData(key)) | ||
90 | -} | ||
91 | - | ||
92 | -func (c *fakeConfigContainer) DefaultBool(key string, defaultval bool) bool { | ||
93 | - v, err := c.Bool(key) | ||
94 | - if err != nil { | ||
95 | - return defaultval | ||
96 | - } | ||
97 | - return v | ||
98 | -} | ||
99 | - | ||
100 | -func (c *fakeConfigContainer) Float(key string) (float64, error) { | ||
101 | - return strconv.ParseFloat(c.getData(key), 64) | ||
102 | -} | ||
103 | - | ||
104 | -func (c *fakeConfigContainer) DefaultFloat(key string, defaultval float64) float64 { | ||
105 | - v, err := c.Float(key) | ||
106 | - if err != nil { | ||
107 | - return defaultval | ||
108 | - } | ||
109 | - return v | ||
110 | -} | ||
111 | - | ||
112 | -func (c *fakeConfigContainer) DIY(key string) (interface{}, error) { | ||
113 | - if v, ok := c.data[strings.ToLower(key)]; ok { | ||
114 | - return v, nil | ||
115 | - } | ||
116 | - return nil, errors.New("key not find") | ||
117 | -} | ||
118 | - | ||
119 | -func (c *fakeConfigContainer) GetSection(section string) (map[string]string, error) { | ||
120 | - return nil, errors.New("not implement in the fakeConfigContainer") | ||
121 | -} | ||
122 | - | ||
123 | -func (c *fakeConfigContainer) SaveConfigFile(filename string) error { | ||
124 | - return errors.New("not implement in the fakeConfigContainer") | ||
125 | -} | ||
126 | - | ||
127 | -var _ Configer = new(fakeConfigContainer) | ||
128 | - | ||
129 | -// NewFakeConfig return a fake Configer | ||
130 | -func NewFakeConfig() Configer { | ||
131 | - return &fakeConfigContainer{ | ||
132 | - data: make(map[string]string), | ||
133 | - } | ||
134 | -} |
1 | -// Copyright 2014 beego Author. All Rights Reserved. | ||
2 | -// | ||
3 | -// Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | -// you may not use this file except in compliance with the License. | ||
5 | -// You may obtain a copy of the License at | ||
6 | -// | ||
7 | -// http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | -// | ||
9 | -// Unless required by applicable law or agreed to in writing, software | ||
10 | -// distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | -// See the License for the specific language governing permissions and | ||
13 | -// limitations under the License. | ||
14 | - | ||
15 | -package config | ||
16 | - | ||
17 | -import ( | ||
18 | - "bufio" | ||
19 | - "bytes" | ||
20 | - "errors" | ||
21 | - "io" | ||
22 | - "io/ioutil" | ||
23 | - "os" | ||
24 | - "os/user" | ||
25 | - "path/filepath" | ||
26 | - "strconv" | ||
27 | - "strings" | ||
28 | - "sync" | ||
29 | -) | ||
30 | - | ||
31 | -var ( | ||
32 | - defaultSection = "default" // default section means if some ini items not in a section, make them in default section, | ||
33 | - bNumComment = []byte{'#'} // number signal | ||
34 | - bSemComment = []byte{';'} // semicolon signal | ||
35 | - bEmpty = []byte{} | ||
36 | - bEqual = []byte{'='} // equal signal | ||
37 | - bDQuote = []byte{'"'} // quote signal | ||
38 | - sectionStart = []byte{'['} // section start signal | ||
39 | - sectionEnd = []byte{']'} // section end signal | ||
40 | - lineBreak = "\n" | ||
41 | -) | ||
42 | - | ||
43 | -// IniConfig implements Config to parse ini file. | ||
44 | -type IniConfig struct { | ||
45 | -} | ||
46 | - | ||
47 | -// Parse creates a new Config and parses the file configuration from the named file. | ||
48 | -func (ini *IniConfig) Parse(name string) (Configer, error) { | ||
49 | - return ini.parseFile(name) | ||
50 | -} | ||
51 | - | ||
52 | -func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) { | ||
53 | - data, err := ioutil.ReadFile(name) | ||
54 | - if err != nil { | ||
55 | - return nil, err | ||
56 | - } | ||
57 | - | ||
58 | - return ini.parseData(filepath.Dir(name), data) | ||
59 | -} | ||
60 | - | ||
61 | -func (ini *IniConfig) parseData(dir string, data []byte) (*IniConfigContainer, error) { | ||
62 | - cfg := &IniConfigContainer{ | ||
63 | - data: make(map[string]map[string]string), | ||
64 | - sectionComment: make(map[string]string), | ||
65 | - keyComment: make(map[string]string), | ||
66 | - RWMutex: sync.RWMutex{}, | ||
67 | - } | ||
68 | - cfg.Lock() | ||
69 | - defer cfg.Unlock() | ||
70 | - | ||
71 | - var comment bytes.Buffer | ||
72 | - buf := bufio.NewReader(bytes.NewBuffer(data)) | ||
73 | - // check the BOM | ||
74 | - head, err := buf.Peek(3) | ||
75 | - if err == nil && head[0] == 239 && head[1] == 187 && head[2] == 191 { | ||
76 | - for i := 1; i <= 3; i++ { | ||
77 | - buf.ReadByte() | ||
78 | - } | ||
79 | - } | ||
80 | - section := defaultSection | ||
81 | - for { | ||
82 | - line, _, err := buf.ReadLine() | ||
83 | - if err == io.EOF { | ||
84 | - break | ||
85 | - } | ||
86 | - //It might be a good idea to throw a error on all unknonw errors? | ||
87 | - if _, ok := err.(*os.PathError); ok { | ||
88 | - return nil, err | ||
89 | - } | ||
90 | - line = bytes.TrimSpace(line) | ||
91 | - if bytes.Equal(line, bEmpty) { | ||
92 | - continue | ||
93 | - } | ||
94 | - var bComment []byte | ||
95 | - switch { | ||
96 | - case bytes.HasPrefix(line, bNumComment): | ||
97 | - bComment = bNumComment | ||
98 | - case bytes.HasPrefix(line, bSemComment): | ||
99 | - bComment = bSemComment | ||
100 | - } | ||
101 | - if bComment != nil { | ||
102 | - line = bytes.TrimLeft(line, string(bComment)) | ||
103 | - // Need append to a new line if multi-line comments. | ||
104 | - if comment.Len() > 0 { | ||
105 | - comment.WriteByte('\n') | ||
106 | - } | ||
107 | - comment.Write(line) | ||
108 | - continue | ||
109 | - } | ||
110 | - | ||
111 | - if bytes.HasPrefix(line, sectionStart) && bytes.HasSuffix(line, sectionEnd) { | ||
112 | - section = strings.ToLower(string(line[1 : len(line)-1])) // section name case insensitive | ||
113 | - if comment.Len() > 0 { | ||
114 | - cfg.sectionComment[section] = comment.String() | ||
115 | - comment.Reset() | ||
116 | - } | ||
117 | - if _, ok := cfg.data[section]; !ok { | ||
118 | - cfg.data[section] = make(map[string]string) | ||
119 | - } | ||
120 | - continue | ||
121 | - } | ||
122 | - | ||
123 | - if _, ok := cfg.data[section]; !ok { | ||
124 | - cfg.data[section] = make(map[string]string) | ||
125 | - } | ||
126 | - keyValue := bytes.SplitN(line, bEqual, 2) | ||
127 | - | ||
128 | - key := string(bytes.TrimSpace(keyValue[0])) // key name case insensitive | ||
129 | - key = strings.ToLower(key) | ||
130 | - | ||
131 | - // handle include "other.conf" | ||
132 | - if len(keyValue) == 1 && strings.HasPrefix(key, "include") { | ||
133 | - | ||
134 | - includefiles := strings.Fields(key) | ||
135 | - if includefiles[0] == "include" && len(includefiles) == 2 { | ||
136 | - | ||
137 | - otherfile := strings.Trim(includefiles[1], "\"") | ||
138 | - if !filepath.IsAbs(otherfile) { | ||
139 | - otherfile = filepath.Join(dir, otherfile) | ||
140 | - } | ||
141 | - | ||
142 | - i, err := ini.parseFile(otherfile) | ||
143 | - if err != nil { | ||
144 | - return nil, err | ||
145 | - } | ||
146 | - | ||
147 | - for sec, dt := range i.data { | ||
148 | - if _, ok := cfg.data[sec]; !ok { | ||
149 | - cfg.data[sec] = make(map[string]string) | ||
150 | - } | ||
151 | - for k, v := range dt { | ||
152 | - cfg.data[sec][k] = v | ||
153 | - } | ||
154 | - } | ||
155 | - | ||
156 | - for sec, comm := range i.sectionComment { | ||
157 | - cfg.sectionComment[sec] = comm | ||
158 | - } | ||
159 | - | ||
160 | - for k, comm := range i.keyComment { | ||
161 | - cfg.keyComment[k] = comm | ||
162 | - } | ||
163 | - | ||
164 | - continue | ||
165 | - } | ||
166 | - } | ||
167 | - | ||
168 | - if len(keyValue) != 2 { | ||
169 | - return nil, errors.New("read the content error: \"" + string(line) + "\", should key = val") | ||
170 | - } | ||
171 | - val := bytes.TrimSpace(keyValue[1]) | ||
172 | - if bytes.HasPrefix(val, bDQuote) { | ||
173 | - val = bytes.Trim(val, `"`) | ||
174 | - } | ||
175 | - | ||
176 | - cfg.data[section][key] = ExpandValueEnv(string(val)) | ||
177 | - if comment.Len() > 0 { | ||
178 | - cfg.keyComment[section+"."+key] = comment.String() | ||
179 | - comment.Reset() | ||
180 | - } | ||
181 | - | ||
182 | - } | ||
183 | - return cfg, nil | ||
184 | -} | ||
185 | - | ||
186 | -// ParseData parse ini the data | ||
187 | -// When include other.conf,other.conf is either absolute directory | ||
188 | -// or under beego in default temporary directory(/tmp/beego[-username]). | ||
189 | -func (ini *IniConfig) ParseData(data []byte) (Configer, error) { | ||
190 | - dir := "beego" | ||
191 | - currentUser, err := user.Current() | ||
192 | - if err == nil { | ||
193 | - dir = "beego-" + currentUser.Username | ||
194 | - } | ||
195 | - dir = filepath.Join(os.TempDir(), dir) | ||
196 | - if err = os.MkdirAll(dir, os.ModePerm); err != nil { | ||
197 | - return nil, err | ||
198 | - } | ||
199 | - | ||
200 | - return ini.parseData(dir, data) | ||
201 | -} | ||
202 | - | ||
203 | -// IniConfigContainer A Config represents the ini configuration. | ||
204 | -// When set and get value, support key as section:name type. | ||
205 | -type IniConfigContainer struct { | ||
206 | - data map[string]map[string]string // section=> key:val | ||
207 | - sectionComment map[string]string // section : comment | ||
208 | - keyComment map[string]string // id: []{comment, key...}; id 1 is for main comment. | ||
209 | - sync.RWMutex | ||
210 | -} | ||
211 | - | ||
212 | -// Bool returns the boolean value for a given key. | ||
213 | -func (c *IniConfigContainer) Bool(key string) (bool, error) { | ||
214 | - return ParseBool(c.getdata(key)) | ||
215 | -} | ||
216 | - | ||
217 | -// DefaultBool returns the boolean value for a given key. | ||
218 | -// if err != nil return defaultval | ||
219 | -func (c *IniConfigContainer) DefaultBool(key string, defaultval bool) bool { | ||
220 | - v, err := c.Bool(key) | ||
221 | - if err != nil { | ||
222 | - return defaultval | ||
223 | - } | ||
224 | - return v | ||
225 | -} | ||
226 | - | ||
227 | -// Int returns the integer value for a given key. | ||
228 | -func (c *IniConfigContainer) Int(key string) (int, error) { | ||
229 | - return strconv.Atoi(c.getdata(key)) | ||
230 | -} | ||
231 | - | ||
232 | -// DefaultInt returns the integer value for a given key. | ||
233 | -// if err != nil return defaultval | ||
234 | -func (c *IniConfigContainer) DefaultInt(key string, defaultval int) int { | ||
235 | - v, err := c.Int(key) | ||
236 | - if err != nil { | ||
237 | - return defaultval | ||
238 | - } | ||
239 | - return v | ||
240 | -} | ||
241 | - | ||
242 | -// Int64 returns the int64 value for a given key. | ||
243 | -func (c *IniConfigContainer) Int64(key string) (int64, error) { | ||
244 | - return strconv.ParseInt(c.getdata(key), 10, 64) | ||
245 | -} | ||
246 | - | ||
247 | -// DefaultInt64 returns the int64 value for a given key. | ||
248 | -// if err != nil return defaultval | ||
249 | -func (c *IniConfigContainer) DefaultInt64(key string, defaultval int64) int64 { | ||
250 | - v, err := c.Int64(key) | ||
251 | - if err != nil { | ||
252 | - return defaultval | ||
253 | - } | ||
254 | - return v | ||
255 | -} | ||
256 | - | ||
257 | -// Float returns the float value for a given key. | ||
258 | -func (c *IniConfigContainer) Float(key string) (float64, error) { | ||
259 | - return strconv.ParseFloat(c.getdata(key), 64) | ||
260 | -} | ||
261 | - | ||
262 | -// DefaultFloat returns the float64 value for a given key. | ||
263 | -// if err != nil return defaultval | ||
264 | -func (c *IniConfigContainer) DefaultFloat(key string, defaultval float64) float64 { | ||
265 | - v, err := c.Float(key) | ||
266 | - if err != nil { | ||
267 | - return defaultval | ||
268 | - } | ||
269 | - return v | ||
270 | -} | ||
271 | - | ||
272 | -// String returns the string value for a given key. | ||
273 | -func (c *IniConfigContainer) String(key string) string { | ||
274 | - return c.getdata(key) | ||
275 | -} | ||
276 | - | ||
277 | -// DefaultString returns the string value for a given key. | ||
278 | -// if err != nil return defaultval | ||
279 | -func (c *IniConfigContainer) DefaultString(key string, defaultval string) string { | ||
280 | - v := c.String(key) | ||
281 | - if v == "" { | ||
282 | - return defaultval | ||
283 | - } | ||
284 | - return v | ||
285 | -} | ||
286 | - | ||
287 | -// Strings returns the []string value for a given key. | ||
288 | -// Return nil if config value does not exist or is empty. | ||
289 | -func (c *IniConfigContainer) Strings(key string) []string { | ||
290 | - v := c.String(key) | ||
291 | - if v == "" { | ||
292 | - return nil | ||
293 | - } | ||
294 | - return strings.Split(v, ";") | ||
295 | -} | ||
296 | - | ||
297 | -// DefaultStrings returns the []string value for a given key. | ||
298 | -// if err != nil return defaultval | ||
299 | -func (c *IniConfigContainer) DefaultStrings(key string, defaultval []string) []string { | ||
300 | - v := c.Strings(key) | ||
301 | - if v == nil { | ||
302 | - return defaultval | ||
303 | - } | ||
304 | - return v | ||
305 | -} | ||
306 | - | ||
307 | -// GetSection returns map for the given section | ||
308 | -func (c *IniConfigContainer) GetSection(section string) (map[string]string, error) { | ||
309 | - if v, ok := c.data[section]; ok { | ||
310 | - return v, nil | ||
311 | - } | ||
312 | - return nil, errors.New("not exist section") | ||
313 | -} | ||
314 | - | ||
315 | -// SaveConfigFile save the config into file. | ||
316 | -// | ||
317 | -// BUG(env): The environment variable config item will be saved with real value in SaveConfigFile Function. | ||
318 | -func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) { | ||
319 | - // Write configuration file by filename. | ||
320 | - f, err := os.Create(filename) | ||
321 | - if err != nil { | ||
322 | - return err | ||
323 | - } | ||
324 | - defer f.Close() | ||
325 | - | ||
326 | - // Get section or key comments. Fixed #1607 | ||
327 | - getCommentStr := func(section, key string) string { | ||
328 | - var ( | ||
329 | - comment string | ||
330 | - ok bool | ||
331 | - ) | ||
332 | - if len(key) == 0 { | ||
333 | - comment, ok = c.sectionComment[section] | ||
334 | - } else { | ||
335 | - comment, ok = c.keyComment[section+"."+key] | ||
336 | - } | ||
337 | - | ||
338 | - if ok { | ||
339 | - // Empty comment | ||
340 | - if len(comment) == 0 || len(strings.TrimSpace(comment)) == 0 { | ||
341 | - return string(bNumComment) | ||
342 | - } | ||
343 | - prefix := string(bNumComment) | ||
344 | - // Add the line head character "#" | ||
345 | - return prefix + strings.Replace(comment, lineBreak, lineBreak+prefix, -1) | ||
346 | - } | ||
347 | - return "" | ||
348 | - } | ||
349 | - | ||
350 | - buf := bytes.NewBuffer(nil) | ||
351 | - // Save default section at first place | ||
352 | - if dt, ok := c.data[defaultSection]; ok { | ||
353 | - for key, val := range dt { | ||
354 | - if key != " " { | ||
355 | - // Write key comments. | ||
356 | - if v := getCommentStr(defaultSection, key); len(v) > 0 { | ||
357 | - if _, err = buf.WriteString(v + lineBreak); err != nil { | ||
358 | - return err | ||
359 | - } | ||
360 | - } | ||
361 | - | ||
362 | - // Write key and value. | ||
363 | - if _, err = buf.WriteString(key + string(bEqual) + val + lineBreak); err != nil { | ||
364 | - return err | ||
365 | - } | ||
366 | - } | ||
367 | - } | ||
368 | - | ||
369 | - // Put a line between sections. | ||
370 | - if _, err = buf.WriteString(lineBreak); err != nil { | ||
371 | - return err | ||
372 | - } | ||
373 | - } | ||
374 | - // Save named sections | ||
375 | - for section, dt := range c.data { | ||
376 | - if section != defaultSection { | ||
377 | - // Write section comments. | ||
378 | - if v := getCommentStr(section, ""); len(v) > 0 { | ||
379 | - if _, err = buf.WriteString(v + lineBreak); err != nil { | ||
380 | - return err | ||
381 | - } | ||
382 | - } | ||
383 | - | ||
384 | - // Write section name. | ||
385 | - if _, err = buf.WriteString(string(sectionStart) + section + string(sectionEnd) + lineBreak); err != nil { | ||
386 | - return err | ||
387 | - } | ||
388 | - | ||
389 | - for key, val := range dt { | ||
390 | - if key != " " { | ||
391 | - // Write key comments. | ||
392 | - if v := getCommentStr(section, key); len(v) > 0 { | ||
393 | - if _, err = buf.WriteString(v + lineBreak); err != nil { | ||
394 | - return err | ||
395 | - } | ||
396 | - } | ||
397 | - | ||
398 | - // Write key and value. | ||
399 | - if _, err = buf.WriteString(key + string(bEqual) + val + lineBreak); err != nil { | ||
400 | - return err | ||
401 | - } | ||
402 | - } | ||
403 | - } | ||
404 | - | ||
405 | - // Put a line between sections. | ||
406 | - if _, err = buf.WriteString(lineBreak); err != nil { | ||
407 | - return err | ||
408 | - } | ||
409 | - } | ||
410 | - } | ||
411 | - _, err = buf.WriteTo(f) | ||
412 | - return err | ||
413 | -} | ||
414 | - | ||
415 | -// Set writes a new value for key. | ||
416 | -// if write to one section, the key need be "section::key". | ||
417 | -// if the section is not existed, it panics. | ||
418 | -func (c *IniConfigContainer) Set(key, value string) error { | ||
419 | - c.Lock() | ||
420 | - defer c.Unlock() | ||
421 | - if len(key) == 0 { | ||
422 | - return errors.New("key is empty") | ||
423 | - } | ||
424 | - | ||
425 | - var ( | ||
426 | - section, k string | ||
427 | - sectionKey = strings.Split(strings.ToLower(key), "::") | ||
428 | - ) | ||
429 | - | ||
430 | - if len(sectionKey) >= 2 { | ||
431 | - section = sectionKey[0] | ||
432 | - k = sectionKey[1] | ||
433 | - } else { | ||
434 | - section = defaultSection | ||
435 | - k = sectionKey[0] | ||
436 | - } | ||
437 | - | ||
438 | - if _, ok := c.data[section]; !ok { | ||
439 | - c.data[section] = make(map[string]string) | ||
440 | - } | ||
441 | - c.data[section][k] = value | ||
442 | - return nil | ||
443 | -} | ||
444 | - | ||
445 | -// DIY returns the raw value by a given key. | ||
446 | -func (c *IniConfigContainer) DIY(key string) (v interface{}, err error) { | ||
447 | - if v, ok := c.data[strings.ToLower(key)]; ok { | ||
448 | - return v, nil | ||
449 | - } | ||
450 | - return v, errors.New("key not find") | ||
451 | -} | ||
452 | - | ||
453 | -// section.key or key | ||
454 | -func (c *IniConfigContainer) getdata(key string) string { | ||
455 | - if len(key) == 0 { | ||
456 | - return "" | ||
457 | - } | ||
458 | - c.RLock() | ||
459 | - defer c.RUnlock() | ||
460 | - | ||
461 | - var ( | ||
462 | - section, k string | ||
463 | - sectionKey = strings.Split(strings.ToLower(key), "::") | ||
464 | - ) | ||
465 | - if len(sectionKey) >= 2 { | ||
466 | - section = sectionKey[0] | ||
467 | - k = sectionKey[1] | ||
468 | - } else { | ||
469 | - section = defaultSection | ||
470 | - k = sectionKey[0] | ||
471 | - } | ||
472 | - if v, ok := c.data[section]; ok { | ||
473 | - if vv, ok := v[k]; ok { | ||
474 | - return vv | ||
475 | - } | ||
476 | - } | ||
477 | - return "" | ||
478 | -} | ||
479 | - | ||
480 | -func init() { | ||
481 | - Register("ini", &IniConfig{}) | ||
482 | -} |
1 | -// Copyright 2014 beego Author. All Rights Reserved. | ||
2 | -// | ||
3 | -// Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | -// you may not use this file except in compliance with the License. | ||
5 | -// You may obtain a copy of the License at | ||
6 | -// | ||
7 | -// http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | -// | ||
9 | -// Unless required by applicable law or agreed to in writing, software | ||
10 | -// distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | -// See the License for the specific language governing permissions and | ||
13 | -// limitations under the License. | ||
14 | - | ||
15 | -package config | ||
16 | - | ||
17 | -import ( | ||
18 | - "encoding/json" | ||
19 | - "errors" | ||
20 | - "fmt" | ||
21 | - "io/ioutil" | ||
22 | - "os" | ||
23 | - "strings" | ||
24 | - "sync" | ||
25 | -) | ||
26 | - | ||
27 | -// JSONConfig is a json config parser and implements Config interface. | ||
28 | -type JSONConfig struct { | ||
29 | -} | ||
30 | - | ||
31 | -// Parse returns a ConfigContainer with parsed json config map. | ||
32 | -func (js *JSONConfig) Parse(filename string) (Configer, error) { | ||
33 | - file, err := os.Open(filename) | ||
34 | - if err != nil { | ||
35 | - return nil, err | ||
36 | - } | ||
37 | - defer file.Close() | ||
38 | - content, err := ioutil.ReadAll(file) | ||
39 | - if err != nil { | ||
40 | - return nil, err | ||
41 | - } | ||
42 | - | ||
43 | - return js.ParseData(content) | ||
44 | -} | ||
45 | - | ||
46 | -// ParseData returns a ConfigContainer with json string | ||
47 | -func (js *JSONConfig) ParseData(data []byte) (Configer, error) { | ||
48 | - x := &JSONConfigContainer{ | ||
49 | - data: make(map[string]interface{}), | ||
50 | - } | ||
51 | - err := json.Unmarshal(data, &x.data) | ||
52 | - if err != nil { | ||
53 | - var wrappingArray []interface{} | ||
54 | - err2 := json.Unmarshal(data, &wrappingArray) | ||
55 | - if err2 != nil { | ||
56 | - return nil, err | ||
57 | - } | ||
58 | - x.data["rootArray"] = wrappingArray | ||
59 | - } | ||
60 | - | ||
61 | - x.data = ExpandValueEnvForMap(x.data) | ||
62 | - | ||
63 | - return x, nil | ||
64 | -} | ||
65 | - | ||
66 | -// JSONConfigContainer A Config represents the json configuration. | ||
67 | -// Only when get value, support key as section:name type. | ||
68 | -type JSONConfigContainer struct { | ||
69 | - data map[string]interface{} | ||
70 | - sync.RWMutex | ||
71 | -} | ||
72 | - | ||
73 | -// Bool returns the boolean value for a given key. | ||
74 | -func (c *JSONConfigContainer) Bool(key string) (bool, error) { | ||
75 | - val := c.getData(key) | ||
76 | - if val != nil { | ||
77 | - return ParseBool(val) | ||
78 | - } | ||
79 | - return false, fmt.Errorf("not exist key: %q", key) | ||
80 | -} | ||
81 | - | ||
82 | -// DefaultBool return the bool value if has no error | ||
83 | -// otherwise return the defaultval | ||
84 | -func (c *JSONConfigContainer) DefaultBool(key string, defaultval bool) bool { | ||
85 | - if v, err := c.Bool(key); err == nil { | ||
86 | - return v | ||
87 | - } | ||
88 | - return defaultval | ||
89 | -} | ||
90 | - | ||
91 | -// Int returns the integer value for a given key. | ||
92 | -func (c *JSONConfigContainer) Int(key string) (int, error) { | ||
93 | - val := c.getData(key) | ||
94 | - if val != nil { | ||
95 | - if v, ok := val.(float64); ok { | ||
96 | - return int(v), nil | ||
97 | - } | ||
98 | - return 0, errors.New("not int value") | ||
99 | - } | ||
100 | - return 0, errors.New("not exist key:" + key) | ||
101 | -} | ||
102 | - | ||
103 | -// DefaultInt returns the integer value for a given key. | ||
104 | -// if err != nil return defaultval | ||
105 | -func (c *JSONConfigContainer) DefaultInt(key string, defaultval int) int { | ||
106 | - if v, err := c.Int(key); err == nil { | ||
107 | - return v | ||
108 | - } | ||
109 | - return defaultval | ||
110 | -} | ||
111 | - | ||
112 | -// Int64 returns the int64 value for a given key. | ||
113 | -func (c *JSONConfigContainer) Int64(key string) (int64, error) { | ||
114 | - val := c.getData(key) | ||
115 | - if val != nil { | ||
116 | - if v, ok := val.(float64); ok { | ||
117 | - return int64(v), nil | ||
118 | - } | ||
119 | - return 0, errors.New("not int64 value") | ||
120 | - } | ||
121 | - return 0, errors.New("not exist key:" + key) | ||
122 | -} | ||
123 | - | ||
124 | -// DefaultInt64 returns the int64 value for a given key. | ||
125 | -// if err != nil return defaultval | ||
126 | -func (c *JSONConfigContainer) DefaultInt64(key string, defaultval int64) int64 { | ||
127 | - if v, err := c.Int64(key); err == nil { | ||
128 | - return v | ||
129 | - } | ||
130 | - return defaultval | ||
131 | -} | ||
132 | - | ||
133 | -// Float returns the float value for a given key. | ||
134 | -func (c *JSONConfigContainer) Float(key string) (float64, error) { | ||
135 | - val := c.getData(key) | ||
136 | - if val != nil { | ||
137 | - if v, ok := val.(float64); ok { | ||
138 | - return v, nil | ||
139 | - } | ||
140 | - return 0.0, errors.New("not float64 value") | ||
141 | - } | ||
142 | - return 0.0, errors.New("not exist key:" + key) | ||
143 | -} | ||
144 | - | ||
145 | -// DefaultFloat returns the float64 value for a given key. | ||
146 | -// if err != nil return defaultval | ||
147 | -func (c *JSONConfigContainer) DefaultFloat(key string, defaultval float64) float64 { | ||
148 | - if v, err := c.Float(key); err == nil { | ||
149 | - return v | ||
150 | - } | ||
151 | - return defaultval | ||
152 | -} | ||
153 | - | ||
154 | -// String returns the string value for a given key. | ||
155 | -func (c *JSONConfigContainer) String(key string) string { | ||
156 | - val := c.getData(key) | ||
157 | - if val != nil { | ||
158 | - if v, ok := val.(string); ok { | ||
159 | - return v | ||
160 | - } | ||
161 | - } | ||
162 | - return "" | ||
163 | -} | ||
164 | - | ||
165 | -// DefaultString returns the string value for a given key. | ||
166 | -// if err != nil return defaultval | ||
167 | -func (c *JSONConfigContainer) DefaultString(key string, defaultval string) string { | ||
168 | - // TODO FIXME should not use "" to replace non existence | ||
169 | - if v := c.String(key); v != "" { | ||
170 | - return v | ||
171 | - } | ||
172 | - return defaultval | ||
173 | -} | ||
174 | - | ||
175 | -// Strings returns the []string value for a given key. | ||
176 | -func (c *JSONConfigContainer) Strings(key string) []string { | ||
177 | - stringVal := c.String(key) | ||
178 | - if stringVal == "" { | ||
179 | - return nil | ||
180 | - } | ||
181 | - return strings.Split(c.String(key), ";") | ||
182 | -} | ||
183 | - | ||
184 | -// DefaultStrings returns the []string value for a given key. | ||
185 | -// if err != nil return defaultval | ||
186 | -func (c *JSONConfigContainer) DefaultStrings(key string, defaultval []string) []string { | ||
187 | - if v := c.Strings(key); v != nil { | ||
188 | - return v | ||
189 | - } | ||
190 | - return defaultval | ||
191 | -} | ||
192 | - | ||
193 | -// GetSection returns map for the given section | ||
194 | -func (c *JSONConfigContainer) GetSection(section string) (map[string]string, error) { | ||
195 | - if v, ok := c.data[section]; ok { | ||
196 | - return v.(map[string]string), nil | ||
197 | - } | ||
198 | - return nil, errors.New("nonexist section " + section) | ||
199 | -} | ||
200 | - | ||
201 | -// SaveConfigFile save the config into file | ||
202 | -func (c *JSONConfigContainer) SaveConfigFile(filename string) (err error) { | ||
203 | - // Write configuration file by filename. | ||
204 | - f, err := os.Create(filename) | ||
205 | - if err != nil { | ||
206 | - return err | ||
207 | - } | ||
208 | - defer f.Close() | ||
209 | - b, err := json.MarshalIndent(c.data, "", " ") | ||
210 | - if err != nil { | ||
211 | - return err | ||
212 | - } | ||
213 | - _, err = f.Write(b) | ||
214 | - return err | ||
215 | -} | ||
216 | - | ||
217 | -// Set writes a new value for key. | ||
218 | -func (c *JSONConfigContainer) Set(key, val string) error { | ||
219 | - c.Lock() | ||
220 | - defer c.Unlock() | ||
221 | - c.data[key] = val | ||
222 | - return nil | ||
223 | -} | ||
224 | - | ||
225 | -// DIY returns the raw value by a given key. | ||
226 | -func (c *JSONConfigContainer) DIY(key string) (v interface{}, err error) { | ||
227 | - val := c.getData(key) | ||
228 | - if val != nil { | ||
229 | - return val, nil | ||
230 | - } | ||
231 | - return nil, errors.New("not exist key") | ||
232 | -} | ||
233 | - | ||
234 | -// section.key or key | ||
235 | -func (c *JSONConfigContainer) getData(key string) interface{} { | ||
236 | - if len(key) == 0 { | ||
237 | - return nil | ||
238 | - } | ||
239 | - | ||
240 | - c.RLock() | ||
241 | - defer c.RUnlock() | ||
242 | - | ||
243 | - sectionKeys := strings.Split(key, "::") | ||
244 | - if len(sectionKeys) >= 2 { | ||
245 | - curValue, ok := c.data[sectionKeys[0]] | ||
246 | - if !ok { | ||
247 | - return nil | ||
248 | - } | ||
249 | - for _, key := range sectionKeys[1:] { | ||
250 | - if v, ok := curValue.(map[string]interface{}); ok { | ||
251 | - if curValue, ok = v[key]; !ok { | ||
252 | - return nil | ||
253 | - } | ||
254 | - } | ||
255 | - } | ||
256 | - return curValue | ||
257 | - } | ||
258 | - if v, ok := c.data[key]; ok { | ||
259 | - return v | ||
260 | - } | ||
261 | - return nil | ||
262 | -} | ||
263 | - | ||
264 | -func init() { | ||
265 | - Register("json", &JSONConfig{}) | ||
266 | -} |
1 | -// Copyright 2015 beego Author. All Rights Reserved. | ||
2 | -// | ||
3 | -// Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | -// you may not use this file except in compliance with the License. | ||
5 | -// You may obtain a copy of the License at | ||
6 | -// | ||
7 | -// http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | -// | ||
9 | -// Unless required by applicable law or agreed to in writing, software | ||
10 | -// distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | -// See the License for the specific language governing permissions and | ||
13 | -// limitations under the License. | ||
14 | - | ||
15 | -package context | ||
16 | - | ||
17 | -import ( | ||
18 | - "bytes" | ||
19 | - "compress/flate" | ||
20 | - "compress/gzip" | ||
21 | - "compress/zlib" | ||
22 | - "io" | ||
23 | - "net/http" | ||
24 | - "os" | ||
25 | - "strconv" | ||
26 | - "strings" | ||
27 | - "sync" | ||
28 | -) | ||
29 | - | ||
30 | -var ( | ||
31 | - //Default size==20B same as nginx | ||
32 | - defaultGzipMinLength = 20 | ||
33 | - //Content will only be compressed if content length is either unknown or greater than gzipMinLength. | ||
34 | - gzipMinLength = defaultGzipMinLength | ||
35 | - //The compression level used for deflate compression. (0-9). | ||
36 | - gzipCompressLevel int | ||
37 | - //List of HTTP methods to compress. If not set, only GET requests are compressed. | ||
38 | - includedMethods map[string]bool | ||
39 | - getMethodOnly bool | ||
40 | -) | ||
41 | - | ||
42 | -// InitGzip init the gzipcompress | ||
43 | -func InitGzip(minLength, compressLevel int, methods []string) { | ||
44 | - if minLength >= 0 { | ||
45 | - gzipMinLength = minLength | ||
46 | - } | ||
47 | - gzipCompressLevel = compressLevel | ||
48 | - if gzipCompressLevel < flate.NoCompression || gzipCompressLevel > flate.BestCompression { | ||
49 | - gzipCompressLevel = flate.BestSpeed | ||
50 | - } | ||
51 | - getMethodOnly = (len(methods) == 0) || (len(methods) == 1 && strings.ToUpper(methods[0]) == "GET") | ||
52 | - includedMethods = make(map[string]bool, len(methods)) | ||
53 | - for _, v := range methods { | ||
54 | - includedMethods[strings.ToUpper(v)] = true | ||
55 | - } | ||
56 | -} | ||
57 | - | ||
58 | -type resetWriter interface { | ||
59 | - io.Writer | ||
60 | - Reset(w io.Writer) | ||
61 | -} | ||
62 | - | ||
63 | -type nopResetWriter struct { | ||
64 | - io.Writer | ||
65 | -} | ||
66 | - | ||
67 | -func (n nopResetWriter) Reset(w io.Writer) { | ||
68 | - //do nothing | ||
69 | -} | ||
70 | - | ||
71 | -type acceptEncoder struct { | ||
72 | - name string | ||
73 | - levelEncode func(int) resetWriter | ||
74 | - customCompressLevelPool *sync.Pool | ||
75 | - bestCompressionPool *sync.Pool | ||
76 | -} | ||
77 | - | ||
78 | -func (ac acceptEncoder) encode(wr io.Writer, level int) resetWriter { | ||
79 | - if ac.customCompressLevelPool == nil || ac.bestCompressionPool == nil { | ||
80 | - return nopResetWriter{wr} | ||
81 | - } | ||
82 | - var rwr resetWriter | ||
83 | - switch level { | ||
84 | - case flate.BestSpeed: | ||
85 | - rwr = ac.customCompressLevelPool.Get().(resetWriter) | ||
86 | - case flate.BestCompression: | ||
87 | - rwr = ac.bestCompressionPool.Get().(resetWriter) | ||
88 | - default: | ||
89 | - rwr = ac.levelEncode(level) | ||
90 | - } | ||
91 | - rwr.Reset(wr) | ||
92 | - return rwr | ||
93 | -} | ||
94 | - | ||
95 | -func (ac acceptEncoder) put(wr resetWriter, level int) { | ||
96 | - if ac.customCompressLevelPool == nil || ac.bestCompressionPool == nil { | ||
97 | - return | ||
98 | - } | ||
99 | - wr.Reset(nil) | ||
100 | - | ||
101 | - //notice | ||
102 | - //compressionLevel==BestCompression DOES NOT MATTER | ||
103 | - //sync.Pool will not memory leak | ||
104 | - | ||
105 | - switch level { | ||
106 | - case gzipCompressLevel: | ||
107 | - ac.customCompressLevelPool.Put(wr) | ||
108 | - case flate.BestCompression: | ||
109 | - ac.bestCompressionPool.Put(wr) | ||
110 | - } | ||
111 | -} | ||
112 | - | ||
113 | -var ( | ||
114 | - noneCompressEncoder = acceptEncoder{"", nil, nil, nil} | ||
115 | - gzipCompressEncoder = acceptEncoder{ | ||
116 | - name: "gzip", | ||
117 | - levelEncode: func(level int) resetWriter { wr, _ := gzip.NewWriterLevel(nil, level); return wr }, | ||
118 | - customCompressLevelPool: &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, gzipCompressLevel); return wr }}, | ||
119 | - bestCompressionPool: &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestCompression); return wr }}, | ||
120 | - } | ||
121 | - | ||
122 | - //according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed | ||
123 | - //deflate | ||
124 | - //The "zlib" format defined in RFC 1950 [31] in combination with | ||
125 | - //the "deflate" compression mechanism described in RFC 1951 [29]. | ||
126 | - deflateCompressEncoder = acceptEncoder{ | ||
127 | - name: "deflate", | ||
128 | - levelEncode: func(level int) resetWriter { wr, _ := zlib.NewWriterLevel(nil, level); return wr }, | ||
129 | - customCompressLevelPool: &sync.Pool{New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, gzipCompressLevel); return wr }}, | ||
130 | - bestCompressionPool: &sync.Pool{New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestCompression); return wr }}, | ||
131 | - } | ||
132 | -) | ||
133 | - | ||
134 | -var ( | ||
135 | - encoderMap = map[string]acceptEncoder{ // all the other compress methods will ignore | ||
136 | - "gzip": gzipCompressEncoder, | ||
137 | - "deflate": deflateCompressEncoder, | ||
138 | - "*": gzipCompressEncoder, // * means any compress will accept,we prefer gzip | ||
139 | - "identity": noneCompressEncoder, // identity means none-compress | ||
140 | - } | ||
141 | -) | ||
142 | - | ||
143 | -// WriteFile reads from file and writes to writer by the specific encoding(gzip/deflate) | ||
144 | -func WriteFile(encoding string, writer io.Writer, file *os.File) (bool, string, error) { | ||
145 | - return writeLevel(encoding, writer, file, flate.BestCompression) | ||
146 | -} | ||
147 | - | ||
148 | -// WriteBody reads writes content to writer by the specific encoding(gzip/deflate) | ||
149 | -func WriteBody(encoding string, writer io.Writer, content []byte) (bool, string, error) { | ||
150 | - if encoding == "" || len(content) < gzipMinLength { | ||
151 | - _, err := writer.Write(content) | ||
152 | - return false, "", err | ||
153 | - } | ||
154 | - return writeLevel(encoding, writer, bytes.NewReader(content), gzipCompressLevel) | ||
155 | -} | ||
156 | - | ||
157 | -// writeLevel reads from reader,writes to writer by specific encoding and compress level | ||
158 | -// the compress level is defined by deflate package | ||
159 | -func writeLevel(encoding string, writer io.Writer, reader io.Reader, level int) (bool, string, error) { | ||
160 | - var outputWriter resetWriter | ||
161 | - var err error | ||
162 | - var ce = noneCompressEncoder | ||
163 | - | ||
164 | - if cf, ok := encoderMap[encoding]; ok { | ||
165 | - ce = cf | ||
166 | - } | ||
167 | - encoding = ce.name | ||
168 | - outputWriter = ce.encode(writer, level) | ||
169 | - defer ce.put(outputWriter, level) | ||
170 | - | ||
171 | - _, err = io.Copy(outputWriter, reader) | ||
172 | - if err != nil { | ||
173 | - return false, "", err | ||
174 | - } | ||
175 | - | ||
176 | - switch outputWriter.(type) { | ||
177 | - case io.WriteCloser: | ||
178 | - outputWriter.(io.WriteCloser).Close() | ||
179 | - } | ||
180 | - return encoding != "", encoding, nil | ||
181 | -} | ||
182 | - | ||
183 | -// ParseEncoding will extract the right encoding for response | ||
184 | -// the Accept-Encoding's sec is here: | ||
185 | -// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3 | ||
186 | -func ParseEncoding(r *http.Request) string { | ||
187 | - if r == nil { | ||
188 | - return "" | ||
189 | - } | ||
190 | - if (getMethodOnly && r.Method == "GET") || includedMethods[r.Method] { | ||
191 | - return parseEncoding(r) | ||
192 | - } | ||
193 | - return "" | ||
194 | -} | ||
195 | - | ||
196 | -type q struct { | ||
197 | - name string | ||
198 | - value float64 | ||
199 | -} | ||
200 | - | ||
201 | -func parseEncoding(r *http.Request) string { | ||
202 | - acceptEncoding := r.Header.Get("Accept-Encoding") | ||
203 | - if acceptEncoding == "" { | ||
204 | - return "" | ||
205 | - } | ||
206 | - var lastQ q | ||
207 | - for _, v := range strings.Split(acceptEncoding, ",") { | ||
208 | - v = strings.TrimSpace(v) | ||
209 | - if v == "" { | ||
210 | - continue | ||
211 | - } | ||
212 | - vs := strings.Split(v, ";") | ||
213 | - var cf acceptEncoder | ||
214 | - var ok bool | ||
215 | - if cf, ok = encoderMap[vs[0]]; !ok { | ||
216 | - continue | ||
217 | - } | ||
218 | - if len(vs) == 1 { | ||
219 | - return cf.name | ||
220 | - } | ||
221 | - if len(vs) == 2 { | ||
222 | - f, _ := strconv.ParseFloat(strings.Replace(vs[1], "q=", "", -1), 64) | ||
223 | - if f == 0 { | ||
224 | - continue | ||
225 | - } | ||
226 | - if f > lastQ.value { | ||
227 | - lastQ = q{cf.name, f} | ||
228 | - } | ||
229 | - } | ||
230 | - } | ||
231 | - return lastQ.name | ||
232 | -} |
1 | -// Copyright 2014 beego Author. All Rights Reserved. | ||
2 | -// | ||
3 | -// Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | -// you may not use this file except in compliance with the License. | ||
5 | -// You may obtain a copy of the License at | ||
6 | -// | ||
7 | -// http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | -// | ||
9 | -// Unless required by applicable law or agreed to in writing, software | ||
10 | -// distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | -// See the License for the specific language governing permissions and | ||
13 | -// limitations under the License. | ||
14 | - | ||
15 | -// Package context provide the context utils | ||
16 | -// Usage: | ||
17 | -// | ||
18 | -// import "github.com/astaxie/beego/context" | ||
19 | -// | ||
20 | -// ctx := context.Context{Request:req,ResponseWriter:rw} | ||
21 | -// | ||
22 | -// more docs http://beego.me/docs/module/context.md | ||
23 | -package context | ||
24 | - | ||
25 | -import ( | ||
26 | - "bufio" | ||
27 | - "crypto/hmac" | ||
28 | - "crypto/sha1" | ||
29 | - "encoding/base64" | ||
30 | - "errors" | ||
31 | - "fmt" | ||
32 | - "net" | ||
33 | - "net/http" | ||
34 | - "strconv" | ||
35 | - "strings" | ||
36 | - "time" | ||
37 | - | ||
38 | - "github.com/astaxie/beego/utils" | ||
39 | -) | ||
40 | - | ||
41 | -// NewContext return the Context with Input and Output | ||
42 | -func NewContext() *Context { | ||
43 | - return &Context{ | ||
44 | - Input: NewInput(), | ||
45 | - Output: NewOutput(), | ||
46 | - } | ||
47 | -} | ||
48 | - | ||
49 | -// Context Http request context struct including BeegoInput, BeegoOutput, http.Request and http.ResponseWriter. | ||
50 | -// BeegoInput and BeegoOutput provides some api to operate request and response more easily. | ||
51 | -type Context struct { | ||
52 | - Input *BeegoInput | ||
53 | - Output *BeegoOutput | ||
54 | - Request *http.Request | ||
55 | - ResponseWriter *Response | ||
56 | - _xsrfToken string | ||
57 | -} | ||
58 | - | ||
59 | -// Reset init Context, BeegoInput and BeegoOutput | ||
60 | -func (ctx *Context) Reset(rw http.ResponseWriter, r *http.Request) { | ||
61 | - ctx.Request = r | ||
62 | - if ctx.ResponseWriter == nil { | ||
63 | - ctx.ResponseWriter = &Response{} | ||
64 | - } | ||
65 | - ctx.ResponseWriter.reset(rw) | ||
66 | - ctx.Input.Reset(ctx) | ||
67 | - ctx.Output.Reset(ctx) | ||
68 | - ctx._xsrfToken = "" | ||
69 | -} | ||
70 | - | ||
71 | -// Redirect does redirection to localurl with http header status code. | ||
72 | -func (ctx *Context) Redirect(status int, localurl string) { | ||
73 | - http.Redirect(ctx.ResponseWriter, ctx.Request, localurl, status) | ||
74 | -} | ||
75 | - | ||
76 | -// Abort stops this request. | ||
77 | -// if beego.ErrorMaps exists, panic body. | ||
78 | -func (ctx *Context) Abort(status int, body string) { | ||
79 | - ctx.Output.SetStatus(status) | ||
80 | - panic(body) | ||
81 | -} | ||
82 | - | ||
83 | -// WriteString Write string to response body. | ||
84 | -// it sends response body. | ||
85 | -func (ctx *Context) WriteString(content string) { | ||
86 | - ctx.ResponseWriter.Write([]byte(content)) | ||
87 | -} | ||
88 | - | ||
89 | -// GetCookie Get cookie from request by a given key. | ||
90 | -// It's alias of BeegoInput.Cookie. | ||
91 | -func (ctx *Context) GetCookie(key string) string { | ||
92 | - return ctx.Input.Cookie(key) | ||
93 | -} | ||
94 | - | ||
95 | -// SetCookie Set cookie for response. | ||
96 | -// It's alias of BeegoOutput.Cookie. | ||
97 | -func (ctx *Context) SetCookie(name string, value string, others ...interface{}) { | ||
98 | - ctx.Output.Cookie(name, value, others...) | ||
99 | -} | ||
100 | - | ||
101 | -// GetSecureCookie Get secure cookie from request by a given key. | ||
102 | -func (ctx *Context) GetSecureCookie(Secret, key string) (string, bool) { | ||
103 | - val := ctx.Input.Cookie(key) | ||
104 | - if val == "" { | ||
105 | - return "", false | ||
106 | - } | ||
107 | - | ||
108 | - parts := strings.SplitN(val, "|", 3) | ||
109 | - | ||
110 | - if len(parts) != 3 { | ||
111 | - return "", false | ||
112 | - } | ||
113 | - | ||
114 | - vs := parts[0] | ||
115 | - timestamp := parts[1] | ||
116 | - sig := parts[2] | ||
117 | - | ||
118 | - h := hmac.New(sha1.New, []byte(Secret)) | ||
119 | - fmt.Fprintf(h, "%s%s", vs, timestamp) | ||
120 | - | ||
121 | - if fmt.Sprintf("%02x", h.Sum(nil)) != sig { | ||
122 | - return "", false | ||
123 | - } | ||
124 | - res, _ := base64.URLEncoding.DecodeString(vs) | ||
125 | - return string(res), true | ||
126 | -} | ||
127 | - | ||
128 | -// SetSecureCookie Set Secure cookie for response. | ||
129 | -func (ctx *Context) SetSecureCookie(Secret, name, value string, others ...interface{}) { | ||
130 | - vs := base64.URLEncoding.EncodeToString([]byte(value)) | ||
131 | - timestamp := strconv.FormatInt(time.Now().UnixNano(), 10) | ||
132 | - h := hmac.New(sha1.New, []byte(Secret)) | ||
133 | - fmt.Fprintf(h, "%s%s", vs, timestamp) | ||
134 | - sig := fmt.Sprintf("%02x", h.Sum(nil)) | ||
135 | - cookie := strings.Join([]string{vs, timestamp, sig}, "|") | ||
136 | - ctx.Output.Cookie(name, cookie, others...) | ||
137 | -} | ||
138 | - | ||
139 | -// XSRFToken creates a xsrf token string and returns. | ||
140 | -func (ctx *Context) XSRFToken(key string, expire int64) string { | ||
141 | - if ctx._xsrfToken == "" { | ||
142 | - token, ok := ctx.GetSecureCookie(key, "_xsrf") | ||
143 | - if !ok { | ||
144 | - token = string(utils.RandomCreateBytes(32)) | ||
145 | - ctx.SetSecureCookie(key, "_xsrf", token, expire) | ||
146 | - } | ||
147 | - ctx._xsrfToken = token | ||
148 | - } | ||
149 | - return ctx._xsrfToken | ||
150 | -} | ||
151 | - | ||
152 | -// CheckXSRFCookie checks xsrf token in this request is valid or not. | ||
153 | -// the token can provided in request header "X-Xsrftoken" and "X-CsrfToken" | ||
154 | -// or in form field value named as "_xsrf". | ||
155 | -func (ctx *Context) CheckXSRFCookie() bool { | ||
156 | - token := ctx.Input.Query("_xsrf") | ||
157 | - if token == "" { | ||
158 | - token = ctx.Request.Header.Get("X-Xsrftoken") | ||
159 | - } | ||
160 | - if token == "" { | ||
161 | - token = ctx.Request.Header.Get("X-Csrftoken") | ||
162 | - } | ||
163 | - if token == "" { | ||
164 | - ctx.Abort(403, "'_xsrf' argument missing from POST") | ||
165 | - return false | ||
166 | - } | ||
167 | - if ctx._xsrfToken != token { | ||
168 | - ctx.Abort(403, "XSRF cookie does not match POST argument") | ||
169 | - return false | ||
170 | - } | ||
171 | - return true | ||
172 | -} | ||
173 | - | ||
174 | -// RenderMethodResult renders the return value of a controller method to the output | ||
175 | -func (ctx *Context) RenderMethodResult(result interface{}) { | ||
176 | - if result != nil { | ||
177 | - renderer, ok := result.(Renderer) | ||
178 | - if !ok { | ||
179 | - err, ok := result.(error) | ||
180 | - if ok { | ||
181 | - renderer = errorRenderer(err) | ||
182 | - } else { | ||
183 | - renderer = jsonRenderer(result) | ||
184 | - } | ||
185 | - } | ||
186 | - renderer.Render(ctx) | ||
187 | - } | ||
188 | -} | ||
189 | - | ||
190 | -//Response is a wrapper for the http.ResponseWriter | ||
191 | -//started set to true if response was written to then don't execute other handler | ||
192 | -type Response struct { | ||
193 | - http.ResponseWriter | ||
194 | - Started bool | ||
195 | - Status int | ||
196 | -} | ||
197 | - | ||
198 | -func (r *Response) reset(rw http.ResponseWriter) { | ||
199 | - r.ResponseWriter = rw | ||
200 | - r.Status = 0 | ||
201 | - r.Started = false | ||
202 | -} | ||
203 | - | ||
204 | -// Write writes the data to the connection as part of an HTTP reply, | ||
205 | -// and sets `started` to true. | ||
206 | -// started means the response has sent out. | ||
207 | -func (r *Response) Write(p []byte) (int, error) { | ||
208 | - r.Started = true | ||
209 | - return r.ResponseWriter.Write(p) | ||
210 | -} | ||
211 | - | ||
212 | -// WriteHeader sends an HTTP response header with status code, | ||
213 | -// and sets `started` to true. | ||
214 | -func (r *Response) WriteHeader(code int) { | ||
215 | - if r.Status > 0 { | ||
216 | - //prevent multiple response.WriteHeader calls | ||
217 | - return | ||
218 | - } | ||
219 | - r.Status = code | ||
220 | - r.Started = true | ||
221 | - r.ResponseWriter.WriteHeader(code) | ||
222 | -} | ||
223 | - | ||
224 | -// Hijack hijacker for http | ||
225 | -func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) { | ||
226 | - hj, ok := r.ResponseWriter.(http.Hijacker) | ||
227 | - if !ok { | ||
228 | - return nil, nil, errors.New("webserver doesn't support hijacking") | ||
229 | - } | ||
230 | - return hj.Hijack() | ||
231 | -} | ||
232 | - | ||
233 | -// Flush http.Flusher | ||
234 | -func (r *Response) Flush() { | ||
235 | - if f, ok := r.ResponseWriter.(http.Flusher); ok { | ||
236 | - f.Flush() | ||
237 | - } | ||
238 | -} | ||
239 | - | ||
240 | -// CloseNotify http.CloseNotifier | ||
241 | -func (r *Response) CloseNotify() <-chan bool { | ||
242 | - if cn, ok := r.ResponseWriter.(http.CloseNotifier); ok { | ||
243 | - return cn.CloseNotify() | ||
244 | - } | ||
245 | - return nil | ||
246 | -} |
1 | -// Copyright 2014 beego Author. All Rights Reserved. | ||
2 | -// | ||
3 | -// Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | -// you may not use this file except in compliance with the License. | ||
5 | -// You may obtain a copy of the License at | ||
6 | -// | ||
7 | -// http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | -// | ||
9 | -// Unless required by applicable law or agreed to in writing, software | ||
10 | -// distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | -// See the License for the specific language governing permissions and | ||
13 | -// limitations under the License. | ||
14 | - | ||
15 | -package context | ||
16 | - | ||
17 | -import ( | ||
18 | - "bytes" | ||
19 | - "compress/gzip" | ||
20 | - "errors" | ||
21 | - "io" | ||
22 | - "io/ioutil" | ||
23 | - "net" | ||
24 | - "net/http" | ||
25 | - "net/url" | ||
26 | - "reflect" | ||
27 | - "regexp" | ||
28 | - "strconv" | ||
29 | - "strings" | ||
30 | - | ||
31 | - "github.com/astaxie/beego/session" | ||
32 | -) | ||
33 | - | ||
34 | -// Regexes for checking the accept headers | ||
35 | -// TODO make sure these are correct | ||
36 | -var ( | ||
37 | - acceptsHTMLRegex = regexp.MustCompile(`(text/html|application/xhtml\+xml)(?:,|$)`) | ||
38 | - acceptsXMLRegex = regexp.MustCompile(`(application/xml|text/xml)(?:,|$)`) | ||
39 | - acceptsJSONRegex = regexp.MustCompile(`(application/json)(?:,|$)`) | ||
40 | - acceptsYAMLRegex = regexp.MustCompile(`(application/x-yaml)(?:,|$)`) | ||
41 | - maxParam = 50 | ||
42 | -) | ||
43 | - | ||
44 | -// BeegoInput operates the http request header, data, cookie and body. | ||
45 | -// it also contains router params and current session. | ||
46 | -type BeegoInput struct { | ||
47 | - Context *Context | ||
48 | - CruSession session.Store | ||
49 | - pnames []string | ||
50 | - pvalues []string | ||
51 | - data map[interface{}]interface{} // store some values in this context when calling context in filter or controller. | ||
52 | - RequestBody []byte | ||
53 | - RunMethod string | ||
54 | - RunController reflect.Type | ||
55 | -} | ||
56 | - | ||
57 | -// NewInput return BeegoInput generated by Context. | ||
58 | -func NewInput() *BeegoInput { | ||
59 | - return &BeegoInput{ | ||
60 | - pnames: make([]string, 0, maxParam), | ||
61 | - pvalues: make([]string, 0, maxParam), | ||
62 | - data: make(map[interface{}]interface{}), | ||
63 | - } | ||
64 | -} | ||
65 | - | ||
66 | -// Reset init the BeegoInput | ||
67 | -func (input *BeegoInput) Reset(ctx *Context) { | ||
68 | - input.Context = ctx | ||
69 | - input.CruSession = nil | ||
70 | - input.pnames = input.pnames[:0] | ||
71 | - input.pvalues = input.pvalues[:0] | ||
72 | - input.data = nil | ||
73 | - input.RequestBody = []byte{} | ||
74 | -} | ||
75 | - | ||
76 | -// Protocol returns request protocol name, such as HTTP/1.1 . | ||
77 | -func (input *BeegoInput) Protocol() string { | ||
78 | - return input.Context.Request.Proto | ||
79 | -} | ||
80 | - | ||
81 | -// URI returns full request url with query string, fragment. | ||
82 | -func (input *BeegoInput) URI() string { | ||
83 | - return input.Context.Request.RequestURI | ||
84 | -} | ||
85 | - | ||
86 | -// URL returns request url path (without query string, fragment). | ||
87 | -func (input *BeegoInput) URL() string { | ||
88 | - return input.Context.Request.URL.Path | ||
89 | -} | ||
90 | - | ||
91 | -// Site returns base site url as scheme://domain type. | ||
92 | -func (input *BeegoInput) Site() string { | ||
93 | - return input.Scheme() + "://" + input.Domain() | ||
94 | -} | ||
95 | - | ||
96 | -// Scheme returns request scheme as "http" or "https". | ||
97 | -func (input *BeegoInput) Scheme() string { | ||
98 | - if scheme := input.Header("X-Forwarded-Proto"); scheme != "" { | ||
99 | - return scheme | ||
100 | - } | ||
101 | - if input.Context.Request.URL.Scheme != "" { | ||
102 | - return input.Context.Request.URL.Scheme | ||
103 | - } | ||
104 | - if input.Context.Request.TLS == nil { | ||
105 | - return "http" | ||
106 | - } | ||
107 | - return "https" | ||
108 | -} | ||
109 | - | ||
110 | -// Domain returns host name. | ||
111 | -// Alias of Host method. | ||
112 | -func (input *BeegoInput) Domain() string { | ||
113 | - return input.Host() | ||
114 | -} | ||
115 | - | ||
116 | -// Host returns host name. | ||
117 | -// if no host info in request, return localhost. | ||
118 | -func (input *BeegoInput) Host() string { | ||
119 | - if input.Context.Request.Host != "" { | ||
120 | - if hostPart, _, err := net.SplitHostPort(input.Context.Request.Host); err == nil { | ||
121 | - return hostPart | ||
122 | - } | ||
123 | - return input.Context.Request.Host | ||
124 | - } | ||
125 | - return "localhost" | ||
126 | -} | ||
127 | - | ||
128 | -// Method returns http request method. | ||
129 | -func (input *BeegoInput) Method() string { | ||
130 | - return input.Context.Request.Method | ||
131 | -} | ||
132 | - | ||
133 | -// Is returns boolean of this request is on given method, such as Is("POST"). | ||
134 | -func (input *BeegoInput) Is(method string) bool { | ||
135 | - return input.Method() == method | ||
136 | -} | ||
137 | - | ||
138 | -// IsGet Is this a GET method request? | ||
139 | -func (input *BeegoInput) IsGet() bool { | ||
140 | - return input.Is("GET") | ||
141 | -} | ||
142 | - | ||
143 | -// IsPost Is this a POST method request? | ||
144 | -func (input *BeegoInput) IsPost() bool { | ||
145 | - return input.Is("POST") | ||
146 | -} | ||
147 | - | ||
148 | -// IsHead Is this a Head method request? | ||
149 | -func (input *BeegoInput) IsHead() bool { | ||
150 | - return input.Is("HEAD") | ||
151 | -} | ||
152 | - | ||
153 | -// IsOptions Is this a OPTIONS method request? | ||
154 | -func (input *BeegoInput) IsOptions() bool { | ||
155 | - return input.Is("OPTIONS") | ||
156 | -} | ||
157 | - | ||
158 | -// IsPut Is this a PUT method request? | ||
159 | -func (input *BeegoInput) IsPut() bool { | ||
160 | - return input.Is("PUT") | ||
161 | -} | ||
162 | - | ||
163 | -// IsDelete Is this a DELETE method request? | ||
164 | -func (input *BeegoInput) IsDelete() bool { | ||
165 | - return input.Is("DELETE") | ||
166 | -} | ||
167 | - | ||
168 | -// IsPatch Is this a PATCH method request? | ||
169 | -func (input *BeegoInput) IsPatch() bool { | ||
170 | - return input.Is("PATCH") | ||
171 | -} | ||
172 | - | ||
173 | -// IsAjax returns boolean of this request is generated by ajax. | ||
174 | -func (input *BeegoInput) IsAjax() bool { | ||
175 | - return input.Header("X-Requested-With") == "XMLHttpRequest" | ||
176 | -} | ||
177 | - | ||
178 | -// IsSecure returns boolean of this request is in https. | ||
179 | -func (input *BeegoInput) IsSecure() bool { | ||
180 | - return input.Scheme() == "https" | ||
181 | -} | ||
182 | - | ||
183 | -// IsWebsocket returns boolean of this request is in webSocket. | ||
184 | -func (input *BeegoInput) IsWebsocket() bool { | ||
185 | - return input.Header("Upgrade") == "websocket" | ||
186 | -} | ||
187 | - | ||
188 | -// IsUpload returns boolean of whether file uploads in this request or not.. | ||
189 | -func (input *BeegoInput) IsUpload() bool { | ||
190 | - return strings.Contains(input.Header("Content-Type"), "multipart/form-data") | ||
191 | -} | ||
192 | - | ||
193 | -// AcceptsHTML Checks if request accepts html response | ||
194 | -func (input *BeegoInput) AcceptsHTML() bool { | ||
195 | - return acceptsHTMLRegex.MatchString(input.Header("Accept")) | ||
196 | -} | ||
197 | - | ||
198 | -// AcceptsXML Checks if request accepts xml response | ||
199 | -func (input *BeegoInput) AcceptsXML() bool { | ||
200 | - return acceptsXMLRegex.MatchString(input.Header("Accept")) | ||
201 | -} | ||
202 | - | ||
203 | -// AcceptsJSON Checks if request accepts json response | ||
204 | -func (input *BeegoInput) AcceptsJSON() bool { | ||
205 | - return acceptsJSONRegex.MatchString(input.Header("Accept")) | ||
206 | -} | ||
207 | -// AcceptsYAML Checks if request accepts json response | ||
208 | -func (input *BeegoInput) AcceptsYAML() bool { | ||
209 | - return acceptsYAMLRegex.MatchString(input.Header("Accept")) | ||
210 | -} | ||
211 | - | ||
212 | -// IP returns request client ip. | ||
213 | -// if in proxy, return first proxy id. | ||
214 | -// if error, return RemoteAddr. | ||
215 | -func (input *BeegoInput) IP() string { | ||
216 | - ips := input.Proxy() | ||
217 | - if len(ips) > 0 && ips[0] != "" { | ||
218 | - rip, _, err := net.SplitHostPort(ips[0]) | ||
219 | - if err != nil { | ||
220 | - rip = ips[0] | ||
221 | - } | ||
222 | - return rip | ||
223 | - } | ||
224 | - if ip, _, err := net.SplitHostPort(input.Context.Request.RemoteAddr); err == nil { | ||
225 | - return ip | ||
226 | - } | ||
227 | - return input.Context.Request.RemoteAddr | ||
228 | -} | ||
229 | - | ||
230 | -// Proxy returns proxy client ips slice. | ||
231 | -func (input *BeegoInput) Proxy() []string { | ||
232 | - if ips := input.Header("X-Forwarded-For"); ips != "" { | ||
233 | - return strings.Split(ips, ",") | ||
234 | - } | ||
235 | - return []string{} | ||
236 | -} | ||
237 | - | ||
238 | -// Referer returns http referer header. | ||
239 | -func (input *BeegoInput) Referer() string { | ||
240 | - return input.Header("Referer") | ||
241 | -} | ||
242 | - | ||
243 | -// Refer returns http referer header. | ||
244 | -func (input *BeegoInput) Refer() string { | ||
245 | - return input.Referer() | ||
246 | -} | ||
247 | - | ||
248 | -// SubDomains returns sub domain string. | ||
249 | -// if aa.bb.domain.com, returns aa.bb . | ||
250 | -func (input *BeegoInput) SubDomains() string { | ||
251 | - parts := strings.Split(input.Host(), ".") | ||
252 | - if len(parts) >= 3 { | ||
253 | - return strings.Join(parts[:len(parts)-2], ".") | ||
254 | - } | ||
255 | - return "" | ||
256 | -} | ||
257 | - | ||
258 | -// Port returns request client port. | ||
259 | -// when error or empty, return 80. | ||
260 | -func (input *BeegoInput) Port() int { | ||
261 | - if _, portPart, err := net.SplitHostPort(input.Context.Request.Host); err == nil { | ||
262 | - port, _ := strconv.Atoi(portPart) | ||
263 | - return port | ||
264 | - } | ||
265 | - return 80 | ||
266 | -} | ||
267 | - | ||
268 | -// UserAgent returns request client user agent string. | ||
269 | -func (input *BeegoInput) UserAgent() string { | ||
270 | - return input.Header("User-Agent") | ||
271 | -} | ||
272 | - | ||
273 | -// ParamsLen return the length of the params | ||
274 | -func (input *BeegoInput) ParamsLen() int { | ||
275 | - return len(input.pnames) | ||
276 | -} | ||
277 | - | ||
278 | -// Param returns router param by a given key. | ||
279 | -func (input *BeegoInput) Param(key string) string { | ||
280 | - for i, v := range input.pnames { | ||
281 | - if v == key && i <= len(input.pvalues) { | ||
282 | - return input.pvalues[i] | ||
283 | - } | ||
284 | - } | ||
285 | - return "" | ||
286 | -} | ||
287 | - | ||
288 | -// Params returns the map[key]value. | ||
289 | -func (input *BeegoInput) Params() map[string]string { | ||
290 | - m := make(map[string]string) | ||
291 | - for i, v := range input.pnames { | ||
292 | - if i <= len(input.pvalues) { | ||
293 | - m[v] = input.pvalues[i] | ||
294 | - } | ||
295 | - } | ||
296 | - return m | ||
297 | -} | ||
298 | - | ||
299 | -// SetParam will set the param with key and value | ||
300 | -func (input *BeegoInput) SetParam(key, val string) { | ||
301 | - // check if already exists | ||
302 | - for i, v := range input.pnames { | ||
303 | - if v == key && i <= len(input.pvalues) { | ||
304 | - input.pvalues[i] = val | ||
305 | - return | ||
306 | - } | ||
307 | - } | ||
308 | - input.pvalues = append(input.pvalues, val) | ||
309 | - input.pnames = append(input.pnames, key) | ||
310 | -} | ||
311 | - | ||
312 | -// ResetParams clears any of the input's Params | ||
313 | -// This function is used to clear parameters so they may be reset between filter | ||
314 | -// passes. | ||
315 | -func (input *BeegoInput) ResetParams() { | ||
316 | - input.pnames = input.pnames[:0] | ||
317 | - input.pvalues = input.pvalues[:0] | ||
318 | -} | ||
319 | - | ||
320 | -// Query returns input data item string by a given string. | ||
321 | -func (input *BeegoInput) Query(key string) string { | ||
322 | - if val := input.Param(key); val != "" { | ||
323 | - return val | ||
324 | - } | ||
325 | - if input.Context.Request.Form == nil { | ||
326 | - input.Context.Request.ParseForm() | ||
327 | - } | ||
328 | - return input.Context.Request.Form.Get(key) | ||
329 | -} | ||
330 | - | ||
331 | -// Header returns request header item string by a given string. | ||
332 | -// if non-existed, return empty string. | ||
333 | -func (input *BeegoInput) Header(key string) string { | ||
334 | - return input.Context.Request.Header.Get(key) | ||
335 | -} | ||
336 | - | ||
337 | -// Cookie returns request cookie item string by a given key. | ||
338 | -// if non-existed, return empty string. | ||
339 | -func (input *BeegoInput) Cookie(key string) string { | ||
340 | - ck, err := input.Context.Request.Cookie(key) | ||
341 | - if err != nil { | ||
342 | - return "" | ||
343 | - } | ||
344 | - return ck.Value | ||
345 | -} | ||
346 | - | ||
347 | -// Session returns current session item value by a given key. | ||
348 | -// if non-existed, return nil. | ||
349 | -func (input *BeegoInput) Session(key interface{}) interface{} { | ||
350 | - return input.CruSession.Get(key) | ||
351 | -} | ||
352 | - | ||
353 | -// CopyBody returns the raw request body data as bytes. | ||
354 | -func (input *BeegoInput) CopyBody(MaxMemory int64) []byte { | ||
355 | - if input.Context.Request.Body == nil { | ||
356 | - return []byte{} | ||
357 | - } | ||
358 | - | ||
359 | - var requestbody []byte | ||
360 | - safe := &io.LimitedReader{R: input.Context.Request.Body, N: MaxMemory} | ||
361 | - if input.Header("Content-Encoding") == "gzip" { | ||
362 | - reader, err := gzip.NewReader(safe) | ||
363 | - if err != nil { | ||
364 | - return nil | ||
365 | - } | ||
366 | - requestbody, _ = ioutil.ReadAll(reader) | ||
367 | - } else { | ||
368 | - requestbody, _ = ioutil.ReadAll(safe) | ||
369 | - } | ||
370 | - | ||
371 | - input.Context.Request.Body.Close() | ||
372 | - bf := bytes.NewBuffer(requestbody) | ||
373 | - input.Context.Request.Body = http.MaxBytesReader(input.Context.ResponseWriter, ioutil.NopCloser(bf), MaxMemory) | ||
374 | - input.RequestBody = requestbody | ||
375 | - return requestbody | ||
376 | -} | ||
377 | - | ||
378 | -// Data return the implicit data in the input | ||
379 | -func (input *BeegoInput) Data() map[interface{}]interface{} { | ||
380 | - if input.data == nil { | ||
381 | - input.data = make(map[interface{}]interface{}) | ||
382 | - } | ||
383 | - return input.data | ||
384 | -} | ||
385 | - | ||
386 | -// GetData returns the stored data in this context. | ||
387 | -func (input *BeegoInput) GetData(key interface{}) interface{} { | ||
388 | - if v, ok := input.data[key]; ok { | ||
389 | - return v | ||
390 | - } | ||
391 | - return nil | ||
392 | -} | ||
393 | - | ||
394 | -// SetData stores data with given key in this context. | ||
395 | -// This data are only available in this context. | ||
396 | -func (input *BeegoInput) SetData(key, val interface{}) { | ||
397 | - if input.data == nil { | ||
398 | - input.data = make(map[interface{}]interface{}) | ||
399 | - } | ||
400 | - input.data[key] = val | ||
401 | -} | ||
402 | - | ||
403 | -// ParseFormOrMulitForm parseForm or parseMultiForm based on Content-type | ||
404 | -func (input *BeegoInput) ParseFormOrMulitForm(maxMemory int64) error { | ||
405 | - // Parse the body depending on the content type. | ||
406 | - if strings.Contains(input.Header("Content-Type"), "multipart/form-data") { | ||
407 | - if err := input.Context.Request.ParseMultipartForm(maxMemory); err != nil { | ||
408 | - return errors.New("Error parsing request body:" + err.Error()) | ||
409 | - } | ||
410 | - } else if err := input.Context.Request.ParseForm(); err != nil { | ||
411 | - return errors.New("Error parsing request body:" + err.Error()) | ||
412 | - } | ||
413 | - return nil | ||
414 | -} | ||
415 | - | ||
416 | -// Bind data from request.Form[key] to dest | ||
417 | -// like /?id=123&isok=true&ft=1.2&ol[0]=1&ol[1]=2&ul[]=str&ul[]=array&user.Name=astaxie | ||
418 | -// var id int beegoInput.Bind(&id, "id") id ==123 | ||
419 | -// var isok bool beegoInput.Bind(&isok, "isok") isok ==true | ||
420 | -// var ft float64 beegoInput.Bind(&ft, "ft") ft ==1.2 | ||
421 | -// ol := make([]int, 0, 2) beegoInput.Bind(&ol, "ol") ol ==[1 2] | ||
422 | -// ul := make([]string, 0, 2) beegoInput.Bind(&ul, "ul") ul ==[str array] | ||
423 | -// user struct{Name} beegoInput.Bind(&user, "user") user == {Name:"astaxie"} | ||
424 | -func (input *BeegoInput) Bind(dest interface{}, key string) error { | ||
425 | - value := reflect.ValueOf(dest) | ||
426 | - if value.Kind() != reflect.Ptr { | ||
427 | - return errors.New("beego: non-pointer passed to Bind: " + key) | ||
428 | - } | ||
429 | - value = value.Elem() | ||
430 | - if !value.CanSet() { | ||
431 | - return errors.New("beego: non-settable variable passed to Bind: " + key) | ||
432 | - } | ||
433 | - typ := value.Type() | ||
434 | - // Get real type if dest define with interface{}. | ||
435 | - // e.g var dest interface{} dest=1.0 | ||
436 | - if value.Kind() == reflect.Interface { | ||
437 | - typ = value.Elem().Type() | ||
438 | - } | ||
439 | - rv := input.bind(key, typ) | ||
440 | - if !rv.IsValid() { | ||
441 | - return errors.New("beego: reflect value is empty") | ||
442 | - } | ||
443 | - value.Set(rv) | ||
444 | - return nil | ||
445 | -} | ||
446 | - | ||
447 | -func (input *BeegoInput) bind(key string, typ reflect.Type) reflect.Value { | ||
448 | - if input.Context.Request.Form == nil { | ||
449 | - input.Context.Request.ParseForm() | ||
450 | - } | ||
451 | - rv := reflect.Zero(typ) | ||
452 | - switch typ.Kind() { | ||
453 | - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
454 | - val := input.Query(key) | ||
455 | - if len(val) == 0 { | ||
456 | - return rv | ||
457 | - } | ||
458 | - rv = input.bindInt(val, typ) | ||
459 | - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||
460 | - val := input.Query(key) | ||
461 | - if len(val) == 0 { | ||
462 | - return rv | ||
463 | - } | ||
464 | - rv = input.bindUint(val, typ) | ||
465 | - case reflect.Float32, reflect.Float64: | ||
466 | - val := input.Query(key) | ||
467 | - if len(val) == 0 { | ||
468 | - return rv | ||
469 | - } | ||
470 | - rv = input.bindFloat(val, typ) | ||
471 | - case reflect.String: | ||
472 | - val := input.Query(key) | ||
473 | - if len(val) == 0 { | ||
474 | - return rv | ||
475 | - } | ||
476 | - rv = input.bindString(val, typ) | ||
477 | - case reflect.Bool: | ||
478 | - val := input.Query(key) | ||
479 | - if len(val) == 0 { | ||
480 | - return rv | ||
481 | - } | ||
482 | - rv = input.bindBool(val, typ) | ||
483 | - case reflect.Slice: | ||
484 | - rv = input.bindSlice(&input.Context.Request.Form, key, typ) | ||
485 | - case reflect.Struct: | ||
486 | - rv = input.bindStruct(&input.Context.Request.Form, key, typ) | ||
487 | - case reflect.Ptr: | ||
488 | - rv = input.bindPoint(key, typ) | ||
489 | - case reflect.Map: | ||
490 | - rv = input.bindMap(&input.Context.Request.Form, key, typ) | ||
491 | - } | ||
492 | - return rv | ||
493 | -} | ||
494 | - | ||
495 | -func (input *BeegoInput) bindValue(val string, typ reflect.Type) reflect.Value { | ||
496 | - rv := reflect.Zero(typ) | ||
497 | - switch typ.Kind() { | ||
498 | - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
499 | - rv = input.bindInt(val, typ) | ||
500 | - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||
501 | - rv = input.bindUint(val, typ) | ||
502 | - case reflect.Float32, reflect.Float64: | ||
503 | - rv = input.bindFloat(val, typ) | ||
504 | - case reflect.String: | ||
505 | - rv = input.bindString(val, typ) | ||
506 | - case reflect.Bool: | ||
507 | - rv = input.bindBool(val, typ) | ||
508 | - case reflect.Slice: | ||
509 | - rv = input.bindSlice(&url.Values{"": {val}}, "", typ) | ||
510 | - case reflect.Struct: | ||
511 | - rv = input.bindStruct(&url.Values{"": {val}}, "", typ) | ||
512 | - case reflect.Ptr: | ||
513 | - rv = input.bindPoint(val, typ) | ||
514 | - case reflect.Map: | ||
515 | - rv = input.bindMap(&url.Values{"": {val}}, "", typ) | ||
516 | - } | ||
517 | - return rv | ||
518 | -} | ||
519 | - | ||
520 | -func (input *BeegoInput) bindInt(val string, typ reflect.Type) reflect.Value { | ||
521 | - intValue, err := strconv.ParseInt(val, 10, 64) | ||
522 | - if err != nil { | ||
523 | - return reflect.Zero(typ) | ||
524 | - } | ||
525 | - pValue := reflect.New(typ) | ||
526 | - pValue.Elem().SetInt(intValue) | ||
527 | - return pValue.Elem() | ||
528 | -} | ||
529 | - | ||
530 | -func (input *BeegoInput) bindUint(val string, typ reflect.Type) reflect.Value { | ||
531 | - uintValue, err := strconv.ParseUint(val, 10, 64) | ||
532 | - if err != nil { | ||
533 | - return reflect.Zero(typ) | ||
534 | - } | ||
535 | - pValue := reflect.New(typ) | ||
536 | - pValue.Elem().SetUint(uintValue) | ||
537 | - return pValue.Elem() | ||
538 | -} | ||
539 | - | ||
540 | -func (input *BeegoInput) bindFloat(val string, typ reflect.Type) reflect.Value { | ||
541 | - floatValue, err := strconv.ParseFloat(val, 64) | ||
542 | - if err != nil { | ||
543 | - return reflect.Zero(typ) | ||
544 | - } | ||
545 | - pValue := reflect.New(typ) | ||
546 | - pValue.Elem().SetFloat(floatValue) | ||
547 | - return pValue.Elem() | ||
548 | -} | ||
549 | - | ||
550 | -func (input *BeegoInput) bindString(val string, typ reflect.Type) reflect.Value { | ||
551 | - return reflect.ValueOf(val) | ||
552 | -} | ||
553 | - | ||
554 | -func (input *BeegoInput) bindBool(val string, typ reflect.Type) reflect.Value { | ||
555 | - val = strings.TrimSpace(strings.ToLower(val)) | ||
556 | - switch val { | ||
557 | - case "true", "on", "1": | ||
558 | - return reflect.ValueOf(true) | ||
559 | - } | ||
560 | - return reflect.ValueOf(false) | ||
561 | -} | ||
562 | - | ||
563 | -type sliceValue struct { | ||
564 | - index int // Index extracted from brackets. If -1, no index was provided. | ||
565 | - value reflect.Value // the bound value for this slice element. | ||
566 | -} | ||
567 | - | ||
568 | -func (input *BeegoInput) bindSlice(params *url.Values, key string, typ reflect.Type) reflect.Value { | ||
569 | - maxIndex := -1 | ||
570 | - numNoIndex := 0 | ||
571 | - sliceValues := []sliceValue{} | ||
572 | - for reqKey, vals := range *params { | ||
573 | - if !strings.HasPrefix(reqKey, key+"[") { | ||
574 | - continue | ||
575 | - } | ||
576 | - // Extract the index, and the index where a sub-key starts. (e.g. field[0].subkey) | ||
577 | - index := -1 | ||
578 | - leftBracket, rightBracket := len(key), strings.Index(reqKey[len(key):], "]")+len(key) | ||
579 | - if rightBracket > leftBracket+1 { | ||
580 | - index, _ = strconv.Atoi(reqKey[leftBracket+1 : rightBracket]) | ||
581 | - } | ||
582 | - subKeyIndex := rightBracket + 1 | ||
583 | - | ||
584 | - // Handle the indexed case. | ||
585 | - if index > -1 { | ||
586 | - if index > maxIndex { | ||
587 | - maxIndex = index | ||
588 | - } | ||
589 | - sliceValues = append(sliceValues, sliceValue{ | ||
590 | - index: index, | ||
591 | - value: input.bind(reqKey[:subKeyIndex], typ.Elem()), | ||
592 | - }) | ||
593 | - continue | ||
594 | - } | ||
595 | - | ||
596 | - // It's an un-indexed element. (e.g. element[]) | ||
597 | - numNoIndex += len(vals) | ||
598 | - for _, val := range vals { | ||
599 | - // Unindexed values can only be direct-bound. | ||
600 | - sliceValues = append(sliceValues, sliceValue{ | ||
601 | - index: -1, | ||
602 | - value: input.bindValue(val, typ.Elem()), | ||
603 | - }) | ||
604 | - } | ||
605 | - } | ||
606 | - resultArray := reflect.MakeSlice(typ, maxIndex+1, maxIndex+1+numNoIndex) | ||
607 | - for _, sv := range sliceValues { | ||
608 | - if sv.index != -1 { | ||
609 | - resultArray.Index(sv.index).Set(sv.value) | ||
610 | - } else { | ||
611 | - resultArray = reflect.Append(resultArray, sv.value) | ||
612 | - } | ||
613 | - } | ||
614 | - return resultArray | ||
615 | -} | ||
616 | - | ||
617 | -func (input *BeegoInput) bindStruct(params *url.Values, key string, typ reflect.Type) reflect.Value { | ||
618 | - result := reflect.New(typ).Elem() | ||
619 | - fieldValues := make(map[string]reflect.Value) | ||
620 | - for reqKey, val := range *params { | ||
621 | - var fieldName string | ||
622 | - if strings.HasPrefix(reqKey, key+".") { | ||
623 | - fieldName = reqKey[len(key)+1:] | ||
624 | - } else if strings.HasPrefix(reqKey, key+"[") && reqKey[len(reqKey)-1] == ']' { | ||
625 | - fieldName = reqKey[len(key)+1 : len(reqKey)-1] | ||
626 | - } else { | ||
627 | - continue | ||
628 | - } | ||
629 | - | ||
630 | - if _, ok := fieldValues[fieldName]; !ok { | ||
631 | - // Time to bind this field. Get it and make sure we can set it. | ||
632 | - fieldValue := result.FieldByName(fieldName) | ||
633 | - if !fieldValue.IsValid() { | ||
634 | - continue | ||
635 | - } | ||
636 | - if !fieldValue.CanSet() { | ||
637 | - continue | ||
638 | - } | ||
639 | - boundVal := input.bindValue(val[0], fieldValue.Type()) | ||
640 | - fieldValue.Set(boundVal) | ||
641 | - fieldValues[fieldName] = boundVal | ||
642 | - } | ||
643 | - } | ||
644 | - | ||
645 | - return result | ||
646 | -} | ||
647 | - | ||
648 | -func (input *BeegoInput) bindPoint(key string, typ reflect.Type) reflect.Value { | ||
649 | - return input.bind(key, typ.Elem()).Addr() | ||
650 | -} | ||
651 | - | ||
652 | -func (input *BeegoInput) bindMap(params *url.Values, key string, typ reflect.Type) reflect.Value { | ||
653 | - var ( | ||
654 | - result = reflect.MakeMap(typ) | ||
655 | - keyType = typ.Key() | ||
656 | - valueType = typ.Elem() | ||
657 | - ) | ||
658 | - for paramName, values := range *params { | ||
659 | - if !strings.HasPrefix(paramName, key+"[") || paramName[len(paramName)-1] != ']' { | ||
660 | - continue | ||
661 | - } | ||
662 | - | ||
663 | - key := paramName[len(key)+1 : len(paramName)-1] | ||
664 | - result.SetMapIndex(input.bindValue(key, keyType), input.bindValue(values[0], valueType)) | ||
665 | - } | ||
666 | - return result | ||
667 | -} |
1 | -// Copyright 2014 beego Author. All Rights Reserved. | ||
2 | -// | ||
3 | -// Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | -// you may not use this file except in compliance with the License. | ||
5 | -// You may obtain a copy of the License at | ||
6 | -// | ||
7 | -// http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | -// | ||
9 | -// Unless required by applicable law or agreed to in writing, software | ||
10 | -// distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | -// See the License for the specific language governing permissions and | ||
13 | -// limitations under the License. | ||
14 | - | ||
15 | -package context | ||
16 | - | ||
17 | -import ( | ||
18 | - "bytes" | ||
19 | - "encoding/json" | ||
20 | - "encoding/xml" | ||
21 | - "errors" | ||
22 | - "fmt" | ||
23 | - "html/template" | ||
24 | - "io" | ||
25 | - "mime" | ||
26 | - "net/http" | ||
27 | - "net/url" | ||
28 | - "os" | ||
29 | - "path/filepath" | ||
30 | - "strconv" | ||
31 | - "strings" | ||
32 | - "time" | ||
33 | - "gopkg.in/yaml.v2" | ||
34 | -) | ||
35 | - | ||
36 | -// BeegoOutput does work for sending response header. | ||
37 | -type BeegoOutput struct { | ||
38 | - Context *Context | ||
39 | - Status int | ||
40 | - EnableGzip bool | ||
41 | -} | ||
42 | - | ||
43 | -// NewOutput returns new BeegoOutput. | ||
44 | -// it contains nothing now. | ||
45 | -func NewOutput() *BeegoOutput { | ||
46 | - return &BeegoOutput{} | ||
47 | -} | ||
48 | - | ||
49 | -// Reset init BeegoOutput | ||
50 | -func (output *BeegoOutput) Reset(ctx *Context) { | ||
51 | - output.Context = ctx | ||
52 | - output.Status = 0 | ||
53 | -} | ||
54 | - | ||
55 | -// Header sets response header item string via given key. | ||
56 | -func (output *BeegoOutput) Header(key, val string) { | ||
57 | - output.Context.ResponseWriter.Header().Set(key, val) | ||
58 | -} | ||
59 | - | ||
60 | -// Body sets response body content. | ||
61 | -// if EnableGzip, compress content string. | ||
62 | -// it sends out response body directly. | ||
63 | -func (output *BeegoOutput) Body(content []byte) error { | ||
64 | - var encoding string | ||
65 | - var buf = &bytes.Buffer{} | ||
66 | - if output.EnableGzip { | ||
67 | - encoding = ParseEncoding(output.Context.Request) | ||
68 | - } | ||
69 | - if b, n, _ := WriteBody(encoding, buf, content); b { | ||
70 | - output.Header("Content-Encoding", n) | ||
71 | - output.Header("Content-Length", strconv.Itoa(buf.Len())) | ||
72 | - } else { | ||
73 | - output.Header("Content-Length", strconv.Itoa(len(content))) | ||
74 | - } | ||
75 | - // Write status code if it has been set manually | ||
76 | - // Set it to 0 afterwards to prevent "multiple response.WriteHeader calls" | ||
77 | - if output.Status != 0 { | ||
78 | - output.Context.ResponseWriter.WriteHeader(output.Status) | ||
79 | - output.Status = 0 | ||
80 | - } else { | ||
81 | - output.Context.ResponseWriter.Started = true | ||
82 | - } | ||
83 | - io.Copy(output.Context.ResponseWriter, buf) | ||
84 | - return nil | ||
85 | -} | ||
86 | - | ||
87 | -// Cookie sets cookie value via given key. | ||
88 | -// others are ordered as cookie's max age time, path,domain, secure and httponly. | ||
89 | -func (output *BeegoOutput) Cookie(name string, value string, others ...interface{}) { | ||
90 | - var b bytes.Buffer | ||
91 | - fmt.Fprintf(&b, "%s=%s", sanitizeName(name), sanitizeValue(value)) | ||
92 | - | ||
93 | - //fix cookie not work in IE | ||
94 | - if len(others) > 0 { | ||
95 | - var maxAge int64 | ||
96 | - | ||
97 | - switch v := others[0].(type) { | ||
98 | - case int: | ||
99 | - maxAge = int64(v) | ||
100 | - case int32: | ||
101 | - maxAge = int64(v) | ||
102 | - case int64: | ||
103 | - maxAge = v | ||
104 | - } | ||
105 | - | ||
106 | - switch { | ||
107 | - case maxAge > 0: | ||
108 | - fmt.Fprintf(&b, "; Expires=%s; Max-Age=%d", time.Now().Add(time.Duration(maxAge)*time.Second).UTC().Format(time.RFC1123), maxAge) | ||
109 | - case maxAge < 0: | ||
110 | - fmt.Fprintf(&b, "; Max-Age=0") | ||
111 | - } | ||
112 | - } | ||
113 | - | ||
114 | - // the settings below | ||
115 | - // Path, Domain, Secure, HttpOnly | ||
116 | - // can use nil skip set | ||
117 | - | ||
118 | - // default "/" | ||
119 | - if len(others) > 1 { | ||
120 | - if v, ok := others[1].(string); ok && len(v) > 0 { | ||
121 | - fmt.Fprintf(&b, "; Path=%s", sanitizeValue(v)) | ||
122 | - } | ||
123 | - } else { | ||
124 | - fmt.Fprintf(&b, "; Path=%s", "/") | ||
125 | - } | ||
126 | - | ||
127 | - // default empty | ||
128 | - if len(others) > 2 { | ||
129 | - if v, ok := others[2].(string); ok && len(v) > 0 { | ||
130 | - fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(v)) | ||
131 | - } | ||
132 | - } | ||
133 | - | ||
134 | - // default empty | ||
135 | - if len(others) > 3 { | ||
136 | - var secure bool | ||
137 | - switch v := others[3].(type) { | ||
138 | - case bool: | ||
139 | - secure = v | ||
140 | - default: | ||
141 | - if others[3] != nil { | ||
142 | - secure = true | ||
143 | - } | ||
144 | - } | ||
145 | - if secure { | ||
146 | - fmt.Fprintf(&b, "; Secure") | ||
147 | - } | ||
148 | - } | ||
149 | - | ||
150 | - // default false. for session cookie default true | ||
151 | - if len(others) > 4 { | ||
152 | - if v, ok := others[4].(bool); ok && v { | ||
153 | - fmt.Fprintf(&b, "; HttpOnly") | ||
154 | - } | ||
155 | - } | ||
156 | - | ||
157 | - output.Context.ResponseWriter.Header().Add("Set-Cookie", b.String()) | ||
158 | -} | ||
159 | - | ||
160 | -var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-") | ||
161 | - | ||
162 | -func sanitizeName(n string) string { | ||
163 | - return cookieNameSanitizer.Replace(n) | ||
164 | -} | ||
165 | - | ||
166 | -var cookieValueSanitizer = strings.NewReplacer("\n", " ", "\r", " ", ";", " ") | ||
167 | - | ||
168 | -func sanitizeValue(v string) string { | ||
169 | - return cookieValueSanitizer.Replace(v) | ||
170 | -} | ||
171 | - | ||
172 | -func jsonRenderer(value interface{}) Renderer { | ||
173 | - return rendererFunc(func(ctx *Context) { | ||
174 | - ctx.Output.JSON(value, false, false) | ||
175 | - }) | ||
176 | -} | ||
177 | - | ||
178 | -func errorRenderer(err error) Renderer { | ||
179 | - return rendererFunc(func(ctx *Context) { | ||
180 | - ctx.Output.SetStatus(500) | ||
181 | - ctx.Output.Body([]byte(err.Error())) | ||
182 | - }) | ||
183 | -} | ||
184 | - | ||
185 | -// JSON writes json to response body. | ||
186 | -// if encoding is true, it converts utf-8 to \u0000 type. | ||
187 | -func (output *BeegoOutput) JSON(data interface{}, hasIndent bool, encoding bool) error { | ||
188 | - output.Header("Content-Type", "application/json; charset=utf-8") | ||
189 | - var content []byte | ||
190 | - var err error | ||
191 | - if hasIndent { | ||
192 | - content, err = json.MarshalIndent(data, "", " ") | ||
193 | - } else { | ||
194 | - content, err = json.Marshal(data) | ||
195 | - } | ||
196 | - if err != nil { | ||
197 | - http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError) | ||
198 | - return err | ||
199 | - } | ||
200 | - if encoding { | ||
201 | - content = []byte(stringsToJSON(string(content))) | ||
202 | - } | ||
203 | - return output.Body(content) | ||
204 | -} | ||
205 | - | ||
206 | - | ||
207 | -// YAML writes yaml to response body. | ||
208 | -func (output *BeegoOutput) YAML(data interface{}) error { | ||
209 | - output.Header("Content-Type", "application/application/x-yaml; charset=utf-8") | ||
210 | - var content []byte | ||
211 | - var err error | ||
212 | - content, err = yaml.Marshal(data) | ||
213 | - if err != nil { | ||
214 | - http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError) | ||
215 | - return err | ||
216 | - } | ||
217 | - return output.Body(content) | ||
218 | -} | ||
219 | - | ||
220 | -// JSONP writes jsonp to response body. | ||
221 | -func (output *BeegoOutput) JSONP(data interface{}, hasIndent bool) error { | ||
222 | - output.Header("Content-Type", "application/javascript; charset=utf-8") | ||
223 | - var content []byte | ||
224 | - var err error | ||
225 | - if hasIndent { | ||
226 | - content, err = json.MarshalIndent(data, "", " ") | ||
227 | - } else { | ||
228 | - content, err = json.Marshal(data) | ||
229 | - } | ||
230 | - if err != nil { | ||
231 | - http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError) | ||
232 | - return err | ||
233 | - } | ||
234 | - callback := output.Context.Input.Query("callback") | ||
235 | - if callback == "" { | ||
236 | - return errors.New(`"callback" parameter required`) | ||
237 | - } | ||
238 | - callback = template.JSEscapeString(callback) | ||
239 | - callbackContent := bytes.NewBufferString(" if(window." + callback + ")" + callback) | ||
240 | - callbackContent.WriteString("(") | ||
241 | - callbackContent.Write(content) | ||
242 | - callbackContent.WriteString(");\r\n") | ||
243 | - return output.Body(callbackContent.Bytes()) | ||
244 | -} | ||
245 | - | ||
246 | -// XML writes xml string to response body. | ||
247 | -func (output *BeegoOutput) XML(data interface{}, hasIndent bool) error { | ||
248 | - output.Header("Content-Type", "application/xml; charset=utf-8") | ||
249 | - var content []byte | ||
250 | - var err error | ||
251 | - if hasIndent { | ||
252 | - content, err = xml.MarshalIndent(data, "", " ") | ||
253 | - } else { | ||
254 | - content, err = xml.Marshal(data) | ||
255 | - } | ||
256 | - if err != nil { | ||
257 | - http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError) | ||
258 | - return err | ||
259 | - } | ||
260 | - return output.Body(content) | ||
261 | -} | ||
262 | - | ||
263 | -// Download forces response for download file. | ||
264 | -// it prepares the download response header automatically. | ||
265 | -func (output *BeegoOutput) Download(file string, filename ...string) { | ||
266 | - // check get file error, file not found or other error. | ||
267 | - if _, err := os.Stat(file); err != nil { | ||
268 | - http.ServeFile(output.Context.ResponseWriter, output.Context.Request, file) | ||
269 | - return | ||
270 | - } | ||
271 | - | ||
272 | - var fName string | ||
273 | - if len(filename) > 0 && filename[0] != "" { | ||
274 | - fName = filename[0] | ||
275 | - } else { | ||
276 | - fName = filepath.Base(file) | ||
277 | - } | ||
278 | - output.Header("Content-Disposition", "attachment; filename="+url.PathEscape(fName)) | ||
279 | - output.Header("Content-Description", "File Transfer") | ||
280 | - output.Header("Content-Type", "application/octet-stream") | ||
281 | - output.Header("Content-Transfer-Encoding", "binary") | ||
282 | - output.Header("Expires", "0") | ||
283 | - output.Header("Cache-Control", "must-revalidate") | ||
284 | - output.Header("Pragma", "public") | ||
285 | - http.ServeFile(output.Context.ResponseWriter, output.Context.Request, file) | ||
286 | -} | ||
287 | - | ||
288 | -// ContentType sets the content type from ext string. | ||
289 | -// MIME type is given in mime package. | ||
290 | -func (output *BeegoOutput) ContentType(ext string) { | ||
291 | - if !strings.HasPrefix(ext, ".") { | ||
292 | - ext = "." + ext | ||
293 | - } | ||
294 | - ctype := mime.TypeByExtension(ext) | ||
295 | - if ctype != "" { | ||
296 | - output.Header("Content-Type", ctype) | ||
297 | - } | ||
298 | -} | ||
299 | - | ||
300 | -// SetStatus sets response status code. | ||
301 | -// It writes response header directly. | ||
302 | -func (output *BeegoOutput) SetStatus(status int) { | ||
303 | - output.Status = status | ||
304 | -} | ||
305 | - | ||
306 | -// IsCachable returns boolean of this request is cached. | ||
307 | -// HTTP 304 means cached. | ||
308 | -func (output *BeegoOutput) IsCachable() bool { | ||
309 | - return output.Status >= 200 && output.Status < 300 || output.Status == 304 | ||
310 | -} | ||
311 | - | ||
312 | -// IsEmpty returns boolean of this request is empty. | ||
313 | -// HTTP 201,204 and 304 means empty. | ||
314 | -func (output *BeegoOutput) IsEmpty() bool { | ||
315 | - return output.Status == 201 || output.Status == 204 || output.Status == 304 | ||
316 | -} | ||
317 | - | ||
318 | -// IsOk returns boolean of this request runs well. | ||
319 | -// HTTP 200 means ok. | ||
320 | -func (output *BeegoOutput) IsOk() bool { | ||
321 | - return output.Status == 200 | ||
322 | -} | ||
323 | - | ||
324 | -// IsSuccessful returns boolean of this request runs successfully. | ||
325 | -// HTTP 2xx means ok. | ||
326 | -func (output *BeegoOutput) IsSuccessful() bool { | ||
327 | - return output.Status >= 200 && output.Status < 300 | ||
328 | -} | ||
329 | - | ||
330 | -// IsRedirect returns boolean of this request is redirection header. | ||
331 | -// HTTP 301,302,307 means redirection. | ||
332 | -func (output *BeegoOutput) IsRedirect() bool { | ||
333 | - return output.Status == 301 || output.Status == 302 || output.Status == 303 || output.Status == 307 | ||
334 | -} | ||
335 | - | ||
336 | -// IsForbidden returns boolean of this request is forbidden. | ||
337 | -// HTTP 403 means forbidden. | ||
338 | -func (output *BeegoOutput) IsForbidden() bool { | ||
339 | - return output.Status == 403 | ||
340 | -} | ||
341 | - | ||
342 | -// IsNotFound returns boolean of this request is not found. | ||
343 | -// HTTP 404 means not found. | ||
344 | -func (output *BeegoOutput) IsNotFound() bool { | ||
345 | - return output.Status == 404 | ||
346 | -} | ||
347 | - | ||
348 | -// IsClientError returns boolean of this request client sends error data. | ||
349 | -// HTTP 4xx means client error. | ||
350 | -func (output *BeegoOutput) IsClientError() bool { | ||
351 | - return output.Status >= 400 && output.Status < 500 | ||
352 | -} | ||
353 | - | ||
354 | -// IsServerError returns boolean of this server handler errors. | ||
355 | -// HTTP 5xx means server internal error. | ||
356 | -func (output *BeegoOutput) IsServerError() bool { | ||
357 | - return output.Status >= 500 && output.Status < 600 | ||
358 | -} | ||
359 | - | ||
360 | -func stringsToJSON(str string) string { | ||
361 | - var jsons bytes.Buffer | ||
362 | - for _, r := range str { | ||
363 | - rint := int(r) | ||
364 | - if rint < 128 { | ||
365 | - jsons.WriteRune(r) | ||
366 | - } else { | ||
367 | - jsons.WriteString("\\u") | ||
368 | - if rint < 0x100 { | ||
369 | - jsons.WriteString("00") | ||
370 | - } else if rint < 0x1000 { | ||
371 | - jsons.WriteString("0") | ||
372 | - } | ||
373 | - jsons.WriteString(strconv.FormatInt(int64(rint), 16)) | ||
374 | - } | ||
375 | - } | ||
376 | - return jsons.String() | ||
377 | -} | ||
378 | - | ||
379 | -// Session sets session item value with given key. | ||
380 | -func (output *BeegoOutput) Session(name interface{}, value interface{}) { | ||
381 | - output.Context.Input.CruSession.Set(name, value) | ||
382 | -} |
1 | -package param | ||
2 | - | ||
3 | -import ( | ||
4 | - "fmt" | ||
5 | - "reflect" | ||
6 | - | ||
7 | - beecontext "github.com/astaxie/beego/context" | ||
8 | - "github.com/astaxie/beego/logs" | ||
9 | -) | ||
10 | - | ||
11 | -// ConvertParams converts http method params to values that will be passed to the method controller as arguments | ||
12 | -func ConvertParams(methodParams []*MethodParam, methodType reflect.Type, ctx *beecontext.Context) (result []reflect.Value) { | ||
13 | - result = make([]reflect.Value, 0, len(methodParams)) | ||
14 | - for i := 0; i < len(methodParams); i++ { | ||
15 | - reflectValue := convertParam(methodParams[i], methodType.In(i), ctx) | ||
16 | - result = append(result, reflectValue) | ||
17 | - } | ||
18 | - return | ||
19 | -} | ||
20 | - | ||
21 | -func convertParam(param *MethodParam, paramType reflect.Type, ctx *beecontext.Context) (result reflect.Value) { | ||
22 | - paramValue := getParamValue(param, ctx) | ||
23 | - if paramValue == "" { | ||
24 | - if param.required { | ||
25 | - ctx.Abort(400, fmt.Sprintf("Missing parameter %s", param.name)) | ||
26 | - } else { | ||
27 | - paramValue = param.defaultValue | ||
28 | - } | ||
29 | - } | ||
30 | - | ||
31 | - reflectValue, err := parseValue(param, paramValue, paramType) | ||
32 | - if err != nil { | ||
33 | - logs.Debug(fmt.Sprintf("Error converting param %s to type %s. Value: %v, Error: %s", param.name, paramType, paramValue, err)) | ||
34 | - ctx.Abort(400, fmt.Sprintf("Invalid parameter %s. Can not convert %v to type %s", param.name, paramValue, paramType)) | ||
35 | - } | ||
36 | - | ||
37 | - return reflectValue | ||
38 | -} | ||
39 | - | ||
40 | -func getParamValue(param *MethodParam, ctx *beecontext.Context) string { | ||
41 | - switch param.in { | ||
42 | - case body: | ||
43 | - return string(ctx.Input.RequestBody) | ||
44 | - case header: | ||
45 | - return ctx.Input.Header(param.name) | ||
46 | - case path: | ||
47 | - return ctx.Input.Query(":" + param.name) | ||
48 | - default: | ||
49 | - return ctx.Input.Query(param.name) | ||
50 | - } | ||
51 | -} | ||
52 | - | ||
53 | -func parseValue(param *MethodParam, paramValue string, paramType reflect.Type) (result reflect.Value, err error) { | ||
54 | - if paramValue == "" { | ||
55 | - return reflect.Zero(paramType), nil | ||
56 | - } | ||
57 | - parser := getParser(param, paramType) | ||
58 | - value, err := parser.parse(paramValue, paramType) | ||
59 | - if err != nil { | ||
60 | - return result, err | ||
61 | - } | ||
62 | - | ||
63 | - return safeConvert(reflect.ValueOf(value), paramType) | ||
64 | -} | ||
65 | - | ||
66 | -func safeConvert(value reflect.Value, t reflect.Type) (result reflect.Value, err error) { | ||
67 | - defer func() { | ||
68 | - if r := recover(); r != nil { | ||
69 | - var ok bool | ||
70 | - err, ok = r.(error) | ||
71 | - if !ok { | ||
72 | - err = fmt.Errorf("%v", r) | ||
73 | - } | ||
74 | - } | ||
75 | - }() | ||
76 | - result = value.Convert(t) | ||
77 | - return | ||
78 | -} |
1 | -package param | ||
2 | - | ||
3 | -import ( | ||
4 | - "fmt" | ||
5 | - "strings" | ||
6 | -) | ||
7 | - | ||
8 | -//MethodParam keeps param information to be auto passed to controller methods | ||
9 | -type MethodParam struct { | ||
10 | - name string | ||
11 | - in paramType | ||
12 | - required bool | ||
13 | - defaultValue string | ||
14 | -} | ||
15 | - | ||
16 | -type paramType byte | ||
17 | - | ||
18 | -const ( | ||
19 | - param paramType = iota | ||
20 | - path | ||
21 | - body | ||
22 | - header | ||
23 | -) | ||
24 | - | ||
25 | -//New creates a new MethodParam with name and specific options | ||
26 | -func New(name string, opts ...MethodParamOption) *MethodParam { | ||
27 | - return newParam(name, nil, opts) | ||
28 | -} | ||
29 | - | ||
30 | -func newParam(name string, parser paramParser, opts []MethodParamOption) (param *MethodParam) { | ||
31 | - param = &MethodParam{name: name} | ||
32 | - for _, option := range opts { | ||
33 | - option(param) | ||
34 | - } | ||
35 | - return | ||
36 | -} | ||
37 | - | ||
38 | -//Make creates an array of MethodParmas or an empty array | ||
39 | -func Make(list ...*MethodParam) []*MethodParam { | ||
40 | - if len(list) > 0 { | ||
41 | - return list | ||
42 | - } | ||
43 | - return nil | ||
44 | -} | ||
45 | - | ||
46 | -func (mp *MethodParam) String() string { | ||
47 | - options := []string{} | ||
48 | - result := "param.New(\"" + mp.name + "\"" | ||
49 | - if mp.required { | ||
50 | - options = append(options, "param.IsRequired") | ||
51 | - } | ||
52 | - switch mp.in { | ||
53 | - case path: | ||
54 | - options = append(options, "param.InPath") | ||
55 | - case body: | ||
56 | - options = append(options, "param.InBody") | ||
57 | - case header: | ||
58 | - options = append(options, "param.InHeader") | ||
59 | - } | ||
60 | - if mp.defaultValue != "" { | ||
61 | - options = append(options, fmt.Sprintf(`param.Default("%s")`, mp.defaultValue)) | ||
62 | - } | ||
63 | - if len(options) > 0 { | ||
64 | - result += ", " | ||
65 | - } | ||
66 | - result += strings.Join(options, ", ") | ||
67 | - result += ")" | ||
68 | - return result | ||
69 | -} |
-
请 注册 或 登录 后发表评论