1
0
mirror of https://github.com/astaxie/beego.git synced 2025-07-11 09:41:01 +00:00

63 Commits

Author SHA1 Message Date
cab8458c1c Merge pull request #2651 from astaxie/develop
v1.8.3
2017-05-19 21:19:18 +08:00
f0b95c552b Merge pull request #2315 from sch00lb0y/master
issue no:#2261 fix for xsrf panic error
2017-05-19 18:50:56 +08:00
ce677202e5 issue no:#2261 fix for xsrf panic error 2017-05-19 14:02:14 +05:30
720c323e20 Merge pull request #2652 from gouyang/gouyang/dev
Support timeformat "2006-01-02T15:04:05"
2017-05-19 09:48:35 +08:00
47e351e11d Support timeformat "2006-01-02T15:04:05"
Fixes #2649

Signed-off-by: Guohua Ouyang <guohuaouyang@gmail.com>
2017-05-19 09:22:27 +08:00
248beab557 v1.8.3 2017-05-18 22:55:10 +08:00
388a5610fa Merge pull request #2365 from chesedo/RequiredValidationCatchSpaces
[WIP]Have Required validator trim strings to fix #2361
2017-05-18 22:44:15 +08:00
41498758fe Merge pull request #2620 from hsluoyz/authz
Add an authorization plugin that supports ACL, RBAC based on casbin.
2017-05-18 18:18:12 +08:00
655484b4df Merge pull request #2586 from eyalpost/develop
Automatic Parameter Router
2017-05-18 18:14:49 +08:00
11b4bf8aaa move to context 2017-05-18 10:38:12 +03:00
2513bcf584 remove Redirect to avoid confusion 2017-05-18 10:32:51 +03:00
3e51823c0f move response 2017-05-18 09:05:49 +03:00
e32a18203b fix gosimple 2017-05-17 21:27:32 +03:00
ee1d8bc30e fix gosimple 2017-05-17 20:50:41 +03:00
828cbbdf5d Refactor a bit to consolidate packages 2017-05-17 20:38:59 +03:00
d54cd4fa5f Merge remote-tracking branch 'upstream/develop' into develop 2017-05-17 20:02:40 +03:00
7747e9ec8b Merge branch 'develop' of https://github.com/astaxie/beego into develop 2017-05-17 20:52:53 +08:00
9765519f38 Merge pull request #2637 from alexsunxl/develop
allow o.Raw(sql).QueryRows(&container) pass nested struct
2017-05-17 16:45:14 +08:00
69f0b94745 fix gosimple 2017-05-16 22:21:43 +08:00
3c9b6c99b7 Merge pull request #2643 from rbw0/master
Spelling fixes
2017-05-16 11:26:16 +08:00
b5c6eb54d2 Missing PK error spelling fix 2017-05-16 00:58:20 +02:00
e1c90bfc09 Table not found spelling fixes 2017-05-16 00:27:57 +02:00
91400f10b0 Merge pull request #2640 from franzwilhelm/master
Moved Security to Operation struct to support swagger API security auth
2017-05-14 19:15:20 +08:00
c814893d65 add support for global security 2017-05-14 12:13:35 +02:00
2325090101 add test case that used nested struct test QueryRows 2017-05-14 12:03:34 +08:00
40bc52b844 fix security struct placement and formatting 2017-05-14 00:42:09 +02:00
589f3755f0 允许o.Raw(sql).QueryRows(&container) 传入的container包含结构的嵌套 2017-05-12 18:11:42 +08:00
1004678005 popular status codes 2017-05-12 09:57:56 +03:00
0ac2e47162 location=>paramType 2017-05-12 09:28:46 +03:00
b6a35a8944 more tests 2017-05-12 09:25:12 +03:00
74dc3c7500 tests 2017-05-11 19:32:44 +03:00
cb4f252a06 defValue -> defaultValue 2017-05-11 17:58:25 +03:00
bceefc9075 Merge pull request #2636 from guanly/master
ISSUE2630 使用sqlite,orm中通过filter后的delete删除不成功
2017-05-11 22:04:27 +08:00
10cd1070f4 使用sqlite,orm中通过filter后的delete删除不成功
https://github.com/astaxie/beego/issues/2630
2017-05-11 21:45:38 +08:00
9b01b1c63d ISSUE2630 使用sqlite,orm中通过filter后的delete删除不成功
https://github.com/astaxie/beego/issues/2630
2017-05-11 14:49:01 +08:00
b2e7720fcd Add an authorization plugin that supports ACL, RBAC based on casbin. It requires the built-in HTTP basic authentication by default. 2017-05-04 14:02:21 +08:00
83814a76cc hotfix: err nil 2017-05-02 12:47:15 +08:00
d3a16dca85 Redirect should returns error 2017-05-01 08:57:57 +03:00
7452151bee Merge pull request #2611 from astaxie/develop
1.8.2
2017-05-01 13:01:59 +08:00
1b8f05cef1 golint fixes 2017-04-30 19:28:26 +03:00
cfb2f68dd6 Merge remote-tracking branch 'upstream/develop' into develop 2017-04-30 18:59:50 +03:00
e76423e6dc revert #2518, fix #2605 2017-04-30 23:59:38 +08:00
947980b5eb beego 1.8.2 2017-04-30 23:43:46 +08:00
44bdf1df63 ignore NilErr 2017-04-30 23:38:48 +08:00
79b66ef053 fix the beego ORM test 2017-04-30 22:55:39 +08:00
a91e2e9950 add golint check and fix all golints 2017-04-30 22:41:23 +08:00
ea3d0690cf golint 2017-04-29 09:13:28 +08:00
1c32c011a1 fix misspell 2017-04-28 23:37:40 +08:00
64b475d7d6 fix ReadOrCreate test case 2017-04-28 22:58:17 +08:00
aa8f7bc146 fix ineffectual 2017-04-28 22:36:28 +08:00
3e29078f68 add check ineffect and gofmt 2017-04-28 21:38:08 +08:00
a1bc94e648 dont generate comment if router not found 2017-04-26 01:00:25 +03:00
4cba78afd9 small fixes 2017-04-25 23:42:35 +03:00
f311ae9ebe feature: Export function printTree (#2597)
This exports PrintTree function which allow to set Role Based Access Control, Create our own requests statistics...etc
2017-04-25 18:12:03 +02:00
cbd831042a move under context 2017-04-25 18:39:42 +03:00
9b79437778 all types working + controller comments generation 2017-04-25 16:00:49 +03:00
3b29a9c12a Merge remote-tracking branch 'upstream/develop' into develop 2017-04-24 18:23:58 +03:00
864693d2f8 mall fixes 2017-04-24 02:35:04 +03:00
08ea9b3339 Merge remote-tracking branch 'upstream/develop' into develop 2017-04-23 22:07:46 +03:00
19f4a6ac0b slice support 2017-04-23 21:37:09 +03:00
89e01d125c all types implemented 2017-04-23 01:33:50 +03:00
9aedb4d05a phase #1 2017-04-21 15:26:41 +03:00
a8a2dffc59 Have Required validator trim strings to fix #2361
This will cause the Required validator not to consider fields that has
only spaces or new lines to be regarded as valid. This is done by
checking if the trimmed version of the string is valid.
2017-01-06 10:12:22 +02:00
64 changed files with 1439 additions and 372 deletions

View File

@ -33,8 +33,12 @@ install:
- go get github.com/ssdb/gossdb/ssdb
- go get github.com/cloudflare/golz4
- go get github.com/gogo/protobuf/proto
- go get github.com/Knetic/govaluate
- go get github.com/hsluoyz/casbin
- go get -u honnef.co/go/tools/cmd/gosimple
- go get -u github.com/mdempsky/unconvert
- go get -u github.com/gordonklaus/ineffassign
- go get -u github.com/golang/lint/golint
before_script:
- psql --version
- sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi"
@ -51,5 +55,8 @@ script:
- go test -v ./...
- gosimple -ignore "$(cat .gosimpleignore)" $(go list ./... | grep -v /vendor/)
- unconvert $(go list ./... | grep -v /vendor/)
- ineffassign .
- find . ! \( -path './vendor' -prune \) -type f -name '*.go' -print0 | xargs -0 gofmt -l -s
- golint ./...
addons:
postgresql: "9.4"

View File

@ -105,29 +105,12 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
tmpl.Execute(rw, data)
case "router":
var (
content = map[string]interface{}{
"Fields": []string{
"Router Pattern",
"Methods",
"Controller",
},
}
methods = []string{}
methodsData = make(map[string]interface{})
)
for method, t := range BeeApp.Handlers.routers {
resultList := new([][]string)
printTree(resultList, t)
methods = append(methods, method)
methodsData[method] = resultList
content := PrintTree()
content["Fields"] = []string{
"Router Pattern",
"Methods",
"Controller",
}
content["Data"] = methodsData
content["Methods"] = methods
data["Content"] = content
data["Title"] = "Routers"
execTpl(rw, data, routerAndFilterTpl, defaultScriptsTpl)
@ -200,6 +183,28 @@ func list(root string, p interface{}, m map[string]interface{}) {
}
}
// PrintTree prints all registered routers.
func PrintTree() map[string]interface{} {
var (
content = map[string]interface{}{}
methods = []string{}
methodsData = make(map[string]interface{})
)
for method, t := range BeeApp.Handlers.routers {
resultList := new([][]string)
printTree(resultList, t)
methods = append(methods, method)
methodsData[method] = resultList
}
content["Data"] = methodsData
content["Methods"] = methods
return content
}
func printTree(resultList *[][]string, t *Tree) {
for _, tr := range t.fixrouters {
printTree(resultList, tr)

View File

@ -23,7 +23,7 @@ import (
const (
// VERSION represent beego web framework version.
VERSION = "1.8.1"
VERSION = "1.8.3"
// DEV is for develop
DEV = "dev"

2
cache/conv.go vendored
View File

@ -28,7 +28,7 @@ func GetString(v interface{}) string {
return string(result)
default:
if v != nil {
return fmt.Sprintf("%v", result)
return fmt.Sprint(result)
}
}
return ""

2
config/env/env.go vendored
View File

@ -12,6 +12,8 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package env is used to parse environment.
package env
import (

View File

@ -325,7 +325,10 @@ func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) {
// Get section or key comments. Fixed #1607
getCommentStr := func(section, key string) string {
comment, ok := "", false
var (
comment string
ok bool
)
if len(key) == 0 {
comment, ok = c.sectionComment[section]
} else {

View File

@ -39,6 +39,7 @@ var (
getMethodOnly bool
)
// InitGzip init the gzipcompress
func InitGzip(minLength, compressLevel int, methods []string) {
if minLength >= 0 {
gzipMinLength = minLength

View File

@ -171,6 +171,22 @@ func (ctx *Context) CheckXSRFCookie() bool {
return true
}
// RenderMethodResult renders the return value of a controller method to the output
func (ctx *Context) RenderMethodResult(result interface{}) {
if result != nil {
renderer, ok := result.(Renderer)
if !ok {
err, ok := result.(error)
if ok {
renderer = errorRenderer(err)
} else {
renderer = jsonRenderer(result)
}
}
renderer.Render(ctx)
}
}
//Response is a wrapper for the http.ResponseWriter
//started set to true if response was written to then don't execute other handler
type Response struct {

View File

@ -105,7 +105,7 @@ func (output *BeegoOutput) Cookie(name string, value string, others ...interface
switch {
case maxAge > 0:
fmt.Fprintf(&b, "; Expires=%s; Max-Age=%d", time.Now().Add(time.Duration(maxAge)*time.Second).UTC().Format(time.RFC1123), maxAge)
case maxAge <= 0:
case maxAge < 0:
fmt.Fprintf(&b, "; Max-Age=0")
}
}
@ -168,6 +168,19 @@ func sanitizeValue(v string) string {
return cookieValueSanitizer.Replace(v)
}
func jsonRenderer(value interface{}) Renderer {
return rendererFunc(func(ctx *Context) {
ctx.Output.JSON(value, false, false)
})
}
func errorRenderer(err error) Renderer {
return rendererFunc(func(ctx *Context) {
ctx.Output.SetStatus(500)
ctx.WriteString(err.Error())
})
}
// JSON writes json to response body.
// if coding is true, it converts utf-8 to \u0000 type.
func (output *BeegoOutput) JSON(data interface{}, hasIndent bool, coding bool) error {
@ -330,9 +343,8 @@ func (output *BeegoOutput) IsServerError() bool {
}
func stringsToJSON(str string) string {
rs := []rune(str)
var jsons bytes.Buffer
for _, r := range rs {
for _, r := range str {
rint := int(r)
if rint < 128 {
jsons.WriteRune(r)

78
context/param/conv.go Normal file
View File

@ -0,0 +1,78 @@
package param
import (
"fmt"
"reflect"
beecontext "github.com/astaxie/beego/context"
"github.com/astaxie/beego/logs"
)
// ConvertParams converts http method params to values that will be passed to the method controller as arguments
func ConvertParams(methodParams []*MethodParam, methodType reflect.Type, ctx *beecontext.Context) (result []reflect.Value) {
result = make([]reflect.Value, 0, len(methodParams))
for i := 0; i < len(methodParams); i++ {
reflectValue := convertParam(methodParams[i], methodType.In(i), ctx)
result = append(result, reflectValue)
}
return
}
func convertParam(param *MethodParam, paramType reflect.Type, ctx *beecontext.Context) (result reflect.Value) {
paramValue := getParamValue(param, ctx)
if paramValue == "" {
if param.required {
ctx.Abort(400, fmt.Sprintf("Missing parameter %s", param.name))
} else {
paramValue = param.defaultValue
}
}
reflectValue, err := parseValue(param, paramValue, paramType)
if err != nil {
logs.Debug(fmt.Sprintf("Error converting param %s to type %s. Value: %v, Error: %s", param.name, paramType, paramValue, err))
ctx.Abort(400, fmt.Sprintf("Invalid parameter %s. Can not convert %v to type %s", param.name, paramValue, paramType))
}
return reflectValue
}
func getParamValue(param *MethodParam, ctx *beecontext.Context) string {
switch param.in {
case body:
return string(ctx.Input.RequestBody)
case header:
return ctx.Input.Header(param.name)
case path:
return ctx.Input.Query(":" + param.name)
default:
return ctx.Input.Query(param.name)
}
}
func parseValue(param *MethodParam, paramValue string, paramType reflect.Type) (result reflect.Value, err error) {
if paramValue == "" {
return reflect.Zero(paramType), nil
}
parser := getParser(param, paramType)
value, err := parser.parse(paramValue, paramType)
if err != nil {
return result, err
}
return safeConvert(reflect.ValueOf(value), paramType)
}
func safeConvert(value reflect.Value, t reflect.Type) (result reflect.Value, err error) {
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok = r.(error)
if !ok {
err = fmt.Errorf("%v", r)
}
}
}()
result = value.Convert(t)
return
}

View File

@ -0,0 +1,69 @@
package param
import (
"fmt"
"strings"
)
//MethodParam keeps param information to be auto passed to controller methods
type MethodParam struct {
name string
in paramType
required bool
defaultValue string
}
type paramType byte
const (
param paramType = iota
path
body
header
)
//New creates a new MethodParam with name and specific options
func New(name string, opts ...MethodParamOption) *MethodParam {
return newParam(name, nil, opts)
}
func newParam(name string, parser paramParser, opts []MethodParamOption) (param *MethodParam) {
param = &MethodParam{name: name}
for _, option := range opts {
option(param)
}
return
}
//Make creates an array of MethodParmas or an empty array
func Make(list ...*MethodParam) []*MethodParam {
if len(list) > 0 {
return list
}
return nil
}
func (mp *MethodParam) String() string {
options := []string{}
result := "param.New(\"" + mp.name + "\""
if mp.required {
options = append(options, "param.IsRequired")
}
switch mp.in {
case path:
options = append(options, "param.InPath")
case body:
options = append(options, "param.InBody")
case header:
options = append(options, "param.InHeader")
}
if mp.defaultValue != "" {
options = append(options, fmt.Sprintf(`param.Default("%s")`, mp.defaultValue))
}
if len(options) > 0 {
result += ", "
}
result += strings.Join(options, ", ")
result += ")"
return result
}

37
context/param/options.go Normal file
View File

@ -0,0 +1,37 @@
package param
import (
"fmt"
)
// MethodParamOption defines a func which apply options on a MethodParam
type MethodParamOption func(*MethodParam)
// IsRequired indicates that this param is required and can not be ommited from the http request
var IsRequired MethodParamOption = func(p *MethodParam) {
p.required = true
}
// InHeader indicates that this param is passed via an http header
var InHeader MethodParamOption = func(p *MethodParam) {
p.in = header
}
// InPath indicates that this param is part of the URL path
var InPath MethodParamOption = func(p *MethodParam) {
p.in = path
}
// InBody indicates that this param is passed as an http request body
var InBody MethodParamOption = func(p *MethodParam) {
p.in = body
}
// Default provides a default value for the http param
func Default(defaultValue interface{}) MethodParamOption {
return func(p *MethodParam) {
if defaultValue != nil {
p.defaultValue = fmt.Sprint(defaultValue)
}
}
}

149
context/param/parsers.go Normal file
View File

@ -0,0 +1,149 @@
package param
import (
"encoding/json"
"reflect"
"strconv"
"strings"
"time"
)
type paramParser interface {
parse(value string, toType reflect.Type) (interface{}, error)
}
func getParser(param *MethodParam, t reflect.Type) paramParser {
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return intParser{}
case reflect.Slice:
if t.Elem().Kind() == reflect.Uint8 { //treat []byte as string
return stringParser{}
}
if param.in == body {
return jsonParser{}
}
elemParser := getParser(param, t.Elem())
if elemParser == (jsonParser{}) {
return elemParser
}
return sliceParser(elemParser)
case reflect.Bool:
return boolParser{}
case reflect.String:
return stringParser{}
case reflect.Float32, reflect.Float64:
return floatParser{}
case reflect.Ptr:
elemParser := getParser(param, t.Elem())
if elemParser == (jsonParser{}) {
return elemParser
}
return ptrParser(elemParser)
default:
if t.PkgPath() == "time" && t.Name() == "Time" {
return timeParser{}
}
return jsonParser{}
}
}
type parserFunc func(value string, toType reflect.Type) (interface{}, error)
func (f parserFunc) parse(value string, toType reflect.Type) (interface{}, error) {
return f(value, toType)
}
type boolParser struct {
}
func (p boolParser) parse(value string, toType reflect.Type) (interface{}, error) {
return strconv.ParseBool(value)
}
type stringParser struct {
}
func (p stringParser) parse(value string, toType reflect.Type) (interface{}, error) {
return value, nil
}
type intParser struct {
}
func (p intParser) parse(value string, toType reflect.Type) (interface{}, error) {
return strconv.Atoi(value)
}
type floatParser struct {
}
func (p floatParser) parse(value string, toType reflect.Type) (interface{}, error) {
if toType.Kind() == reflect.Float32 {
res, err := strconv.ParseFloat(value, 32)
if err != nil {
return nil, err
}
return float32(res), nil
}
return strconv.ParseFloat(value, 64)
}
type timeParser struct {
}
func (p timeParser) parse(value string, toType reflect.Type) (result interface{}, err error) {
result, err = time.Parse(time.RFC3339, value)
if err != nil {
result, err = time.Parse("2006-01-02", value)
}
return
}
type jsonParser struct {
}
func (p jsonParser) parse(value string, toType reflect.Type) (interface{}, error) {
pResult := reflect.New(toType)
v := pResult.Interface()
err := json.Unmarshal([]byte(value), v)
if err != nil {
return nil, err
}
return pResult.Elem().Interface(), nil
}
func sliceParser(elemParser paramParser) paramParser {
return parserFunc(func(value string, toType reflect.Type) (interface{}, error) {
values := strings.Split(value, ",")
result := reflect.MakeSlice(toType, 0, len(values))
elemType := toType.Elem()
for _, v := range values {
parsedValue, err := elemParser.parse(v, elemType)
if err != nil {
return nil, err
}
result = reflect.Append(result, reflect.ValueOf(parsedValue))
}
return result.Interface(), nil
})
}
func ptrParser(elemParser paramParser) paramParser {
return parserFunc(func(value string, toType reflect.Type) (interface{}, error) {
parsedValue, err := elemParser.parse(value, toType.Elem())
if err != nil {
return nil, err
}
newValPtr := reflect.New(toType.Elem())
newVal := reflect.Indirect(newValPtr)
convertedVal, err := safeConvert(reflect.ValueOf(parsedValue), toType.Elem())
if err != nil {
return nil, err
}
newVal.Set(convertedVal)
return newValPtr.Interface(), nil
})
}

View File

@ -0,0 +1,84 @@
package param
import "testing"
import "reflect"
import "time"
type testDefinition struct {
strValue string
expectedValue interface{}
expectedParser paramParser
}
func Test_Parsers(t *testing.T) {
//ints
checkParser(testDefinition{"1", 1, intParser{}}, t)
checkParser(testDefinition{"-1", int64(-1), intParser{}}, t)
checkParser(testDefinition{"1", uint64(1), intParser{}}, t)
//floats
checkParser(testDefinition{"1.0", float32(1.0), floatParser{}}, t)
checkParser(testDefinition{"-1.0", float64(-1.0), floatParser{}}, t)
//strings
checkParser(testDefinition{"AB", "AB", stringParser{}}, t)
checkParser(testDefinition{"AB", []byte{65, 66}, stringParser{}}, t)
//bools
checkParser(testDefinition{"true", true, boolParser{}}, t)
checkParser(testDefinition{"0", false, boolParser{}}, t)
//timeParser
checkParser(testDefinition{"2017-05-30T13:54:53Z", time.Date(2017, 5, 30, 13, 54, 53, 0, time.UTC), timeParser{}}, t)
checkParser(testDefinition{"2017-05-30", time.Date(2017, 5, 30, 0, 0, 0, 0, time.UTC), timeParser{}}, t)
//json
checkParser(testDefinition{`{"X": 5, "Y":"Z"}`, struct {
X int
Y string
}{5, "Z"}, jsonParser{}}, t)
//slice in query is parsed as comma delimited
checkParser(testDefinition{`1,2`, []int{1, 2}, sliceParser(intParser{})}, t)
//slice in body is parsed as json
checkParser(testDefinition{`["a","b"]`, []string{"a", "b"}, jsonParser{}}, t, MethodParam{in: body})
//pointers
var someInt = 1
checkParser(testDefinition{`1`, &someInt, ptrParser(intParser{})}, t)
var someStruct = struct{ X int }{5}
checkParser(testDefinition{`{"X": 5}`, &someStruct, jsonParser{}}, t)
}
func checkParser(def testDefinition, t *testing.T, methodParam ...MethodParam) {
toType := reflect.TypeOf(def.expectedValue)
var mp MethodParam
if len(methodParam) == 0 {
mp = MethodParam{}
} else {
mp = methodParam[0]
}
parser := getParser(&mp, toType)
if reflect.TypeOf(parser) != reflect.TypeOf(def.expectedParser) {
t.Errorf("Invalid parser for value %v. Expected: %v, actual: %v", def.strValue, reflect.TypeOf(def.expectedParser).Name(), reflect.TypeOf(parser).Name())
return
}
result, err := parser.parse(def.strValue, toType)
if err != nil {
t.Errorf("Parsing error for value %v. Expected result: %v, error: %v", def.strValue, def.expectedValue, err)
return
}
convResult, err := safeConvert(reflect.ValueOf(result), toType)
if err != nil {
t.Errorf("Convertion error for %v. from value: %v, toType: %v, error: %v", def.strValue, result, toType, err)
return
}
if !reflect.DeepEqual(convResult.Interface(), def.expectedValue) {
t.Errorf("Parsing error for value %v. Expected result: %v, actual: %v", def.strValue, def.expectedValue, result)
}
}

12
context/renderer.go Normal file
View File

@ -0,0 +1,12 @@
package context
// Renderer defines an http response renderer
type Renderer interface {
Render(ctx *Context)
}
type rendererFunc func(ctx *Context)
func (f rendererFunc) Render(ctx *Context) {
f(ctx)
}

27
context/response.go Normal file
View File

@ -0,0 +1,27 @@
package context
import (
"strconv"
"net/http"
)
const (
//BadRequest indicates http error 400
BadRequest StatusCode = http.StatusBadRequest
//NotFound indicates http error 404
NotFound StatusCode = http.StatusNotFound
)
// StatusCode sets the http response status code
type StatusCode int
func (s StatusCode) Error() string {
return strconv.Itoa(int(s))
}
// Render sets the http status code
func (s StatusCode) Render(ctx *Context) {
ctx.Output.SetStatus(int(s))
}

View File

@ -28,6 +28,7 @@ import (
"strings"
"github.com/astaxie/beego/context"
"github.com/astaxie/beego/context/param"
"github.com/astaxie/beego/session"
)
@ -51,6 +52,7 @@ type ControllerComments struct {
Router string
AllowHTTPMethods []string
Params []map[string]string
MethodParams []*param.MethodParam
}
// Controller defines some basic http request handler operations, such as

View File

@ -252,6 +252,30 @@ func forbidden(rw http.ResponseWriter, r *http.Request) {
)
}
// show 422 missing xsrf token
func missingxsrf(rw http.ResponseWriter, r *http.Request) {
responseError(rw, r,
422,
"<br>The page you have requested is forbidden."+
"<br>Perhaps you are here because:"+
"<br><br><ul>"+
"<br>'_xsrf' argument missing from POST"+
"</ul>",
)
}
// show 417 invalid xsrf token
func invalidxsrf(rw http.ResponseWriter, r *http.Request) {
responseError(rw, r,
417,
"<br>The page you have requested is forbidden."+
"<br>Perhaps you are here because:"+
"<br><br><ul>"+
"<br>expected XSRF not found"+
"</ul>",
)
}
// show 404 not found error.
func notFound(rw http.ResponseWriter, r *http.Request) {
responseError(rw, r,

View File

@ -291,7 +291,7 @@ func (srv *Server) fork() (err error) {
// RegisterSignalHook registers a function to be run PreSignal or PostSignal for a given signal.
func (srv *Server) RegisterSignalHook(ppFlag int, sig os.Signal, f func()) (err error) {
if ppFlag != PreSignal && ppFlag != PostSignal {
err = fmt.Errorf("Invalid ppFlag argument. Must be either grace.PreSignal or grace.PostSignal.")
err = fmt.Errorf("Invalid ppFlag argument. Must be either grace.PreSignal or grace.PostSignal")
return
}
for _, s := range hookableSignals {
@ -300,6 +300,6 @@ func (srv *Server) RegisterSignalHook(ppFlag int, sig os.Signal, f func()) (err
return
}
}
err = fmt.Errorf("Signal '%v' is not supported.", sig)
err = fmt.Errorf("Signal '%v' is not supported", sig)
return
}

View File

@ -32,6 +32,8 @@ func registerDefaultErrorHandler() error {
"502": badGateway,
"503": serviceUnavailable,
"504": gatewayTimeout,
"417": invalidxsrf,
"422": missingxsrf,
}
for e, h := range m {
if _, ok := ErrorMaps[e]; !ok {
@ -55,9 +57,9 @@ func registerSession() error {
conf.ProviderConfig = filepath.ToSlash(BConfig.WebConfig.Session.SessionProviderConfig)
conf.DisableHTTPOnly = BConfig.WebConfig.Session.SessionDisableHTTPOnly
conf.Domain = BConfig.WebConfig.Session.SessionDomain
conf.EnableSidInHttpHeader = BConfig.WebConfig.Session.SessionEnableSidInHTTPHeader
conf.SessionNameInHttpHeader = BConfig.WebConfig.Session.SessionNameInHTTPHeader
conf.EnableSidInUrlQuery = BConfig.WebConfig.Session.SessionEnableSidInURLQuery
conf.EnableSidInHTTPHeader = BConfig.WebConfig.Session.SessionEnableSidInHTTPHeader
conf.SessionNameInHTTPHeader = BConfig.WebConfig.Session.SessionNameInHTTPHeader
conf.EnableSidInURLQuery = BConfig.WebConfig.Session.SessionEnableSidInURLQuery
} else {
if err = json.Unmarshal([]byte(sessionConfig), conf); err != nil {
return err

View File

@ -32,7 +32,7 @@ The default timeout is `60` seconds, function prototype:
SetTimeout(connectTimeout, readWriteTimeout time.Duration)
Exmaple:
Example:
// GET
httplib.Get("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second)

View File

@ -520,9 +520,9 @@ func (b *BeegoHTTPRequest) Bytes() ([]byte, error) {
return nil, err
}
b.body, err = ioutil.ReadAll(reader)
} else {
b.body, err = ioutil.ReadAll(resp.Body)
return b.body, err
}
b.body, err = ioutil.ReadAll(resp.Body)
return b.body, err
}

View File

@ -2,19 +2,23 @@ package alils
import (
"encoding/json"
"github.com/astaxie/beego/logs"
"github.com/gogo/protobuf/proto"
"strings"
"sync"
"time"
"github.com/astaxie/beego/logs"
"github.com/gogo/protobuf/proto"
)
const (
CacheSize int = 64
// CacheSize set the flush size
CacheSize int = 64
// Delimiter define the topic delimiter
Delimiter string = "##"
)
type AliLSConfig struct {
// Config is the Config for Ali Log
type Config struct {
Project string `json:"project"`
Endpoint string `json:"endpoint"`
KeyID string `json:"key_id"`
@ -34,18 +38,17 @@ type aliLSWriter struct {
withMap bool
groupMap map[string]*LogGroup
lock *sync.Mutex
AliLSConfig
Config
}
// 创建提供Logger接口的日志服务
// NewAliLS create a new Logger
func NewAliLS() logs.Logger {
alils := new(aliLSWriter)
alils.Level = logs.LevelTrace
return alils
}
// 读取配置
// 初始化必要的数据结构
// Init parse config and init struct
func (c *aliLSWriter) Init(jsonConfig string) (err error) {
json.Unmarshal([]byte(jsonConfig), c)
@ -54,28 +57,26 @@ func (c *aliLSWriter) Init(jsonConfig string) (err error) {
c.FlushWhen = CacheSize
}
// 初始化Project
prj := &LogProject{
Name: c.Project,
Endpoint: c.Endpoint,
AccessKeyId: c.KeyID,
AccessKeyID: c.KeyID,
AccessKeySecret: c.KeySecret,
}
// 获取logstore
c.store, err = prj.GetLogStore(c.LogStore)
if err != nil {
return err
}
// 创建默认Log Group
// Create default Log Group
c.group = append(c.group, &LogGroup{
Topic: proto.String(""),
Source: proto.String(c.Source),
Logs: make([]*Log, 0, c.FlushWhen),
})
// 创建其它Log Group
// Create other Log Group
c.groupMap = make(map[string]*LogGroup)
for _, topic := range c.Topics {
@ -113,7 +114,7 @@ func (c *aliLSWriter) WriteMsg(when time.Time, msg string, level int) (err error
var lg *LogGroup
if c.withMap {
// 解析出Topic并匹配LogGroup
// TopicLogGroup
strs := strings.SplitN(msg, Delimiter, 2)
if len(strs) == 2 {
pos := strings.LastIndex(strs[0], " ")
@ -122,27 +123,24 @@ func (c *aliLSWriter) WriteMsg(when time.Time, msg string, level int) (err error
lg = c.groupMap[topic]
}
// 默认发到空Topic
// send to empty Topic
if lg == nil {
topic = ""
content = msg
lg = c.group[0]
}
} else {
topic = ""
content = msg
lg = c.group[0]
}
// 生成日志
c1 := &Log_Content{
c1 := &LogContent{
Key: proto.String("msg"),
Value: proto.String(content),
}
l := &Log{
Time: proto.Uint32(uint32(when.Unix())), // 填写日志时间
Contents: []*Log_Content{
Time: proto.Uint32(uint32(when.Unix())),
Contents: []*LogContent{
c1,
},
}
@ -151,7 +149,6 @@ func (c *aliLSWriter) WriteMsg(when time.Time, msg string, level int) (err error
lg.Logs = append(lg.Logs, l)
c.lock.Unlock()
// 满足条件则Flush
if len(lg.Logs) >= c.FlushWhen {
c.flush(lg)
}
@ -162,7 +159,7 @@ func (c *aliLSWriter) WriteMsg(when time.Time, msg string, level int) (err error
// Flush implementing method. empty.
func (c *aliLSWriter) Flush() {
// flush所有group
// flush all group
for _, lg := range c.group {
c.flush(lg)
}
@ -176,9 +173,6 @@ func (c *aliLSWriter) flush(lg *LogGroup) {
c.lock.Lock()
defer c.lock.Unlock()
// 把以上的LogGroup推送到SLS服务器
// SLS服务器会根据该logstore的shard个数自动进行负载均衡。
err := c.store.PutLogs(lg)
if err != nil {
return

View File

@ -1,30 +1,43 @@
package alils
import "github.com/gogo/protobuf/proto"
import "fmt"
import "math"
import (
"fmt"
"io"
"math"
// discarding unused import gogoproto "."
import github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto"
import "io"
"github.com/gogo/protobuf/proto"
github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
var (
// ErrInvalidLengthLog invalid proto
ErrInvalidLengthLog = fmt.Errorf("proto: negative length found during unmarshaling")
// ErrIntOverflowLog overflow
ErrIntOverflowLog = fmt.Errorf("proto: integer overflow")
)
// Log define the proto Log
type Log struct {
Time *uint32 `protobuf:"varint,1,req,name=Time" json:"Time,omitempty"`
Contents []*Log_Content `protobuf:"bytes,2,rep,name=Contents" json:"Contents,omitempty"`
XXX_unrecognized []byte `json:"-"`
Time *uint32 `protobuf:"varint,1,req,name=Time" json:"Time,omitempty"`
Contents []*LogContent `protobuf:"bytes,2,rep,name=Contents" json:"Contents,omitempty"`
XXXUnrecognized []byte `json:"-"`
}
func (m *Log) Reset() { *m = Log{} }
func (m *Log) String() string { return proto.CompactTextString(m) }
func (*Log) ProtoMessage() {}
// Reset the Log
func (m *Log) Reset() { *m = Log{} }
// String return the Compact Log
func (m *Log) String() string { return proto.CompactTextString(m) }
// ProtoMessage not implemented
func (*Log) ProtoMessage() {}
// GetTime return the Log's Time
func (m *Log) GetTime() uint32 {
if m != nil && m.Time != nil {
return *m.Time
@ -32,49 +45,65 @@ func (m *Log) GetTime() uint32 {
return 0
}
func (m *Log) GetContents() []*Log_Content {
// GetContents return the Log's Contents
func (m *Log) GetContents() []*LogContent {
if m != nil {
return m.Contents
}
return nil
}
type Log_Content struct {
Key *string `protobuf:"bytes,1,req,name=Key" json:"Key,omitempty"`
Value *string `protobuf:"bytes,2,req,name=Value" json:"Value,omitempty"`
XXX_unrecognized []byte `json:"-"`
// LogContent define the Log content struct
type LogContent struct {
Key *string `protobuf:"bytes,1,req,name=Key" json:"Key,omitempty"`
Value *string `protobuf:"bytes,2,req,name=Value" json:"Value,omitempty"`
XXXUnrecognized []byte `json:"-"`
}
func (m *Log_Content) Reset() { *m = Log_Content{} }
func (m *Log_Content) String() string { return proto.CompactTextString(m) }
func (*Log_Content) ProtoMessage() {}
// Reset LogContent
func (m *LogContent) Reset() { *m = LogContent{} }
func (m *Log_Content) GetKey() string {
// String return the compact text
func (m *LogContent) String() string { return proto.CompactTextString(m) }
// ProtoMessage not implemented
func (*LogContent) ProtoMessage() {}
// GetKey return the Key
func (m *LogContent) GetKey() string {
if m != nil && m.Key != nil {
return *m.Key
}
return ""
}
func (m *Log_Content) GetValue() string {
// GetValue return the Value
func (m *LogContent) GetValue() string {
if m != nil && m.Value != nil {
return *m.Value
}
return ""
}
// LogGroup define the logs struct
type LogGroup struct {
Logs []*Log `protobuf:"bytes,1,rep,name=Logs" json:"Logs,omitempty"`
Reserved *string `protobuf:"bytes,2,opt,name=Reserved" json:"Reserved,omitempty"`
Topic *string `protobuf:"bytes,3,opt,name=Topic" json:"Topic,omitempty"`
Source *string `protobuf:"bytes,4,opt,name=Source" json:"Source,omitempty"`
XXX_unrecognized []byte `json:"-"`
Logs []*Log `protobuf:"bytes,1,rep,name=Logs" json:"Logs,omitempty"`
Reserved *string `protobuf:"bytes,2,opt,name=Reserved" json:"Reserved,omitempty"`
Topic *string `protobuf:"bytes,3,opt,name=Topic" json:"Topic,omitempty"`
Source *string `protobuf:"bytes,4,opt,name=Source" json:"Source,omitempty"`
XXXUnrecognized []byte `json:"-"`
}
func (m *LogGroup) Reset() { *m = LogGroup{} }
func (m *LogGroup) String() string { return proto.CompactTextString(m) }
func (*LogGroup) ProtoMessage() {}
// Reset LogGroup
func (m *LogGroup) Reset() { *m = LogGroup{} }
// String return the compact text
func (m *LogGroup) String() string { return proto.CompactTextString(m) }
// ProtoMessage not implemented
func (*LogGroup) ProtoMessage() {}
// GetLogs return the loggroup logs
func (m *LogGroup) GetLogs() []*Log {
if m != nil {
return m.Logs
@ -82,6 +111,7 @@ func (m *LogGroup) GetLogs() []*Log {
return nil
}
// GetReserved return Reserved
func (m *LogGroup) GetReserved() string {
if m != nil && m.Reserved != nil {
return *m.Reserved
@ -89,6 +119,7 @@ func (m *LogGroup) GetReserved() string {
return ""
}
// GetTopic return Topic
func (m *LogGroup) GetTopic() string {
if m != nil && m.Topic != nil {
return *m.Topic
@ -96,6 +127,7 @@ func (m *LogGroup) GetTopic() string {
return ""
}
// GetSource return Source
func (m *LogGroup) GetSource() string {
if m != nil && m.Source != nil {
return *m.Source
@ -103,15 +135,22 @@ func (m *LogGroup) GetSource() string {
return ""
}
// LogGroupList define the LogGroups
type LogGroupList struct {
LogGroups []*LogGroup `protobuf:"bytes,1,rep,name=logGroups" json:"logGroups,omitempty"`
XXX_unrecognized []byte `json:"-"`
LogGroups []*LogGroup `protobuf:"bytes,1,rep,name=logGroups" json:"logGroups,omitempty"`
XXXUnrecognized []byte `json:"-"`
}
func (m *LogGroupList) Reset() { *m = LogGroupList{} }
func (m *LogGroupList) String() string { return proto.CompactTextString(m) }
func (*LogGroupList) ProtoMessage() {}
// Reset LogGroupList
func (m *LogGroupList) Reset() { *m = LogGroupList{} }
// String return compact text
func (m *LogGroupList) String() string { return proto.CompactTextString(m) }
// ProtoMessage not implemented
func (*LogGroupList) ProtoMessage() {}
// GetLogGroups return the LogGroups
func (m *LogGroupList) GetLogGroups() []*LogGroup {
if m != nil {
return m.LogGroups
@ -119,6 +158,7 @@ func (m *LogGroupList) GetLogGroups() []*LogGroup {
return nil
}
// Marshal the logs to byte slice
func (m *Log) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
@ -129,6 +169,7 @@ func (m *Log) Marshal() (data []byte, err error) {
return data[:n], nil
}
// MarshalTo data
func (m *Log) MarshalTo(data []byte) (int, error) {
var i int
_ = i
@ -136,11 +177,10 @@ func (m *Log) MarshalTo(data []byte) (int, error) {
_ = l
if m.Time == nil {
return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("Time")
} else {
data[i] = 0x8
i++
i = encodeVarintLog(data, i, uint64(*m.Time))
}
data[i] = 0x8
i++
i = encodeVarintLog(data, i, uint64(*m.Time))
if len(m.Contents) > 0 {
for _, msg := range m.Contents {
data[i] = 0x12
@ -153,13 +193,14 @@ func (m *Log) MarshalTo(data []byte) (int, error) {
i += n
}
}
if m.XXX_unrecognized != nil {
i += copy(data[i:], m.XXX_unrecognized)
if m.XXXUnrecognized != nil {
i += copy(data[i:], m.XXXUnrecognized)
}
return i, nil
}
func (m *Log_Content) Marshal() (data []byte, err error) {
// Marshal LogContent
func (m *LogContent) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
n, err := m.MarshalTo(data)
@ -169,33 +210,34 @@ func (m *Log_Content) Marshal() (data []byte, err error) {
return data[:n], nil
}
func (m *Log_Content) MarshalTo(data []byte) (int, error) {
// MarshalTo logcontent to data
func (m *LogContent) MarshalTo(data []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.Key == nil {
return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("Key")
} else {
data[i] = 0xa
i++
i = encodeVarintLog(data, i, uint64(len(*m.Key)))
i += copy(data[i:], *m.Key)
}
data[i] = 0xa
i++
i = encodeVarintLog(data, i, uint64(len(*m.Key)))
i += copy(data[i:], *m.Key)
if m.Value == nil {
return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("Value")
} else {
data[i] = 0x12
i++
i = encodeVarintLog(data, i, uint64(len(*m.Value)))
i += copy(data[i:], *m.Value)
}
if m.XXX_unrecognized != nil {
i += copy(data[i:], m.XXX_unrecognized)
data[i] = 0x12
i++
i = encodeVarintLog(data, i, uint64(len(*m.Value)))
i += copy(data[i:], *m.Value)
if m.XXXUnrecognized != nil {
i += copy(data[i:], m.XXXUnrecognized)
}
return i, nil
}
// Marshal LogGroup
func (m *LogGroup) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
@ -206,6 +248,7 @@ func (m *LogGroup) Marshal() (data []byte, err error) {
return data[:n], nil
}
// MarshalTo LogGroup to data
func (m *LogGroup) MarshalTo(data []byte) (int, error) {
var i int
_ = i
@ -241,12 +284,13 @@ func (m *LogGroup) MarshalTo(data []byte) (int, error) {
i = encodeVarintLog(data, i, uint64(len(*m.Source)))
i += copy(data[i:], *m.Source)
}
if m.XXX_unrecognized != nil {
i += copy(data[i:], m.XXX_unrecognized)
if m.XXXUnrecognized != nil {
i += copy(data[i:], m.XXXUnrecognized)
}
return i, nil
}
// Marshal LogGroupList
func (m *LogGroupList) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
@ -257,6 +301,7 @@ func (m *LogGroupList) Marshal() (data []byte, err error) {
return data[:n], nil
}
// MarshalTo LogGroupList to data
func (m *LogGroupList) MarshalTo(data []byte) (int, error) {
var i int
_ = i
@ -274,8 +319,8 @@ func (m *LogGroupList) MarshalTo(data []byte) (int, error) {
i += n
}
}
if m.XXX_unrecognized != nil {
i += copy(data[i:], m.XXX_unrecognized)
if m.XXXUnrecognized != nil {
i += copy(data[i:], m.XXXUnrecognized)
}
return i, nil
}
@ -307,6 +352,8 @@ func encodeVarintLog(data []byte, offset int, v uint64) int {
data[offset] = uint8(v)
return offset + 1
}
// Size return the log's size
func (m *Log) Size() (n int) {
var l int
_ = l
@ -319,13 +366,14 @@ func (m *Log) Size() (n int) {
n += 1 + l + sovLog(uint64(l))
}
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
if m.XXXUnrecognized != nil {
n += len(m.XXXUnrecognized)
}
return n
}
func (m *Log_Content) Size() (n int) {
// Size return LogContent size based on Key and Value
func (m *LogContent) Size() (n int) {
var l int
_ = l
if m.Key != nil {
@ -336,12 +384,13 @@ func (m *Log_Content) Size() (n int) {
l = len(*m.Value)
n += 1 + l + sovLog(uint64(l))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
if m.XXXUnrecognized != nil {
n += len(m.XXXUnrecognized)
}
return n
}
// Size return LogGroup size based on Logs
func (m *LogGroup) Size() (n int) {
var l int
_ = l
@ -363,12 +412,13 @@ func (m *LogGroup) Size() (n int) {
l = len(*m.Source)
n += 1 + l + sovLog(uint64(l))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
if m.XXXUnrecognized != nil {
n += len(m.XXXUnrecognized)
}
return n
}
// Size return LogGroupList size
func (m *LogGroupList) Size() (n int) {
var l int
_ = l
@ -378,8 +428,8 @@ func (m *LogGroupList) Size() (n int) {
n += 1 + l + sovLog(uint64(l))
}
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
if m.XXXUnrecognized != nil {
n += len(m.XXXUnrecognized)
}
return n
}
@ -397,6 +447,8 @@ func sovLog(x uint64) (n int) {
func sozLog(x uint64) (n int) {
return sovLog((x << 1) ^ (x >> 63))
}
// Unmarshal data to log
func (m *Log) Unmarshal(data []byte) error {
var hasFields [1]uint64
l := len(data)
@ -474,7 +526,7 @@ func (m *Log) Unmarshal(data []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Contents = append(m.Contents, &Log_Content{})
m.Contents = append(m.Contents, &LogContent{})
if err := m.Contents[len(m.Contents)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
return err
}
@ -491,7 +543,7 @@ func (m *Log) Unmarshal(data []byte) error {
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...)
m.XXXUnrecognized = append(m.XXXUnrecognized, data[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
@ -504,7 +556,9 @@ func (m *Log) Unmarshal(data []byte) error {
}
return nil
}
func (m *Log_Content) Unmarshal(data []byte) error {
// Unmarshal data to LogContent
func (m *LogContent) Unmarshal(data []byte) error {
var hasFields [1]uint64
l := len(data)
iNdEx := 0
@ -608,7 +662,7 @@ func (m *Log_Content) Unmarshal(data []byte) error {
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...)
m.XXXUnrecognized = append(m.XXXUnrecognized, data[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
@ -624,6 +678,8 @@ func (m *Log_Content) Unmarshal(data []byte) error {
}
return nil
}
// Unmarshal data to LogGroup
func (m *LogGroup) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
@ -786,7 +842,7 @@ func (m *LogGroup) Unmarshal(data []byte) error {
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...)
m.XXXUnrecognized = append(m.XXXUnrecognized, data[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
@ -796,6 +852,8 @@ func (m *LogGroup) Unmarshal(data []byte) error {
}
return nil
}
// Unmarshal data to LogGroupList
func (m *LogGroupList) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
@ -868,7 +926,7 @@ func (m *LogGroupList) Unmarshal(data []byte) error {
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...)
m.XXXUnrecognized = append(m.XXXUnrecognized, data[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
@ -878,6 +936,7 @@ func (m *LogGroupList) Unmarshal(data []byte) error {
}
return nil
}
func skipLog(data []byte) (n int, err error) {
l := len(data)
iNdEx := 0
@ -940,7 +999,7 @@ func skipLog(data []byte) (n int, err error) {
case 3:
for {
var innerWire uint64
var start int = iNdEx
var start = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowLog
@ -977,8 +1036,3 @@ func skipLog(data []byte) (n int, err error) {
}
panic("unreachable")
}
var (
ErrInvalidLengthLog = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowLog = fmt.Errorf("proto: integer overflow")
)

View File

@ -1,5 +1,6 @@
package alils
// InputDetail define log detail
type InputDetail struct {
LogType string `json:"logType"`
LogPath string `json:"logPath"`
@ -14,11 +15,13 @@ type InputDetail struct {
TopicFormat string `json:"topicFormat"`
}
// OutputDetail define the output detail
type OutputDetail struct {
Endpoint string `json:"endpoint"`
LogStoreName string `json:"logstoreName"`
}
// LogConfig define Log Config
type LogConfig struct {
Name string `json:"configName"`
InputType string `json:"inputType"`

View File

@ -1,5 +1,5 @@
/*
Package sls implements the SDK(v0.5.0) of Simple Log Service(abbr. SLS).
Package alils implements the SDK(v0.5.0) of Simple Log Service(abbr. SLS).
For more description about SLS, please read this article:
http://gitlab.alibaba-inc.com/sls/doc.
@ -20,19 +20,20 @@ type errorMessage struct {
Message string `json:"errorMessage"`
}
// LogProject Define the Ali Project detail
type LogProject struct {
Name string // Project name
Endpoint string // IP or hostname of SLS endpoint
AccessKeyId string
AccessKeyID string
AccessKeySecret string
}
// NewLogProject creates a new SLS project.
func NewLogProject(name, endpoint, accessKeyId, accessKeySecret string) (p *LogProject, err error) {
func NewLogProject(name, endpoint, AccessKeyID, accessKeySecret string) (p *LogProject, err error) {
p = &LogProject{
Name: name,
Endpoint: endpoint,
AccessKeyId: accessKeyId,
AccessKeyID: AccessKeyID,
AccessKeySecret: accessKeySecret,
}
return p, nil

View File

@ -12,6 +12,7 @@ import (
"github.com/gogo/protobuf/proto"
)
// LogStore Store the logs
type LogStore struct {
Name string `json:"logstoreName"`
TTL int
@ -23,6 +24,7 @@ type LogStore struct {
project *LogProject
}
// Shard define the Log Shard
type Shard struct {
ShardID int `json:"shardID"`
}
@ -116,16 +118,16 @@ func (s *LogStore) PutLogs(lg *LogGroup) (err error) {
return
}
// GetCursor gets log cursor of one shard specified by shardId.
// GetCursor gets log cursor of one shard specified by shardID.
// The from can be in three form: a) unix timestamp in seccond, b) "begin", c) "end".
// For more detail please read: http://gitlab.alibaba-inc.com/sls/doc/blob/master/api/shard.md#logstore
func (s *LogStore) GetCursor(shardId int, from string) (cursor string, err error) {
func (s *LogStore) GetCursor(shardID int, from string) (cursor string, err error) {
h := map[string]string{
"x-sls-bodyrawsize": "0",
}
uri := fmt.Sprintf("/logstores/%v/shards/%v?type=cursor&from=%v",
s.Name, shardId, from)
s.Name, shardID, from)
r, err := request(s.project, "GET", uri, h, nil)
if err != nil {
@ -163,10 +165,10 @@ func (s *LogStore) GetCursor(shardId int, from string) (cursor string, err error
return
}
// GetLogsBytes gets logs binary data from shard specified by shardId according cursor.
// GetLogsBytes gets logs binary data from shard specified by shardID according cursor.
// The logGroupMaxCount is the max number of logGroup could be returned.
// The nextCursor is the next curosr can be used to read logs at next time.
func (s *LogStore) GetLogsBytes(shardId int, cursor string,
func (s *LogStore) GetLogsBytes(shardID int, cursor string,
logGroupMaxCount int) (out []byte, nextCursor string, err error) {
h := map[string]string{
@ -176,7 +178,7 @@ func (s *LogStore) GetLogsBytes(shardId int, cursor string,
}
uri := fmt.Sprintf("/logstores/%v/shards/%v?type=logs&cursor=%v&count=%v",
s.Name, shardId, cursor, logGroupMaxCount)
s.Name, shardID, cursor, logGroupMaxCount)
r, err := request(s.project, "GET", uri, h, nil)
if err != nil {
@ -249,13 +251,13 @@ func LogsBytesDecode(data []byte) (gl *LogGroupList, err error) {
return
}
// GetLogs gets logs from shard specified by shardId according cursor.
// GetLogs gets logs from shard specified by shardID according cursor.
// The logGroupMaxCount is the max number of logGroup could be returned.
// The nextCursor is the next curosr can be used to read logs at next time.
func (s *LogStore) GetLogs(shardId int, cursor string,
func (s *LogStore) GetLogs(shardID int, cursor string,
logGroupMaxCount int) (gl *LogGroupList, nextCursor string, err error) {
out, nextCursor, err := s.GetLogsBytes(shardId, cursor, logGroupMaxCount)
out, nextCursor, err := s.GetLogsBytes(shardID, cursor, logGroupMaxCount)
if err != nil {
return
}

View File

@ -8,18 +8,20 @@ import (
"net/http/httputil"
)
type MachinGroupAttribute struct {
// MachineGroupAttribute define the Attribute
type MachineGroupAttribute struct {
ExternalName string `json:"externalName"`
TopicName string `json:"groupTopic"`
}
// MachineGroup define the machine Group
type MachineGroup struct {
Name string `json:"groupName"`
Type string `json:"groupType"`
MachineIdType string `json:"machineIdentifyType"`
MachineIdList []string `json:"machineList"`
MachineIDType string `json:"machineIdentifyType"`
MachineIDList []string `json:"machineList"`
Attribute MachinGroupAttribute `json:"groupAttribute"`
Attribute MachineGroupAttribute `json:"groupAttribute"`
CreateTime uint32
LastModifyTime uint32
@ -27,12 +29,14 @@ type MachineGroup struct {
project *LogProject
}
// Machine define the Machine
type Machine struct {
IP string
UniqueId string `json:"machine-uniqueid"`
UserdefinedId string `json:"userdefined-id"`
UniqueID string `json:"machine-uniqueid"`
UserdefinedID string `json:"userdefined-id"`
}
// MachineList define the Machine List
type MachineList struct {
Total int
Machines []*Machine

View File

@ -33,12 +33,12 @@ func request(project *LogProject, method, uri string, headers map[string]string,
}
// Calc Authorization
// Authorization = "SLS <AccessKeyId>:<Signature>"
// Authorization = "SLS <AccessKeyID>:<Signature>"
digest, err := signature(project, method, uri, headers)
if err != nil {
return
}
auth := fmt.Sprintf("SLS %v:%v", project.AccessKeyId, digest)
auth := fmt.Sprintf("SLS %v:%v", project.AccessKeyID, digest)
headers["Authorization"] = auth
// Initialize http request

View File

@ -361,7 +361,7 @@ func isParameterChar(b byte) bool {
}
func (cw *ansiColorWriter) Write(p []byte) (int, error) {
r, nw, first, last := 0, 0, 0, 0
var r, nw, first, last int
if cw.mode != DiscardNonColorEscSeq {
cw.state = outsideCsiCode
cw.resetBuffer()

View File

@ -170,7 +170,7 @@ func (w *fileLogWriter) initFd() error {
fd := w.fileWriter
fInfo, err := fd.Stat()
if err != nil {
return fmt.Errorf("get stat err: %s\n", err)
return fmt.Errorf("get stat err: %s", err)
}
w.maxSizeCurSize = int(fInfo.Size())
w.dailyOpenTime = time.Now()
@ -259,7 +259,7 @@ func (w *fileLogWriter) doRotate(logTime time.Time) error {
}
// return error if the last file checked still existed
if err == nil {
return fmt.Errorf("Rotate: Cannot find free log number to rename %s\n", w.Filename)
return fmt.Errorf("Rotate: Cannot find free log number to rename %s", w.Filename)
}
// close fileWriter before rename
@ -268,6 +268,9 @@ func (w *fileLogWriter) doRotate(logTime time.Time) error {
// Rename the file to its new found name
// even if occurs error,we MUST guarantee to restart new logger
err = os.Rename(w.Filename, fName)
if err != nil {
goto RESTART_LOGGER
}
err = os.Chmod(fName, os.FileMode(0440))
// re-start logger
RESTART_LOGGER:
@ -276,13 +279,12 @@ RESTART_LOGGER:
go w.deleteOldLog()
if startLoggerErr != nil {
return fmt.Errorf("Rotate StartLogger: %s\n", startLoggerErr)
return fmt.Errorf("Rotate StartLogger: %s", startLoggerErr)
}
if err != nil {
return fmt.Errorf("Rotate: %s\n", err)
return fmt.Errorf("Rotate: %s", err)
}
return nil
}
func (w *fileLogWriter) deleteOldLog() {

View File

@ -492,9 +492,9 @@ func (bl *BeeLogger) flush() {
}
// beeLogger references the used application logger.
var beeLogger *BeeLogger = NewLogger()
var beeLogger = NewLogger()
// GetLogger returns the default BeeLogger
// GetBeeLogger returns the default BeeLogger
func GetBeeLogger() *BeeLogger {
return beeLogger
}
@ -534,6 +534,7 @@ func Reset() {
beeLogger.Reset()
}
// Async set the beelogger with Async mode and hold msglen messages
func Async(msgLen ...int64) *BeeLogger {
return beeLogger.Async(msgLen...)
}

View File

@ -139,6 +139,11 @@ var (
reset = string([]byte{27, 91, 48, 109})
)
// ColorByStatus return color by http code
// 2xx return Green
// 3xx return White
// 4xx return Yellow
// 5xx return Red
func ColorByStatus(cond bool, code int) string {
switch {
case code >= 200 && code < 300:
@ -152,6 +157,14 @@ func ColorByStatus(cond bool, code int) string {
}
}
// ColorByMethod return color by http code
// GET return Blue
// POST return Cyan
// PUT return Yellow
// DELETE return Red
// PATCH return Green
// HEAD return Magenta
// OPTIONS return WHITE
func ColorByMethod(cond bool, method string) string {
switch method {
case "GET":
@ -173,10 +186,10 @@ func ColorByMethod(cond bool, method string) string {
}
}
// Guard Mutex to guarantee atomicity of W32Debug(string) function
// Guard Mutex to guarantee atomic of W32Debug(string) function
var mu sync.Mutex
// Helper method to output colored logs in Windows terminals
// W32Debug Helper method to output colored logs in Windows terminals
func W32Debug(msg string) {
mu.Lock()
defer mu.Unlock()

View File

@ -507,10 +507,9 @@ func (d *dbBase) InsertOrUpdate(q dbQuerier, mi *modelInfo, ind reflect.Value, a
case DRPostgres:
if len(args) == 0 {
return 0, fmt.Errorf("`%s` use InsertOrUpdate must have a conflict column", a.DriverName)
} else {
args0 = strings.ToLower(args[0])
iouStr = fmt.Sprintf("ON CONFLICT (%s) DO UPDATE SET", args0)
}
args0 = strings.ToLower(args[0])
iouStr = fmt.Sprintf("ON CONFLICT (%s) DO UPDATE SET", args0)
default:
return 0, fmt.Errorf("`%s` nonsupport InsertOrUpdate in beego", a.DriverName)
}
@ -834,7 +833,11 @@ func (d *dbBase) DeleteBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Con
if err := rs.Scan(&ref); err != nil {
return 0, err
}
args = append(args, reflect.ValueOf(ref).Interface())
pkValue, err := d.convertValueFromDB(mi.fields.pk, reflect.ValueOf(ref).Interface(), tz)
if err != nil {
return 0, err
}
args = append(args, pkValue)
cnt++
}
@ -1110,7 +1113,7 @@ func (d *dbBase) Count(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condition
// generate sql with replacing operator string placeholders and replaced values.
func (d *dbBase) GenerateOperatorSQL(mi *modelInfo, fi *fieldInfo, operator string, args []interface{}, tz *time.Location) (string, []interface{}) {
sql := ""
var sql string
params := getFlatParams(fi, args, tz)
if len(params) == 0 {
@ -1733,7 +1736,7 @@ func (d *dbBase) TableQuote() string {
return "`"
}
// replace value placeholer in parametered sql string.
// replace value placeholder in parametered sql string.
func (d *dbBase) ReplaceMarks(query *string) {
// default use `?` as mark, do nothing
}

View File

@ -250,7 +250,7 @@ func RegisterDriver(driverName string, typ DriverType) error {
drivers[driverName] = typ
} else {
if t != typ {
return fmt.Errorf("driverName `%s` db driver already registered and is other type\n", driverName)
return fmt.Errorf("driverName `%s` db driver already registered and is other type", driverName)
}
}
return nil
@ -261,7 +261,7 @@ func SetDataBaseTZ(aliasName string, tz *time.Location) error {
if al, ok := dataBaseCache.get(aliasName); ok {
al.TZ = tz
} else {
return fmt.Errorf("DataBase alias name `%s` not registered\n", aliasName)
return fmt.Errorf("DataBase alias name `%s` not registered", aliasName)
}
return nil
}
@ -296,5 +296,5 @@ func GetDB(aliasNames ...string) (*sql.DB, error) {
if ok {
return al.DB, nil
}
return nil, fmt.Errorf("DataBase of alias name `%s` not found\n", name)
return nil, fmt.Errorf("DataBase of alias name `%s` not found", name)
}

View File

@ -103,8 +103,7 @@ func (d *dbBaseMysql) IndexExists(db dbQuerier, table string, name string) bool
// If no will insert
// Add "`" for mysql sql building
func (d *dbBaseMysql) InsertOrUpdate(q dbQuerier, mi *modelInfo, ind reflect.Value, a *alias, args ...string) (int64, error) {
iouStr := ""
var iouStr string
argsMap := map[string]string{}
iouStr = "ON DUPLICATE KEY UPDATE"

View File

@ -75,7 +75,7 @@ func registerModel(PrefixOrSuffix string, model interface{}, isPrefix bool) {
}
if mi.fields.pk == nil {
fmt.Printf("<orm.RegisterModel> `%s` need a primary key field, default use 'id' if not set\n", name)
fmt.Printf("<orm.RegisterModel> `%s` needs a primary key field, default is to use 'id' if not set\n", name)
os.Exit(2)
}

View File

@ -107,7 +107,7 @@ func (o *orm) getMiInd(md interface{}, needPtr bool) (mi *modelInfo, ind reflect
if mi, ok := modelCache.getByFullName(name); ok {
return mi, ind
}
panic(fmt.Errorf("<Ormer> table: `%s` not found, maybe not RegisterModel", name))
panic(fmt.Errorf("<Ormer> table: `%s` not found, make sure it was registered with `RegisterModel()`", name))
}
// get field info from model info by given field name
@ -420,7 +420,7 @@ func (o *orm) getRelQs(md interface{}, mi *modelInfo, fi *fieldInfo) *querySet {
// table name can be string or struct.
// e.g. QueryTable("user"), QueryTable(&user{}) or QueryTable((*User)(nil)),
func (o *orm) QueryTable(ptrStructOrTableName interface{}) (qs QuerySeter) {
name := ""
var name string
if table, ok := ptrStructOrTableName.(string); ok {
name = snakeString(table)
if mi, ok := modelCache.get(name); ok {

View File

@ -493,19 +493,33 @@ func (o *rawSet) QueryRows(containers ...interface{}) (int64, error) {
}
}
} else {
for i := 0; i < ind.NumField(); i++ {
f := ind.Field(i)
fe := ind.Type().Field(i)
_, tags := parseStructTag(fe.Tag.Get(defaultStructTagName))
var col string
if col = tags["column"]; col == "" {
col = snakeString(fe.Name)
}
if v, ok := columnsMp[col]; ok {
value := reflect.ValueOf(v).Elem().Interface()
o.setFieldValue(f, value)
// define recursive function
var recursiveSetField func(rv reflect.Value)
recursiveSetField = func(rv reflect.Value) {
for i := 0; i < rv.NumField(); i++ {
f := rv.Field(i)
fe := rv.Type().Field(i)
// check if the field is a Struct
// recursive the Struct type
if fe.Type.Kind() == reflect.Struct {
recursiveSetField(f)
}
_, tags := parseStructTag(fe.Tag.Get(defaultStructTagName))
var col string
if col = tags["column"]; col == "" {
col = snakeString(fe.Name)
}
if v, ok := columnsMp[col]; ok {
value := reflect.ValueOf(v).Elem().Interface()
o.setFieldValue(f, value)
}
}
}
// init call the recursive function
recursiveSetField(ind)
}
if eTyps[0].Kind() == reflect.Ptr {
@ -671,7 +685,7 @@ func (o *rawSet) queryRowsTo(container interface{}, keyCol, valueCol string) (in
ind *reflect.Value
)
typ := 0
var typ int
switch container.(type) {
case *Params:
typ = 1

View File

@ -135,7 +135,7 @@ func getCaller(skip int) string {
if i := strings.LastIndex(funName, "."); i > -1 {
funName = funName[i+1:]
}
return fmt.Sprintf("%s:%d: \n%s", fn, line, strings.Join(codes, "\n"))
return fmt.Sprintf("%s:%s:%d: \n%s", fn, funName, line, strings.Join(codes, "\n"))
}
func throwFail(t *testing.T, err error, args ...interface{}) {
@ -1014,6 +1014,8 @@ func TestAll(t *testing.T) {
var users3 []*User
qs = dORM.QueryTable("user")
num, err = qs.Filter("user_name", "nothing").All(&users3)
throwFailNow(t, err)
throwFailNow(t, AssertIs(num, 0))
throwFailNow(t, AssertIs(users3 == nil, false))
}
@ -1138,6 +1140,7 @@ func TestRelatedSel(t *testing.T) {
}
err = qs.Filter("user_name", "nobody").RelatedSel("profile").One(&user)
throwFail(t, err)
throwFail(t, AssertIs(num, 1))
throwFail(t, AssertIs(user.Profile, nil))
@ -1246,20 +1249,24 @@ func TestLoadRelated(t *testing.T) {
num, err = dORM.LoadRelated(&user, "Posts", true)
throwFailNow(t, err)
throwFailNow(t, AssertIs(num, 2))
throwFailNow(t, AssertIs(len(user.Posts), 2))
throwFailNow(t, AssertIs(user.Posts[0].User.UserName, "astaxie"))
num, err = dORM.LoadRelated(&user, "Posts", true, 1)
throwFailNow(t, err)
throwFailNow(t, AssertIs(num, 1))
throwFailNow(t, AssertIs(len(user.Posts), 1))
num, err = dORM.LoadRelated(&user, "Posts", true, 0, 0, "-Id")
throwFailNow(t, err)
throwFailNow(t, AssertIs(num, 2))
throwFailNow(t, AssertIs(len(user.Posts), 2))
throwFailNow(t, AssertIs(user.Posts[0].Title, "Formatting"))
num, err = dORM.LoadRelated(&user, "Posts", true, 1, 1, "Id")
throwFailNow(t, err)
throwFailNow(t, AssertIs(num, 1))
throwFailNow(t, AssertIs(len(user.Posts), 1))
throwFailNow(t, AssertIs(user.Posts[0].Title, "Formatting"))
@ -1654,6 +1661,13 @@ func TestRawQueryRow(t *testing.T) {
throwFail(t, AssertIs(pid, nil))
}
// user_profile table
type userProfile struct {
User
Age int
Money float64
}
func TestQueryRows(t *testing.T) {
Q := dDbBaser.TableQuote()
@ -1724,6 +1738,19 @@ func TestQueryRows(t *testing.T) {
throwFailNow(t, AssertIs(usernames[1], "astaxie"))
throwFailNow(t, AssertIs(ids[2], 4))
throwFailNow(t, AssertIs(usernames[2], "nobody"))
//test query rows by nested struct
var l []userProfile
query = fmt.Sprintf("SELECT * FROM %suser_profile%s LEFT JOIN %suser%s ON %suser_profile%s.%sid%s = %suser%s.%sid%s", Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q)
num, err = dORM.Raw(query).QueryRows(&l)
throwFailNow(t, err)
throwFailNow(t, AssertIs(num, 2))
throwFailNow(t, AssertIs(len(l), 2))
throwFailNow(t, AssertIs(l[0].UserName, "slene"))
throwFailNow(t, AssertIs(l[0].Age, 28))
throwFailNow(t, AssertIs(l[1].UserName, "astaxie"))
throwFailNow(t, AssertIs(l[1].Age, 30))
}
func TestRawValues(t *testing.T) {
@ -1976,6 +2003,7 @@ func TestReadOrCreate(t *testing.T) {
created, pk, err := dORM.ReadOrCreate(u, "UserName")
throwFail(t, err)
throwFail(t, AssertIs(created, true))
throwFail(t, AssertIs(u.ID, pk))
throwFail(t, AssertIs(u.UserName, "Kyle"))
throwFail(t, AssertIs(u.Email, "kylemcc@gmail.com"))
throwFail(t, AssertIs(u.Password, "other_pass"))
@ -2130,13 +2158,13 @@ func TestUintPk(t *testing.T) {
Name: name,
}
created, pk, err := dORM.ReadOrCreate(u, "ID")
created, _, err := dORM.ReadOrCreate(u, "ID")
throwFail(t, err)
throwFail(t, AssertIs(created, true))
throwFail(t, AssertIs(u.Name, name))
nu := &UintPk{ID: 8}
created, pk, err = dORM.ReadOrCreate(nu, "ID")
created, pk, err := dORM.ReadOrCreate(nu, "ID")
throwFail(t, err)
throwFail(t, AssertIs(created, false))
throwFail(t, AssertIs(nu.ID, u.ID))

210
parser.go
View File

@ -24,9 +24,13 @@ import (
"io/ioutil"
"os"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
"unicode"
"github.com/astaxie/beego/context/param"
"github.com/astaxie/beego/logs"
"github.com/astaxie/beego/utils"
)
@ -35,6 +39,7 @@ var globalRouterTemplate = `package routers
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/context/param"
)
func init() {
@ -81,7 +86,7 @@ func parserPkg(pkgRealpath, pkgpath string) error {
if specDecl.Recv != nil {
exp, ok := specDecl.Recv.List[0].Type.(*ast.StarExpr) // Check that the type is correct first beforing throwing to parser
if ok {
parserComments(specDecl.Doc, specDecl.Name.String(), fmt.Sprint(exp.X), pkgpath)
parserComments(specDecl, fmt.Sprint(exp.X), pkgpath)
}
}
}
@ -93,44 +98,169 @@ func parserPkg(pkgRealpath, pkgpath string) error {
return nil
}
func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpath string) error {
if comments != nil && comments.List != nil {
for _, c := range comments.List {
t := strings.TrimSpace(strings.TrimLeft(c.Text, "//"))
if strings.HasPrefix(t, "@router") {
elements := strings.TrimLeft(t, "@router ")
e1 := strings.SplitN(elements, " ", 2)
if len(e1) < 1 {
return errors.New("you should has router information")
}
key := pkgpath + ":" + controllerName
cc := ControllerComments{}
cc.Method = funcName
cc.Router = e1[0]
if len(e1) == 2 && e1[1] != "" {
e1 = strings.SplitN(e1[1], " ", 2)
if len(e1) >= 1 {
cc.AllowHTTPMethods = strings.Split(strings.Trim(e1[0], "[]"), ",")
} else {
cc.AllowHTTPMethods = append(cc.AllowHTTPMethods, "get")
}
} else {
cc.AllowHTTPMethods = append(cc.AllowHTTPMethods, "get")
}
if len(e1) == 2 && e1[1] != "" {
keyval := strings.Split(strings.Trim(e1[1], "[]"), " ")
for _, kv := range keyval {
kk := strings.Split(kv, ":")
cc.Params = append(cc.Params, map[string]string{strings.Join(kk[:len(kk)-1], ":"): kk[len(kk)-1]})
}
}
genInfoList[key] = append(genInfoList[key], cc)
}
type parsedComment struct {
routerPath string
methods []string
params map[string]parsedParam
}
type parsedParam struct {
name string
datatype string
location string
defValue string
required bool
}
func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error {
if f.Doc != nil {
parsedComment, err := parseComment(f.Doc.List)
if err != nil {
return err
}
if parsedComment.routerPath != "" {
key := pkgpath + ":" + controllerName
cc := ControllerComments{}
cc.Method = f.Name.String()
cc.Router = parsedComment.routerPath
cc.AllowHTTPMethods = parsedComment.methods
cc.MethodParams = buildMethodParams(f.Type.Params.List, parsedComment)
genInfoList[key] = append(genInfoList[key], cc)
}
}
return nil
}
func buildMethodParams(funcParams []*ast.Field, pc *parsedComment) []*param.MethodParam {
result := make([]*param.MethodParam, 0, len(funcParams))
for _, fparam := range funcParams {
methodParam := buildMethodParam(fparam, pc)
result = append(result, methodParam)
}
return result
}
func buildMethodParam(fparam *ast.Field, pc *parsedComment) *param.MethodParam {
options := []param.MethodParamOption{}
name := fparam.Names[0].Name
if cparam, ok := pc.params[name]; ok {
//Build param from comment info
name = cparam.name
if cparam.required {
options = append(options, param.IsRequired)
}
switch cparam.location {
case "body":
options = append(options, param.InBody)
case "header":
options = append(options, param.InHeader)
case "path":
options = append(options, param.InPath)
}
if cparam.defValue != "" {
options = append(options, param.Default(cparam.defValue))
}
} else {
if paramInPath(name, pc.routerPath) {
options = append(options, param.InPath)
}
}
return param.New(name, options...)
}
func paramInPath(name, route string) bool {
return strings.HasSuffix(route, ":"+name) ||
strings.Contains(route, ":"+name+"/")
}
var routeRegex = regexp.MustCompile(`@router\s+(\S+)(?:\s+\[(\S+)\])?`)
func parseComment(lines []*ast.Comment) (pc *parsedComment, err error) {
pc = &parsedComment{}
for _, c := range lines {
t := strings.TrimSpace(strings.TrimLeft(c.Text, "//"))
if strings.HasPrefix(t, "@router") {
matches := routeRegex.FindStringSubmatch(t)
if len(matches) == 3 {
pc.routerPath = matches[1]
methods := matches[2]
if methods == "" {
pc.methods = []string{"get"}
//pc.hasGet = true
} else {
pc.methods = strings.Split(methods, ",")
//pc.hasGet = strings.Contains(methods, "get")
}
} else {
return nil, errors.New("Router information is missing")
}
} else if strings.HasPrefix(t, "@Param") {
pv := getparams(strings.TrimSpace(strings.TrimLeft(t, "@Param")))
if len(pv) < 4 {
logs.Error("Invalid @Param format. Needs at least 4 parameters")
}
p := parsedParam{}
names := strings.SplitN(pv[0], "=>", 2)
p.name = names[0]
funcParamName := p.name
if len(names) > 1 {
funcParamName = names[1]
}
p.location = pv[1]
p.datatype = pv[2]
switch len(pv) {
case 5:
p.required, _ = strconv.ParseBool(pv[3])
case 6:
p.defValue = pv[3]
p.required, _ = strconv.ParseBool(pv[4])
}
if pc.params == nil {
pc.params = map[string]parsedParam{}
}
pc.params[funcParamName] = p
}
}
return
}
// direct copy from bee\g_docs.go
// analisys params return []string
// @Param query form string true "The email for login"
// [query form string true "The email for login"]
func getparams(str string) []string {
var s []rune
var j int
var start bool
var r []string
var quoted int8
for _, c := range str {
if unicode.IsSpace(c) && quoted == 0 {
if !start {
continue
} else {
start = false
j++
r = append(r, string(s))
s = make([]rune, 0)
continue
}
}
start = true
if c == '"' {
quoted ^= 1
continue
}
s = append(s, c)
}
if len(s) > 0 {
r = append(r, string(s))
}
return r
}
func genRouterCode(pkgRealpath string) {
os.Mkdir(getRouterDir(pkgRealpath), 0755)
logs.Info("generate router from comments")
@ -163,12 +293,24 @@ func genRouterCode(pkgRealpath string) {
}
params = strings.TrimRight(params, ",") + "}"
}
methodParams := "param.Make("
if len(c.MethodParams) > 0 {
lines := make([]string, 0, len(c.MethodParams))
for _, m := range c.MethodParams {
lines = append(lines, fmt.Sprint(m))
}
methodParams += "\n " +
strings.Join(lines, ",\n ") +
",\n "
}
methodParams += ")"
globalinfo = globalinfo + `
beego.GlobalControllerRouter["` + k + `"] = append(beego.GlobalControllerRouter["` + k + `"],
beego.ControllerComments{
Method: "` + strings.TrimSpace(c.Method) + `",
` + "Router: `" + c.Router + "`" + `,
AllowHTTPMethods: ` + allmethod + `,
MethodParams: ` + methodParams + `,
Params: ` + params + `})
`
}

86
plugins/authz/authz.go Normal file
View File

@ -0,0 +1,86 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package authz provides handlers to enable ACL, RBAC, ABAC authorization support.
// Simple Usage:
// import(
// "github.com/astaxie/beego"
// "github.com/astaxie/beego/plugins/authz"
// "github.com/hsluoyz/casbin"
// )
//
// func main(){
// // mediate the access for every request
// beego.InsertFilter("*", beego.BeforeRouter, authz.NewAuthorizer(casbin.NewEnforcer("authz_model.conf", "authz_policy.csv")))
// beego.Run()
// }
//
//
// Advanced Usage:
//
// func main(){
// e := casbin.NewEnforcer("authz_model.conf", "")
// e.AddRoleForUser("alice", "admin")
// e.AddPolicy(...)
//
// beego.InsertFilter("*", beego.BeforeRouter, authz.NewAuthorizer(e))
// beego.Run()
// }
package authz
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
"github.com/hsluoyz/casbin"
"net/http"
)
// NewAuthorizer returns the authorizer.
// Use a casbin enforcer as input
func NewAuthorizer(e *casbin.Enforcer) beego.FilterFunc {
return func(ctx *context.Context) {
a := &BasicAuthorizer{enforcer: e}
if !a.CheckPermission(ctx.Request) {
a.RequirePermission(ctx.ResponseWriter)
}
}
}
// BasicAuthorizer stores the casbin handler
type BasicAuthorizer struct {
enforcer *casbin.Enforcer
}
// GetUserName gets the user name from the request.
// Currently, only HTTP basic authentication is supported
func (a *BasicAuthorizer) GetUserName(r *http.Request) string {
username, _, _ := r.BasicAuth()
return username
}
// CheckPermission checks the user/method/path combination from the request.
// Returns true (permission granted) or false (permission forbidden)
func (a *BasicAuthorizer) CheckPermission(r *http.Request) bool {
user := a.GetUserName(r)
method := r.Method
path := r.URL.Path
return a.enforcer.Enforce(user, path, method)
}
// RequirePermission returns the 403 Forbidden to the client
func (a *BasicAuthorizer) RequirePermission(w http.ResponseWriter) {
w.WriteHeader(403)
w.Write([]byte("403 Forbidden\n"))
}

View File

@ -0,0 +1,14 @@
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*")

View File

@ -0,0 +1,7 @@
p, alice, /dataset1/*, GET
p, alice, /dataset1/resource1, POST
p, bob, /dataset2/resource1, *
p, bob, /dataset2/resource2, GET
p, bob, /dataset2/folder1/*, POST
p, dataset1_admin, /dataset1/*, *
g, cathy, dataset1_admin
1 p, alice, /dataset1/*, GET
2 p, alice, /dataset1/resource1, POST
3 p, bob, /dataset2/resource1, *
4 p, bob, /dataset2/resource2, GET
5 p, bob, /dataset2/folder1/*, POST
6 p, dataset1_admin, /dataset1/*, *
7 g, cathy, dataset1_admin

107
plugins/authz/authz_test.go Normal file
View File

@ -0,0 +1,107 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package authz
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
"github.com/astaxie/beego/plugins/auth"
"github.com/hsluoyz/casbin"
"net/http"
"net/http/httptest"
"testing"
)
func testRequest(t *testing.T, handler *beego.ControllerRegister, user string, path string, method string, code int) {
r, _ := http.NewRequest(method, path, nil)
r.SetBasicAuth(user, "123")
w := httptest.NewRecorder()
handler.ServeHTTP(w, r)
if w.Code != code {
t.Errorf("%s, %s, %s: %d, supposed to be %d", user, path, method, w.Code, code)
}
}
func TestBasic(t *testing.T) {
handler := beego.NewControllerRegister()
handler.InsertFilter("*", beego.BeforeRouter, auth.Basic("alice", "123"))
handler.InsertFilter("*", beego.BeforeRouter, NewAuthorizer(casbin.NewEnforcer("authz_model.conf", "authz_policy.csv")))
handler.Any("*", func(ctx *context.Context) {
ctx.Output.SetStatus(200)
})
testRequest(t, handler, "alice", "/dataset1/resource1", "GET", 200)
testRequest(t, handler, "alice", "/dataset1/resource1", "POST", 200)
testRequest(t, handler, "alice", "/dataset1/resource2", "GET", 200)
testRequest(t, handler, "alice", "/dataset1/resource2", "POST", 403)
}
func TestPathWildcard(t *testing.T) {
handler := beego.NewControllerRegister()
handler.InsertFilter("*", beego.BeforeRouter, auth.Basic("bob", "123"))
handler.InsertFilter("*", beego.BeforeRouter, NewAuthorizer(casbin.NewEnforcer("authz_model.conf", "authz_policy.csv")))
handler.Any("*", func(ctx *context.Context) {
ctx.Output.SetStatus(200)
})
testRequest(t, handler, "bob", "/dataset2/resource1", "GET", 200)
testRequest(t, handler, "bob", "/dataset2/resource1", "POST", 200)
testRequest(t, handler, "bob", "/dataset2/resource1", "DELETE", 200)
testRequest(t, handler, "bob", "/dataset2/resource2", "GET", 200)
testRequest(t, handler, "bob", "/dataset2/resource2", "POST", 403)
testRequest(t, handler, "bob", "/dataset2/resource2", "DELETE", 403)
testRequest(t, handler, "bob", "/dataset2/folder1/item1", "GET", 403)
testRequest(t, handler, "bob", "/dataset2/folder1/item1", "POST", 200)
testRequest(t, handler, "bob", "/dataset2/folder1/item1", "DELETE", 403)
testRequest(t, handler, "bob", "/dataset2/folder1/item2", "GET", 403)
testRequest(t, handler, "bob", "/dataset2/folder1/item2", "POST", 200)
testRequest(t, handler, "bob", "/dataset2/folder1/item2", "DELETE", 403)
}
func TestRBAC(t *testing.T) {
handler := beego.NewControllerRegister()
handler.InsertFilter("*", beego.BeforeRouter, auth.Basic("cathy", "123"))
e := casbin.NewEnforcer("authz_model.conf", "authz_policy.csv")
handler.InsertFilter("*", beego.BeforeRouter, NewAuthorizer(e))
handler.Any("*", func(ctx *context.Context) {
ctx.Output.SetStatus(200)
})
// cathy can access all /dataset1/* resources via all methods because it has the dataset1_admin role.
testRequest(t, handler, "cathy", "/dataset1/item", "GET", 200)
testRequest(t, handler, "cathy", "/dataset1/item", "POST", 200)
testRequest(t, handler, "cathy", "/dataset1/item", "DELETE", 200)
testRequest(t, handler, "cathy", "/dataset2/item", "GET", 403)
testRequest(t, handler, "cathy", "/dataset2/item", "POST", 403)
testRequest(t, handler, "cathy", "/dataset2/item", "DELETE", 403)
// delete all roles on user cathy, so cathy cannot access any resources now.
e.DeleteRolesForUser("cathy")
testRequest(t, handler, "cathy", "/dataset1/item", "GET", 403)
testRequest(t, handler, "cathy", "/dataset1/item", "POST", 403)
testRequest(t, handler, "cathy", "/dataset1/item", "DELETE", 403)
testRequest(t, handler, "cathy", "/dataset2/item", "GET", 403)
testRequest(t, handler, "cathy", "/dataset2/item", "POST", 403)
testRequest(t, handler, "cathy", "/dataset2/item", "DELETE", 403)
}

View File

@ -23,7 +23,7 @@ import (
// PolicyFunc defines a policy function which is invoked before the controller handler is executed.
type PolicyFunc func(*context.Context)
// FindRouter Find Router info for URL
// FindPolicy Find Router info for URL
func (p *ControllerRegister) FindPolicy(cont *context.Context) []PolicyFunc {
var urlPath = cont.Input.URL()
if !BConfig.RouterCaseSensitive {
@ -71,7 +71,7 @@ func (p *ControllerRegister) addToPolicy(method, pattern string, r ...PolicyFunc
}
}
// Register new policy in beego
// Policy Register new policy in beego
func Policy(pattern, method string, policy ...PolicyFunc) {
BeeApp.Handlers.addToPolicy(method, pattern, policy...)
}

View File

@ -27,6 +27,7 @@ import (
"time"
beecontext "github.com/astaxie/beego/context"
"github.com/astaxie/beego/context/param"
"github.com/astaxie/beego/logs"
"github.com/astaxie/beego/toolbox"
"github.com/astaxie/beego/utils"
@ -116,6 +117,7 @@ type ControllerInfo struct {
handler http.Handler
runFunction FilterFunc
routerType int
methodParams []*param.MethodParam
}
// ControllerRegister containers registered router rules, controller handlers and filters.
@ -151,6 +153,10 @@ func NewControllerRegister() *ControllerRegister {
// Add("/api",&RestController{},"get,post:ApiFunc"
// Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc")
func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingMethods ...string) {
p.addWithMethodParams(pattern, c, nil, mappingMethods...)
}
func (p *ControllerRegister) addWithMethodParams(pattern string, c ControllerInterface, methodParams []*param.MethodParam, mappingMethods ...string) {
reflectVal := reflect.ValueOf(c)
t := reflect.Indirect(reflectVal).Type()
methods := make(map[string]string)
@ -181,6 +187,7 @@ func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingM
route.methods = methods
route.routerType = routerTypeBeego
route.controllerType = t
route.methodParams = methodParams
if len(methods) == 0 {
for _, m := range HTTPMETHOD {
p.addToRouter(m, pattern, route)
@ -245,7 +252,7 @@ func (p *ControllerRegister) Include(cList ...ControllerInterface) {
key := t.PkgPath() + ":" + t.Name()
if comm, ok := GlobalControllerRouter[key]; ok {
for _, a := range comm {
p.Add(a.Router, c, strings.Join(a.AllowHTTPMethods, ",")+":"+a.Method)
p.addWithMethodParams(a.Router, c, a.MethodParams, strings.Join(a.AllowHTTPMethods, ",")+":"+a.Method)
}
}
}
@ -624,11 +631,12 @@ func (p *ControllerRegister) execFilter(context *beecontext.Context, urlPath str
func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
startTime := time.Now()
var (
runRouter reflect.Type
findRouter bool
runMethod string
routerInfo *ControllerInfo
isRunnable bool
runRouter reflect.Type
findRouter bool
runMethod string
methodParams []*param.MethodParam
routerInfo *ControllerInfo
isRunnable bool
)
context := p.pool.Get().(*beecontext.Context)
context.Reset(rw, r)
@ -740,6 +748,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
routerInfo.handler.ServeHTTP(rw, r)
} else {
runRouter = routerInfo.controllerType
methodParams = routerInfo.methodParams
method := r.Method
if r.Method == http.MethodPost && context.Input.Query("_method") == http.MethodPost {
method = http.MethodPut
@ -802,9 +811,14 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request)
execController.Options()
default:
if !execController.HandlerFunc(runMethod) {
var in []reflect.Value
method := vc.MethodByName(runMethod)
method.Call(in)
in := param.ConvertParams(methodParams, method.Type(), context)
out := method.Call(in)
//For backward compatibility we only handle response if we had incoming methodParams
if methodParams != nil {
p.handleParamResponse(context, execController, out)
}
}
}
@ -884,6 +898,20 @@ Admin:
}
}
func (p *ControllerRegister) handleParamResponse(context *beecontext.Context, execController ControllerInterface, results []reflect.Value) {
//looping in reverse order for the case when both error and value are returned and error sets the response status code
for i := len(results) - 1; i >= 0; i-- {
result := results[i]
if result.Kind() != reflect.Interface || !result.IsNil() {
resultValue := result.Interface()
context.RenderMethodResult(resultValue)
}
}
if !context.ResponseWriter.Started && context.Output.Status == 0 {
context.Output.SetStatus(200)
}
}
// FindRouter Find Router info for URL
func (p *ControllerRegister) FindRouter(context *beecontext.Context) (routerInfo *ControllerInfo, isFind bool) {
var urlPath = context.Input.URL()

View File

@ -162,7 +162,9 @@ func (cp *Provider) SessionRead(sid string) (session.Store, error) {
)
err = cp.b.Get(sid, &doc)
if doc == nil {
if err != nil {
return nil, err
} else if doc == nil {
kv = make(map[interface{}]interface{})
} else {
kv, err = session.DecodeGob(doc)

View File

@ -113,13 +113,10 @@ func (lp *Provider) SessionInit(maxlifetime int64, savePath string) error {
func (lp *Provider) SessionRead(sid string) (session.Store, error) {
var (
kv map[interface{}]interface{}
kvs []byte
err error
)
if kvs, err = c.Get([]byte(sid)); err != nil {
return nil, err
}
kvs, _ := c.Get([]byte(sid))
if len(kvs) == 0 {
kv = make(map[interface{}]interface{})

View File

@ -176,16 +176,12 @@ func (rp *Provider) SessionRead(sid string) (session.Store, error) {
c := rp.poollist.Get()
defer c.Close()
var (
kv map[interface{}]interface{}
kvs string
err error
)
var kv map[interface{}]interface{}
if kvs, err = redis.String(c.Do("GET", sid)); err != nil {
kvs, err := redis.String(c.Do("GET", sid))
if err != nil && err != redis.ErrNil {
return nil, err
}
if len(kvs) == 0 {
kv = make(map[interface{}]interface{})
} else {

View File

@ -87,9 +87,16 @@ func (fs *FileSessionStore) SessionRelease(w http.ResponseWriter) {
var f *os.File
if err == nil {
f, err = os.OpenFile(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid), os.O_RDWR, 0777)
if err != nil {
SLogger.Println(err)
return
}
} else if os.IsNotExist(err) {
f, err = os.Create(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid))
if err != nil {
SLogger.Println(err)
return
}
} else {
return
}

View File

@ -74,8 +74,7 @@ func TestCookieEncodeDecode(t *testing.T) {
if err != nil {
t.Fatal("encodeCookie:", err)
}
dst := make(map[interface{}]interface{})
dst, err = decodeCookie(block, hashKey, securityName, str, 3600)
dst, err := decodeCookie(block, hashKey, securityName, str, 3600)
if err != nil {
t.Fatal("decodeCookie", err)
}

View File

@ -81,6 +81,7 @@ func Register(name string, provide Provider) {
provides[name] = provide
}
// ManagerConfig define the session config
type ManagerConfig struct {
CookieName string `json:"cookieName"`
EnableSetCookie bool `json:"enableSetCookie,omitempty"`
@ -92,9 +93,9 @@ type ManagerConfig struct {
ProviderConfig string `json:"providerConfig"`
Domain string `json:"domain"`
SessionIDLength int64 `json:"sessionIDLength"`
EnableSidInHttpHeader bool `json:"enableSidInHttpHeader"`
SessionNameInHttpHeader string `json:"sessionNameInHttpHeader"`
EnableSidInUrlQuery bool `json:"enableSidInUrlQuery"`
EnableSidInHTTPHeader bool `json:"EnableSidInHTTPHeader"`
SessionNameInHTTPHeader string `json:"SessionNameInHTTPHeader"`
EnableSidInURLQuery bool `json:"EnableSidInURLQuery"`
}
// Manager contains Provider and its configuration.
@ -125,14 +126,14 @@ func NewManager(provideName string, cf *ManagerConfig) (*Manager, error) {
cf.Maxlifetime = cf.Gclifetime
}
if cf.EnableSidInHttpHeader {
if cf.SessionNameInHttpHeader == "" {
panic(errors.New("SessionNameInHttpHeader is empty"))
if cf.EnableSidInHTTPHeader {
if cf.SessionNameInHTTPHeader == "" {
panic(errors.New("SessionNameInHTTPHeader is empty"))
}
strMimeHeader := textproto.CanonicalMIMEHeaderKey(cf.SessionNameInHttpHeader)
if cf.SessionNameInHttpHeader != strMimeHeader {
strErrMsg := "SessionNameInHttpHeader (" + cf.SessionNameInHttpHeader + ") has the wrong format, it should be like this : " + strMimeHeader
strMimeHeader := textproto.CanonicalMIMEHeaderKey(cf.SessionNameInHTTPHeader)
if cf.SessionNameInHTTPHeader != strMimeHeader {
strErrMsg := "SessionNameInHTTPHeader (" + cf.SessionNameInHTTPHeader + ") has the wrong format, it should be like this : " + strMimeHeader
panic(errors.New(strErrMsg))
}
}
@ -163,7 +164,7 @@ func (manager *Manager) getSid(r *http.Request) (string, error) {
cookie, errs := r.Cookie(manager.config.CookieName)
if errs != nil || cookie.Value == "" {
var sid string
if manager.config.EnableSidInUrlQuery {
if manager.config.EnableSidInURLQuery {
errs := r.ParseForm()
if errs != nil {
return "", errs
@ -173,8 +174,8 @@ func (manager *Manager) getSid(r *http.Request) (string, error) {
}
// if not found in Cookie / param, then read it from request headers
if manager.config.EnableSidInHttpHeader && sid == "" {
sids, isFound := r.Header[manager.config.SessionNameInHttpHeader]
if manager.config.EnableSidInHTTPHeader && sid == "" {
sids, isFound := r.Header[manager.config.SessionNameInHTTPHeader]
if isFound && len(sids) != 0 {
return sids[0], nil
}
@ -226,9 +227,9 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se
}
r.AddCookie(cookie)
if manager.config.EnableSidInHttpHeader {
r.Header.Set(manager.config.SessionNameInHttpHeader, sid)
w.Header().Set(manager.config.SessionNameInHttpHeader, sid)
if manager.config.EnableSidInHTTPHeader {
r.Header.Set(manager.config.SessionNameInHTTPHeader, sid)
w.Header().Set(manager.config.SessionNameInHTTPHeader, sid)
}
return
@ -236,9 +237,9 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se
// SessionDestroy Destroy session by its id in http request cookie.
func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) {
if manager.config.EnableSidInHttpHeader {
r.Header.Del(manager.config.SessionNameInHttpHeader)
w.Header().Del(manager.config.SessionNameInHttpHeader)
if manager.config.EnableSidInHTTPHeader {
r.Header.Del(manager.config.SessionNameInHTTPHeader)
w.Header().Del(manager.config.SessionNameInHTTPHeader)
}
cookie, err := r.Cookie(manager.config.CookieName)
@ -306,9 +307,9 @@ func (manager *Manager) SessionRegenerateID(w http.ResponseWriter, r *http.Reque
}
r.AddCookie(cookie)
if manager.config.EnableSidInHttpHeader {
r.Header.Set(manager.config.SessionNameInHttpHeader, sid)
w.Header().Set(manager.config.SessionNameInHttpHeader, sid)
if manager.config.EnableSidInHTTPHeader {
r.Header.Set(manager.config.SessionNameInHTTPHeader, sid)
w.Header().Set(manager.config.SessionNameInHTTPHeader, sid)
}
return
@ -328,7 +329,7 @@ func (manager *Manager) sessionID() (string, error) {
b := make([]byte, manager.config.SessionIDLength)
n, err := rand.Read(b)
if n != len(b) || err != nil {
return "", fmt.Errorf("Could not successfully read from the system CSPRNG.")
return "", fmt.Errorf("Could not successfully read from the system CSPRNG")
}
return hex.EncodeToString(b), nil
}

View File

@ -11,16 +11,17 @@ import (
"github.com/ssdb/gossdb/ssdb"
)
var ssdbProvider = &SsdbProvider{}
var ssdbProvider = &Provider{}
type SsdbProvider struct {
// Provider holds ssdb client and configs
type Provider struct {
client *ssdb.Client
host string
port int
maxLifetime int64
}
func (p *SsdbProvider) connectInit() error {
func (p *Provider) connectInit() error {
var err error
if p.host == "" || p.port == 0 {
return errors.New("SessionInit First")
@ -29,7 +30,8 @@ func (p *SsdbProvider) connectInit() error {
return err
}
func (p *SsdbProvider) SessionInit(maxLifetime int64, savePath string) error {
// SessionInit init the ssdb with the config
func (p *Provider) SessionInit(maxLifetime int64, savePath string) error {
p.maxLifetime = maxLifetime
address := strings.Split(savePath, ":")
p.host = address[0]
@ -41,7 +43,8 @@ func (p *SsdbProvider) SessionInit(maxLifetime int64, savePath string) error {
return p.connectInit()
}
func (p *SsdbProvider) SessionRead(sid string) (session.Store, error) {
// SessionRead return a ssdb client session Store
func (p *Provider) SessionRead(sid string) (session.Store, error) {
if p.client == nil {
if err := p.connectInit(); err != nil {
return nil, err
@ -64,7 +67,8 @@ func (p *SsdbProvider) SessionRead(sid string) (session.Store, error) {
return rs, nil
}
func (p *SsdbProvider) SessionExist(sid string) bool {
// SessionExist judged whether sid is exist in session
func (p *Provider) SessionExist(sid string) bool {
if p.client == nil {
if err := p.connectInit(); err != nil {
panic(err)
@ -80,7 +84,8 @@ func (p *SsdbProvider) SessionExist(sid string) bool {
return true
}
func (p *SsdbProvider) SessionRegenerate(oldsid, sid string) (session.Store, error) {
// SessionRegenerate regenerate session with new sid and delete oldsid
func (p *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) {
//conn.Do("setx", key, v, ttl)
if p.client == nil {
if err := p.connectInit(); err != nil {
@ -112,7 +117,8 @@ func (p *SsdbProvider) SessionRegenerate(oldsid, sid string) (session.Store, err
return rs, nil
}
func (p *SsdbProvider) SessionDestroy(sid string) error {
// SessionDestroy destroy the sid
func (p *Provider) SessionDestroy(sid string) error {
if p.client == nil {
if err := p.connectInit(); err != nil {
return err
@ -122,13 +128,16 @@ func (p *SsdbProvider) SessionDestroy(sid string) error {
return err
}
func (p *SsdbProvider) SessionGC() {
// SessionGC not implemented
func (p *Provider) SessionGC() {
}
func (p *SsdbProvider) SessionAll() int {
// SessionAll not implemented
func (p *Provider) SessionAll() int {
return 0
}
// SessionStore holds the session information which stored in ssdb
type SessionStore struct {
sid string
lock sync.RWMutex
@ -137,12 +146,15 @@ type SessionStore struct {
client *ssdb.Client
}
// Set the key and value
func (s *SessionStore) Set(key, value interface{}) error {
s.lock.Lock()
defer s.lock.Unlock()
s.values[key] = value
return nil
}
// Get return the value by the key
func (s *SessionStore) Get(key interface{}) interface{} {
s.lock.Lock()
defer s.lock.Unlock()
@ -152,30 +164,36 @@ func (s *SessionStore) Get(key interface{}) interface{} {
return nil
}
// Delete the key in session store
func (s *SessionStore) Delete(key interface{}) error {
s.lock.Lock()
defer s.lock.Unlock()
delete(s.values, key)
return nil
}
// Flush delete all keys and values
func (s *SessionStore) Flush() error {
s.lock.Lock()
defer s.lock.Unlock()
s.values = make(map[interface{}]interface{})
return nil
}
// SessionID return the sessionID
func (s *SessionStore) SessionID() string {
return s.sid
}
// SessionRelease Store the keyvalues into ssdb
func (s *SessionStore) SessionRelease(w http.ResponseWriter) {
b, err := session.EncodeGob(s.values)
if err != nil {
return
}
s.client.Do("setx", s.sid, string(b), s.maxLifetime)
}
func init() {
session.Register("ssdb", ssdbProvider)
}

View File

@ -22,19 +22,19 @@ package swagger
// Swagger list the resource
type Swagger struct {
SwaggerVersion string `json:"swagger,omitempty" yaml:"swagger,omitempty"`
Infos Information `json:"info" yaml:"info"`
Host string `json:"host,omitempty" yaml:"host,omitempty"`
BasePath string `json:"basePath,omitempty" yaml:"basePath,omitempty"`
Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"`
Consumes []string `json:"consumes,omitempty" yaml:"consumes,omitempty"`
Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"`
Paths map[string]*Item `json:"paths" yaml:"paths"`
Definitions map[string]Schema `json:"definitions,omitempty" yaml:"definitions,omitempty"`
SecurityDefinitions map[string]Security `json:"securityDefinitions,omitempty" yaml:"securityDefinitions,omitempty"`
Security map[string][]string `json:"security,omitempty" yaml:"security,omitempty"`
Tags []Tag `json:"tags,omitempty" yaml:"tags,omitempty"`
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
SwaggerVersion string `json:"swagger,omitempty" yaml:"swagger,omitempty"`
Infos Information `json:"info" yaml:"info"`
Host string `json:"host,omitempty" yaml:"host,omitempty"`
BasePath string `json:"basePath,omitempty" yaml:"basePath,omitempty"`
Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"`
Consumes []string `json:"consumes,omitempty" yaml:"consumes,omitempty"`
Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"`
Paths map[string]*Item `json:"paths" yaml:"paths"`
Definitions map[string]Schema `json:"definitions,omitempty" yaml:"definitions,omitempty"`
SecurityDefinitions map[string]Security `json:"securityDefinitions,omitempty" yaml:"securityDefinitions,omitempty"`
Security []map[string][]string `json:"security,omitempty" yaml:"security,omitempty"`
Tags []Tag `json:"tags,omitempty" yaml:"tags,omitempty"`
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
}
// Information Provides metadata about the API. The metadata can be used by the clients if needed.
@ -75,16 +75,17 @@ type Item struct {
// Operation Describes a single API operation on a path.
type Operation struct {
Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"`
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
OperationID string `json:"operationId,omitempty" yaml:"operationId,omitempty"`
Consumes []string `json:"consumes,omitempty" yaml:"consumes,omitempty"`
Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"`
Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"`
Parameters []Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"`
Responses map[string]Response `json:"responses,omitempty" yaml:"responses,omitempty"`
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"`
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
OperationID string `json:"operationId,omitempty" yaml:"operationId,omitempty"`
Consumes []string `json:"consumes,omitempty" yaml:"consumes,omitempty"`
Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"`
Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"`
Parameters []Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"`
Responses map[string]Response `json:"responses,omitempty" yaml:"responses,omitempty"`
Security []map[string][]string `json:"security,omitempty" yaml:"security,omitempty"`
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
}
// Parameter Describes a single operation parameter.
@ -100,7 +101,7 @@ type Parameter struct {
Default interface{} `json:"default,omitempty" yaml:"default,omitempty"`
}
// A limited subset of JSON-Schema's items object. It is used by parameter definitions that are not located in "body".
// ParameterItems A limited subset of JSON-Schema's items object. It is used by parameter definitions that are not located in "body".
// http://swagger.io/specification/#itemsObject
type ParameterItems struct {
Type string `json:"type,omitempty" yaml:"type,omitempty"`

View File

@ -307,8 +307,9 @@ func _getTemplate(t0 *template.Template, root string, subMods [][]string, others
}
//second check define
for _, otherFile := range others {
var data []byte
fileAbsPath := filepath.Join(root, otherFile)
data, err := ioutil.ReadFile(fileAbsPath)
data, err = ioutil.ReadFile(fileAbsPath)
if err != nil {
continue
}
@ -364,6 +365,7 @@ func DelStaticPath(url string) *App {
return BeeApp
}
// AddTemplateEngine add a new templatePreProcessor which support extension
func AddTemplateEngine(extension string, fn templatePreProcessor) *App {
AddTemplateExt(extension)
beeTemplateEngines[extension] = fn

View File

@ -159,7 +159,7 @@ var add = `{{ template "layout_blog.tpl" . }}
<script src="/static/js/current.js"></script>
{{ end}}`
var layout_blog = `<!DOCTYPE html>
var layoutBlog = `<!DOCTYPE html>
<html>
<head>
<title>Lin Li</title>
@ -231,7 +231,7 @@ func TestTemplateLayout(t *testing.T) {
if k == 0 {
f.WriteString(add)
} else if k == 1 {
f.WriteString(layout_blog)
f.WriteString(layoutBlog)
}
f.Close()
}

View File

@ -27,9 +27,10 @@ import (
)
const (
formatTime = "15:04:05"
formatDate = "2006-01-02"
formatDateTime = "2006-01-02 15:04:05"
formatTime = "15:04:05"
formatDate = "2006-01-02"
formatDateTime = "2006-01-02 15:04:05"
formatDateTimeT = "2006-01-02T15:04:05"
)
// Substr returns the substr from start to length.
@ -53,21 +54,21 @@ func Substr(s string, start, length int) string {
// HTML2str returns escaping text convert from html.
func HTML2str(html string) string {
re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
re, _ := regexp.Compile(`\<[\S\s]+?\>`)
html = re.ReplaceAllStringFunc(html, strings.ToLower)
//remove STYLE
re, _ = regexp.Compile("\\<style[\\S\\s]+?\\</style\\>")
re, _ = regexp.Compile(`\<style[\S\s]+?\</style\>`)
html = re.ReplaceAllString(html, "")
//remove SCRIPT
re, _ = regexp.Compile("\\<script[\\S\\s]+?\\</script\\>")
re, _ = regexp.Compile(`\<script[\S\s]+?\</script\>`)
html = re.ReplaceAllString(html, "")
re, _ = regexp.Compile("\\<[\\S\\s]+?\\>")
re, _ = regexp.Compile(`\<[\S\s]+?\>`)
html = re.ReplaceAllString(html, "\n")
re, _ = regexp.Compile("\\s{2,}")
re, _ = regexp.Compile(`\s{2,}`)
html = re.ReplaceAllString(html, "\n")
return strings.TrimSpace(html)
@ -360,8 +361,13 @@ func parseFormToStruct(form url.Values, objT reflect.Type, objV reflect.Value) e
value = value[:25]
t, err = time.ParseInLocation(time.RFC3339, value, time.Local)
} else if len(value) >= 19 {
value = value[:19]
t, err = time.ParseInLocation(formatDateTime, value, time.Local)
if strings.Contains(value, "T") {
value = value[:19]
t, err = time.ParseInLocation(formatDateTimeT, value, time.Local)
} else {
value = value[:19]
t, err = time.ParseInLocation(formatDateTime, value, time.Local)
}
} else if len(value) >= 10 {
if len(value) > 10 {
value = value[:10]
@ -373,7 +379,6 @@ func parseFormToStruct(form url.Values, objT reflect.Type, objV reflect.Value) e
}
t, err = time.ParseInLocation(formatTime, value, time.Local)
}
if err != nil {
return err
}
@ -507,9 +512,9 @@ func parseFormTag(fieldT reflect.StructField) (label, name, fType string, id str
class = fieldT.Tag.Get("class")
required = false
required_field := fieldT.Tag.Get("required")
if required_field != "-" && required_field != "" {
required, _ = strconv.ParseBool(required_field)
requiredField := fieldT.Tag.Get("required")
if requiredField != "-" && requiredField != "" {
required, _ = strconv.ParseBool(requiredField)
}
switch len(tags) {

View File

@ -254,43 +254,43 @@ func TestParseFormTag(t *testing.T) {
objT := reflect.TypeOf(&user{}).Elem()
label, name, fType, id, class, ignored, required := parseFormTag(objT.Field(0))
label, name, fType, _, _, ignored, _ := parseFormTag(objT.Field(0))
if !(name == "name" && label == "年龄:" && fType == "text" && !ignored) {
t.Errorf("Form Tag with name, label and type was not correctly parsed.")
}
label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(1))
label, name, fType, _, _, ignored, _ = parseFormTag(objT.Field(1))
if !(name == "NoName" && label == "年龄:" && fType == "hidden" && !ignored) {
t.Errorf("Form Tag with label and type but without name was not correctly parsed.")
}
label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(2))
label, name, fType, _, _, ignored, _ = parseFormTag(objT.Field(2))
if !(name == "OnlyLabel" && label == "年龄:" && fType == "text" && !ignored) {
t.Errorf("Form Tag containing only label was not correctly parsed.")
}
label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(3))
label, name, fType, id, class, ignored, _ := parseFormTag(objT.Field(3))
if !(name == "name" && label == "OnlyName: " && fType == "text" && !ignored &&
id == "name" && class == "form-name") {
t.Errorf("Form Tag containing only name was not correctly parsed.")
}
label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(4))
_, _, _, _, _, ignored, _ = parseFormTag(objT.Field(4))
if !ignored {
t.Errorf("Form Tag that should be ignored was not correctly parsed.")
}
label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(5))
_, name, _, _, _, _, required := parseFormTag(objT.Field(5))
if !(name == "name" && required) {
t.Errorf("Form Tag containing only name and required was not correctly parsed.")
}
label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(6))
_, name, _, _, _, _, required = parseFormTag(objT.Field(6))
if !(name == "name" && !required) {
t.Errorf("Form Tag containing only name and ignore required was not correctly parsed.")
}
label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(7))
_, name, _, _, _, _, required = parseFormTag(objT.Field(7))
if !(name == "name" && !required) {
t.Errorf("Form Tag containing only name and not required was not correctly parsed.")
}

View File

@ -72,7 +72,7 @@ func GrepFile(patten string, filename string) (lines []string, err error) {
lines = make([]string, 0)
reader := bufio.NewReader(fd)
prefix := ""
isLongLine := false
var isLongLine bool
for {
byteLine, isPrefix, er := reader.ReadLine()
if er != nil && er != io.EOF {

View File

@ -54,7 +54,7 @@ func TestSearchFile(t *testing.T) {
_, err = SearchFile(noExistedFile, ".")
if err == nil {
t.Errorf("err shouldnot be nil, got path: %s", SelfDir())
t.Errorf("err shouldnt be nil, got path: %s", SelfDir())
}
}

View File

@ -42,7 +42,7 @@ func TestGetValidFuncs(t *testing.T) {
}
f, _ = tf.FieldByName("Tag")
if vfs, err = getValidFuncs(f); err.Error() != "doesn't exsits Maxx valid function" {
if _, err = getValidFuncs(f); err.Error() != "doesn't exsits Maxx valid function" {
t.Fatal(err)
}

View File

@ -35,6 +35,12 @@ func TestRequired(t *testing.T) {
if valid.Required("", "string").Ok {
t.Error("\"'\" string should be false")
}
if valid.Required(" ", "string").Ok {
t.Error("\" \" string should be false") // For #2361
}
if valid.Required("\n", "string").Ok {
t.Error("new line string should be false") // For #2361
}
if !valid.Required("astaxie", "string").Ok {
t.Error("string should be true")
}
@ -175,10 +181,10 @@ func TestAlphaNumeric(t *testing.T) {
func TestMatch(t *testing.T) {
valid := Validation{}
if valid.Match("suchuangji@gmail", regexp.MustCompile("^\\w+@\\w+\\.\\w+$"), "match").Ok {
if valid.Match("suchuangji@gmail", regexp.MustCompile(`^\w+@\w+\.\w+$`), "match").Ok {
t.Error("\"suchuangji@gmail\" match \"^\\w+@\\w+\\.\\w+$\" should be false")
}
if !valid.Match("suchuangji@gmail.com", regexp.MustCompile("^\\w+@\\w+\\.\\w+$"), "match").Ok {
if !valid.Match("suchuangji@gmail.com", regexp.MustCompile(`^\w+@\w+\.\w+$`), "match").Ok {
t.Error("\"suchuangji@gmail\" match \"^\\w+@\\w+\\.\\w+$\" should be true")
}
}
@ -186,10 +192,10 @@ func TestMatch(t *testing.T) {
func TestNoMatch(t *testing.T) {
valid := Validation{}
if valid.NoMatch("123@gmail", regexp.MustCompile("[^\\w\\d]"), "nomatch").Ok {
if valid.NoMatch("123@gmail", regexp.MustCompile(`[^\w\d]`), "nomatch").Ok {
t.Error("\"123@gmail\" not match \"[^\\w\\d]\" should be false")
}
if !valid.NoMatch("123gmail", regexp.MustCompile("[^\\w\\d]"), "match").Ok {
if !valid.NoMatch("123gmail", regexp.MustCompile(`[^\w\d]`), "match").Ok {
t.Error("\"123@gmail\" not match \"[^\\w\\d@]\" should be true")
}
}

View File

@ -18,6 +18,7 @@ import (
"fmt"
"reflect"
"regexp"
"strings"
"time"
"unicode/utf8"
)
@ -98,7 +99,7 @@ func (r Required) IsSatisfied(obj interface{}) bool {
}
if str, ok := obj.(string); ok {
return len(str) > 0
return len(strings.TrimSpace(str)) > 0
}
if _, ok := obj.(bool); ok {
return true
@ -145,7 +146,7 @@ func (r Required) IsSatisfied(obj interface{}) bool {
// DefaultMessage return the default error message
func (r Required) DefaultMessage() string {
return fmt.Sprint(MessageTmpls["Required"])
return MessageTmpls["Required"]
}
// GetKey return the r.Key
@ -364,7 +365,7 @@ func (a Alpha) IsSatisfied(obj interface{}) bool {
// DefaultMessage return the default Length error message
func (a Alpha) DefaultMessage() string {
return fmt.Sprint(MessageTmpls["Alpha"])
return MessageTmpls["Alpha"]
}
// GetKey return the m.Key
@ -397,7 +398,7 @@ func (n Numeric) IsSatisfied(obj interface{}) bool {
// DefaultMessage return the default Length error message
func (n Numeric) DefaultMessage() string {
return fmt.Sprint(MessageTmpls["Numeric"])
return MessageTmpls["Numeric"]
}
// GetKey return the n.Key
@ -430,7 +431,7 @@ func (a AlphaNumeric) IsSatisfied(obj interface{}) bool {
// DefaultMessage return the default Length error message
func (a AlphaNumeric) DefaultMessage() string {
return fmt.Sprint(MessageTmpls["AlphaNumeric"])
return MessageTmpls["AlphaNumeric"]
}
// GetKey return the a.Key
@ -495,7 +496,7 @@ func (n NoMatch) GetLimitValue() interface{} {
return n.Regexp.String()
}
var alphaDashPattern = regexp.MustCompile("[^\\d\\w-_]")
var alphaDashPattern = regexp.MustCompile(`[^\d\w-_]`)
// AlphaDash check not Alpha
type AlphaDash struct {
@ -505,7 +506,7 @@ type AlphaDash struct {
// DefaultMessage return the default AlphaDash error message
func (a AlphaDash) DefaultMessage() string {
return fmt.Sprint(MessageTmpls["AlphaDash"])
return MessageTmpls["AlphaDash"]
}
// GetKey return the n.Key
@ -518,7 +519,7 @@ func (a AlphaDash) GetLimitValue() interface{} {
return nil
}
var emailPattern = regexp.MustCompile("^[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[a-zA-Z0-9](?:[\\w-]*[\\w])?$")
var emailPattern = regexp.MustCompile(`^[\w!#$%&'*+/=?^_` + "`" + `{|}~-]+(?:\.[\w!#$%&'*+/=?^_` + "`" + `{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[a-zA-Z0-9](?:[\w-]*[\w])?$`)
// Email check struct
type Email struct {
@ -528,7 +529,7 @@ type Email struct {
// DefaultMessage return the default Email error message
func (e Email) DefaultMessage() string {
return fmt.Sprint(MessageTmpls["Email"])
return MessageTmpls["Email"]
}
// GetKey return the n.Key
@ -541,7 +542,7 @@ func (e Email) GetLimitValue() interface{} {
return nil
}
var ipPattern = regexp.MustCompile("^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$")
var ipPattern = regexp.MustCompile(`^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$`)
// IP check struct
type IP struct {
@ -551,7 +552,7 @@ type IP struct {
// DefaultMessage return the default IP error message
func (i IP) DefaultMessage() string {
return fmt.Sprint(MessageTmpls["IP"])
return MessageTmpls["IP"]
}
// GetKey return the i.Key
@ -564,7 +565,7 @@ func (i IP) GetLimitValue() interface{} {
return nil
}
var base64Pattern = regexp.MustCompile("^(?:[A-Za-z0-99+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")
var base64Pattern = regexp.MustCompile(`^(?:[A-Za-z0-99+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$`)
// Base64 check struct
type Base64 struct {
@ -574,7 +575,7 @@ type Base64 struct {
// DefaultMessage return the default Base64 error message
func (b Base64) DefaultMessage() string {
return fmt.Sprint(MessageTmpls["Base64"])
return MessageTmpls["Base64"]
}
// GetKey return the b.Key
@ -588,7 +589,7 @@ func (b Base64) GetLimitValue() interface{} {
}
// just for chinese mobile phone number
var mobilePattern = regexp.MustCompile("^((\\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][06789]|[4][579]))\\d{8}$")
var mobilePattern = regexp.MustCompile(`^((\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][06789]|[4][579]))\d{8}$`)
// Mobile check struct
type Mobile struct {
@ -598,7 +599,7 @@ type Mobile struct {
// DefaultMessage return the default Mobile error message
func (m Mobile) DefaultMessage() string {
return fmt.Sprint(MessageTmpls["Mobile"])
return MessageTmpls["Mobile"]
}
// GetKey return the m.Key
@ -612,7 +613,7 @@ func (m Mobile) GetLimitValue() interface{} {
}
// just for chinese telephone number
var telPattern = regexp.MustCompile("^(0\\d{2,3}(\\-)?)?\\d{7,8}$")
var telPattern = regexp.MustCompile(`^(0\d{2,3}(\-)?)?\d{7,8}$`)
// Tel check telephone struct
type Tel struct {
@ -622,7 +623,7 @@ type Tel struct {
// DefaultMessage return the default Tel error message
func (t Tel) DefaultMessage() string {
return fmt.Sprint(MessageTmpls["Tel"])
return MessageTmpls["Tel"]
}
// GetKey return the t.Key
@ -649,7 +650,7 @@ func (p Phone) IsSatisfied(obj interface{}) bool {
// DefaultMessage return the default Phone error message
func (p Phone) DefaultMessage() string {
return fmt.Sprint(MessageTmpls["Phone"])
return MessageTmpls["Phone"]
}
// GetKey return the p.Key
@ -663,7 +664,7 @@ func (p Phone) GetLimitValue() interface{} {
}
// just for chinese zipcode
var zipCodePattern = regexp.MustCompile("^[1-9]\\d{5}$")
var zipCodePattern = regexp.MustCompile(`^[1-9]\d{5}$`)
// ZipCode check the zip struct
type ZipCode struct {
@ -673,7 +674,7 @@ type ZipCode struct {
// DefaultMessage return the default Zip error message
func (z ZipCode) DefaultMessage() string {
return fmt.Sprint(MessageTmpls["ZipCode"])
return MessageTmpls["ZipCode"]
}
// GetKey return the z.Key