作者 yangfu

fix

要显示太多修改。

为保证性能只显示 21 of 21+ 个文件。

1 -.idea  
2 -.vscode  
3 -.DS_Store  
4 -*.swp  
5 -*.swo  
6 -beego.iml  
1 -github.com/astaxie/beego/*/*:S1012  
2 -github.com/astaxie/beego/*:S1012  
3 -github.com/astaxie/beego/*/*:S1007  
4 -github.com/astaxie/beego/*:S1007  
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  
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).  
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 -`  
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 -}  
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 -}