Browse Source

改用glide做包管理工具

lifei6671 8 years ago
parent
commit
c15b356758
100 changed files with 18138 additions and 175 deletions
  1. 0 150
      Godeps/Godeps.json
  2. 0 5
      Godeps/Readme
  3. 52 0
      glide.yaml
  4. 0 18
      search/search.go
  5. 17 0
      vendor/github.com/astaxie/beego/.github/ISSUE_TEMPLATE
  6. 6 0
      vendor/github.com/astaxie/beego/.gitignore
  7. 62 0
      vendor/github.com/astaxie/beego/.travis.yml
  8. 52 0
      vendor/github.com/astaxie/beego/CONTRIBUTING.md
  9. 2 2
      vendor/github.com/astaxie/beego/LICENSE
  10. 60 0
      vendor/github.com/astaxie/beego/README.md
  11. 404 0
      vendor/github.com/astaxie/beego/admin.go
  12. 73 0
      vendor/github.com/astaxie/beego/admin_test.go
  13. 286 0
      vendor/github.com/astaxie/beego/adminui.go
  14. 366 0
      vendor/github.com/astaxie/beego/app.go
  15. 100 0
      vendor/github.com/astaxie/beego/beego.go
  16. 59 0
      vendor/github.com/astaxie/beego/cache/README.md
  17. 103 0
      vendor/github.com/astaxie/beego/cache/cache.go
  18. 168 0
      vendor/github.com/astaxie/beego/cache/cache_test.go
  19. 100 0
      vendor/github.com/astaxie/beego/cache/conv.go
  20. 143 0
      vendor/github.com/astaxie/beego/cache/conv_test.go
  21. 255 0
      vendor/github.com/astaxie/beego/cache/file.go
  22. 188 0
      vendor/github.com/astaxie/beego/cache/memcache/memcache.go
  23. 108 0
      vendor/github.com/astaxie/beego/cache/memcache/memcache_test.go
  24. 244 0
      vendor/github.com/astaxie/beego/cache/memory.go
  25. 240 0
      vendor/github.com/astaxie/beego/cache/redis/redis.go
  26. 106 0
      vendor/github.com/astaxie/beego/cache/redis/redis_test.go
  27. 231 0
      vendor/github.com/astaxie/beego/cache/ssdb/ssdb.go
  28. 104 0
      vendor/github.com/astaxie/beego/cache/ssdb/ssdb_test.go
  29. 489 0
      vendor/github.com/astaxie/beego/config.go
  30. 242 0
      vendor/github.com/astaxie/beego/config/config.go
  31. 55 0
      vendor/github.com/astaxie/beego/config/config_test.go
  32. 87 0
      vendor/github.com/astaxie/beego/config/env/env.go
  33. 75 0
      vendor/github.com/astaxie/beego/config/env/env_test.go
  34. 134 0
      vendor/github.com/astaxie/beego/config/fake.go
  35. 482 0
      vendor/github.com/astaxie/beego/config/ini.go
  36. 190 0
      vendor/github.com/astaxie/beego/config/ini_test.go
  37. 266 0
      vendor/github.com/astaxie/beego/config/json.go
  38. 222 0
      vendor/github.com/astaxie/beego/config/json_test.go
  39. 228 0
      vendor/github.com/astaxie/beego/config/xml/xml.go
  40. 125 0
      vendor/github.com/astaxie/beego/config/xml/xml_test.go
  41. 297 0
      vendor/github.com/astaxie/beego/config/yaml/yaml.go
  42. 115 0
      vendor/github.com/astaxie/beego/config/yaml/yaml_test.go
  43. 138 0
      vendor/github.com/astaxie/beego/config_test.go
  44. 232 0
      vendor/github.com/astaxie/beego/context/acceptencoder.go
  45. 59 0
      vendor/github.com/astaxie/beego/context/acceptencoder_test.go
  46. 246 0
      vendor/github.com/astaxie/beego/context/context.go
  47. 47 0
      vendor/github.com/astaxie/beego/context/context_test.go
  48. 650 0
      vendor/github.com/astaxie/beego/context/input.go
  49. 207 0
      vendor/github.com/astaxie/beego/context/input_test.go
  50. 362 0
      vendor/github.com/astaxie/beego/context/output.go
  51. 84 0
      vendor/github.com/astaxie/beego/context/param/parsers_test.go
  52. 654 0
      vendor/github.com/astaxie/beego/controller.go
  53. 181 0
      vendor/github.com/astaxie/beego/controller_test.go
  54. 17 0
      vendor/github.com/astaxie/beego/doc.go
  55. 476 0
      vendor/github.com/astaxie/beego/error.go
  56. 88 0
      vendor/github.com/astaxie/beego/error_test.go
  57. 44 0
      vendor/github.com/astaxie/beego/filter.go
  58. 68 0
      vendor/github.com/astaxie/beego/filter_test.go
  59. 110 0
      vendor/github.com/astaxie/beego/flash.go
  60. 54 0
      vendor/github.com/astaxie/beego/flash_test.go
  61. 28 0
      vendor/github.com/astaxie/beego/grace/conn.go
  62. 166 0
      vendor/github.com/astaxie/beego/grace/grace.go
  63. 62 0
      vendor/github.com/astaxie/beego/grace/listener.go
  64. 305 0
      vendor/github.com/astaxie/beego/grace/server.go
  65. 103 0
      vendor/github.com/astaxie/beego/hooks.go
  66. 97 0
      vendor/github.com/astaxie/beego/httplib/README.md
  67. 585 0
      vendor/github.com/astaxie/beego/httplib/httplib.go
  68. 226 0
      vendor/github.com/astaxie/beego/httplib/httplib_test.go
  69. 111 0
      vendor/github.com/astaxie/beego/log.go
  70. 63 0
      vendor/github.com/astaxie/beego/logs/README.md
  71. 186 0
      vendor/github.com/astaxie/beego/logs/alils/alils.go
  72. 13 0
      vendor/github.com/astaxie/beego/logs/alils/config.go
  73. 1038 0
      vendor/github.com/astaxie/beego/logs/alils/log.pb.go
  74. 42 0
      vendor/github.com/astaxie/beego/logs/alils/log_config.go
  75. 819 0
      vendor/github.com/astaxie/beego/logs/alils/log_project.go
  76. 271 0
      vendor/github.com/astaxie/beego/logs/alils/log_store.go
  77. 91 0
      vendor/github.com/astaxie/beego/logs/alils/machine_group.go
  78. 62 0
      vendor/github.com/astaxie/beego/logs/alils/request.go
  79. 111 0
      vendor/github.com/astaxie/beego/logs/alils/signature.go
  80. 28 0
      vendor/github.com/astaxie/beego/logs/color.go
  81. 428 0
      vendor/github.com/astaxie/beego/logs/color_windows.go
  82. 294 0
      vendor/github.com/astaxie/beego/logs/color_windows_test.go
  83. 117 0
      vendor/github.com/astaxie/beego/logs/conn.go
  84. 25 0
      vendor/github.com/astaxie/beego/logs/conn_test.go
  85. 101 0
      vendor/github.com/astaxie/beego/logs/console.go
  86. 51 0
      vendor/github.com/astaxie/beego/logs/console_test.go
  87. 80 0
      vendor/github.com/astaxie/beego/logs/es/es.go
  88. 327 0
      vendor/github.com/astaxie/beego/logs/file.go
  89. 300 0
      vendor/github.com/astaxie/beego/logs/file_test.go
  90. 72 0
      vendor/github.com/astaxie/beego/logs/jianliao.go
  91. 646 0
      vendor/github.com/astaxie/beego/logs/log.go
  92. 201 0
      vendor/github.com/astaxie/beego/logs/logger.go
  93. 75 0
      vendor/github.com/astaxie/beego/logs/logger_test.go
  94. 116 0
      vendor/github.com/astaxie/beego/logs/multifile.go
  95. 78 0
      vendor/github.com/astaxie/beego/logs/multifile_test.go
  96. 60 0
      vendor/github.com/astaxie/beego/logs/slack.go
  97. 149 0
      vendor/github.com/astaxie/beego/logs/smtp.go
  98. 27 0
      vendor/github.com/astaxie/beego/logs/smtp_test.go
  99. 53 0
      vendor/github.com/astaxie/beego/migration/ddl.go
  100. 278 0
      vendor/github.com/astaxie/beego/migration/migration.go

+ 0 - 150
Godeps/Godeps.json

@@ -1,150 +0,0 @@
-{
-	"ImportPath": "github.com/lifei6671/godoc",
-	"GoVersion": "go1.8",
-	"GodepVersion": "v79",
-	"Deps": [
-		{
-			"ImportPath": "github.com/astaxie/beego",
-			"Comment": "v1.8.3",
-			"Rev": "cab8458c1c4a5a3b4bf5192922be620e6dede15b"
-		},
-		{
-			"ImportPath": "github.com/astaxie/beego/config",
-			"Comment": "v1.8.3",
-			"Rev": "cab8458c1c4a5a3b4bf5192922be620e6dede15b"
-		},
-		{
-			"ImportPath": "github.com/astaxie/beego/context",
-			"Comment": "v1.8.3",
-			"Rev": "cab8458c1c4a5a3b4bf5192922be620e6dede15b"
-		},
-		{
-			"ImportPath": "github.com/astaxie/beego/context/param",
-			"Comment": "v1.8.3",
-			"Rev": "cab8458c1c4a5a3b4bf5192922be620e6dede15b"
-		},
-		{
-			"ImportPath": "github.com/astaxie/beego/grace",
-			"Comment": "v1.8.3",
-			"Rev": "cab8458c1c4a5a3b4bf5192922be620e6dede15b"
-		},
-		{
-			"ImportPath": "github.com/astaxie/beego/logs",
-			"Comment": "v1.8.3",
-			"Rev": "cab8458c1c4a5a3b4bf5192922be620e6dede15b"
-		},
-		{
-			"ImportPath": "github.com/astaxie/beego/orm",
-			"Comment": "v1.8.3",
-			"Rev": "cab8458c1c4a5a3b4bf5192922be620e6dede15b"
-		},
-		{
-			"ImportPath": "github.com/astaxie/beego/session",
-			"Comment": "v1.8.3",
-			"Rev": "cab8458c1c4a5a3b4bf5192922be620e6dede15b"
-		},
-		{
-			"ImportPath": "github.com/astaxie/beego/session/memcache",
-			"Comment": "v1.8.3",
-			"Rev": "cab8458c1c4a5a3b4bf5192922be620e6dede15b"
-		},
-		{
-			"ImportPath": "github.com/astaxie/beego/session/mysql",
-			"Comment": "v1.8.3",
-			"Rev": "cab8458c1c4a5a3b4bf5192922be620e6dede15b"
-		},
-		{
-			"ImportPath": "github.com/astaxie/beego/session/redis",
-			"Comment": "v1.8.3",
-			"Rev": "cab8458c1c4a5a3b4bf5192922be620e6dede15b"
-		},
-		{
-			"ImportPath": "github.com/astaxie/beego/toolbox",
-			"Comment": "v1.8.3",
-			"Rev": "cab8458c1c4a5a3b4bf5192922be620e6dede15b"
-		},
-		{
-			"ImportPath": "github.com/astaxie/beego/utils",
-			"Comment": "v1.8.3",
-			"Rev": "cab8458c1c4a5a3b4bf5192922be620e6dede15b"
-		},
-		{
-			"ImportPath": "github.com/boombuler/barcode",
-			"Rev": "059b33dac2e9f716cf906bc5071ebb42e607228f"
-		},
-		{
-			"ImportPath": "github.com/boombuler/barcode/qr",
-			"Rev": "059b33dac2e9f716cf906bc5071ebb42e607228f"
-		},
-		{
-			"ImportPath": "github.com/boombuler/barcode/utils",
-			"Rev": "059b33dac2e9f716cf906bc5071ebb42e607228f"
-		},
-		{
-			"ImportPath": "github.com/bradfitz/gomemcache/memcache",
-			"Comment": "release.r60-46-g1952afa",
-			"Rev": "1952afaa557dc08e8e0d89eafab110fb501c1a2b"
-		},
-		{
-			"ImportPath": "github.com/garyburd/redigo/internal",
-			"Comment": "v1.0.0-23-gac91d6f",
-			"Rev": "ac91d6ff49bd0d278a90201de77a4f8ad9628e25"
-		},
-		{
-			"ImportPath": "github.com/garyburd/redigo/redis",
-			"Comment": "v1.0.0-23-gac91d6f",
-			"Rev": "ac91d6ff49bd0d278a90201de77a4f8ad9628e25"
-		},
-		{
-			"ImportPath": "github.com/go-sql-driver/mysql",
-			"Comment": "v1.2-191-g1421caf",
-			"Rev": "1421caf44f6464fd2ee8de694c7508ee13f92964"
-		},
-		{
-			"ImportPath": "github.com/golang/freetype",
-			"Comment": "release-132-gd9be45a",
-			"Rev": "d9be45aaf7452cc30c0ceb1b1bf7efe1d17b7c87"
-		},
-		{
-			"ImportPath": "github.com/golang/freetype/raster",
-			"Comment": "release-132-gd9be45a",
-			"Rev": "d9be45aaf7452cc30c0ceb1b1bf7efe1d17b7c87"
-		},
-		{
-			"ImportPath": "github.com/golang/freetype/truetype",
-			"Comment": "release-132-gd9be45a",
-			"Rev": "d9be45aaf7452cc30c0ceb1b1bf7efe1d17b7c87"
-		},
-		{
-			"ImportPath": "github.com/lifei6671/gocaptcha",
-			"Rev": "b244e66362327cfd7d47c1a75eb1ca3845ffc52a"
-		},
-		{
-			"ImportPath": "github.com/mattn/go-sqlite3",
-			"Comment": "v1.1.0-62-g467f50b",
-			"Rev": "467f50b0c026317ad28fc2c0a08aab6f755cfc7a"
-		},
-		{
-			"ImportPath": "github.com/nfnt/resize",
-			"Rev": "891127d8d1b52734debe1b3c3d7e747502b6c366"
-		},
-		{
-			"ImportPath": "golang.org/x/image/font",
-			"Rev": "69afd001f792d732a78bd7225793315a8deb09ea"
-		},
-		{
-			"ImportPath": "golang.org/x/image/math/fixed",
-			"Rev": "69afd001f792d732a78bd7225793315a8deb09ea"
-		},
-		{
-			"ImportPath": "gopkg.in/asn1-ber.v1",
-			"Comment": "v1.2",
-			"Rev": "379148ca0225df7a432012b8df0355c2a2063ac0"
-		},
-		{
-			"ImportPath": "gopkg.in/ldap.v2",
-			"Comment": "v2.5.0",
-			"Rev": "8168ee085ee43257585e50c6441aadf54ecb2c9f"
-		}
-	]
-}

+ 0 - 5
Godeps/Readme

@@ -1,5 +0,0 @@
-This directory tree is generated automatically by godep.
-
-Please do not edit.
-
-See https://github.com/tools/godep for more information.

+ 52 - 0
glide.yaml

@@ -0,0 +1,52 @@
+package: github.com/lifei6671/godoc
+import:
+- package: github.com/astaxie/beego
+  version: ^1.8.3
+  subpackages:
+  - config
+  - context
+  - context/param
+  - grace
+  - logs
+  - orm
+  - session
+  - session/memcache
+  - session/mysql
+  - session/redis
+  - toolbox
+  - utils
+- package: github.com/boombuler/barcode
+  version: 059b33dac2e9f716cf906bc5071ebb42e607228f
+  subpackages:
+  - qr
+  - utils
+- package: github.com/bradfitz/gomemcache
+  version: 1952afaa557dc08e8e0d89eafab110fb501c1a2b
+  subpackages:
+  - memcache
+- package: github.com/garyburd/redigo
+  version: ac91d6ff49bd0d278a90201de77a4f8ad9628e25
+  subpackages:
+  - internal
+  - redis
+- package: github.com/go-sql-driver/mysql
+  version: 1421caf44f6464fd2ee8de694c7508ee13f92964
+- package: github.com/golang/freetype
+  version: d9be45aaf7452cc30c0ceb1b1bf7efe1d17b7c87
+  subpackages:
+  - raster
+  - truetype
+- package: github.com/lifei6671/gocaptcha
+  version: b244e66362327cfd7d47c1a75eb1ca3845ffc52a
+- package: github.com/mattn/go-sqlite3
+  version: 467f50b0c026317ad28fc2c0a08aab6f755cfc7a
+- package: github.com/nfnt/resize
+  version: 891127d8d1b52734debe1b3c3d7e747502b6c366
+- package: golang.org/x/image/font
+  version: 69afd001f792d732a78bd7225793315a8deb09ea
+- package: golang.org/x/image/math/fixed
+  version: 69afd001f792d732a78bd7225793315a8deb09ea
+- package: gopkg.in/asn1-ber.v1
+  version: ^1.2.0
+- package: gopkg.in/ldap.v2
+  version: ^2.5.0

+ 0 - 18
search/search.go

@@ -1,18 +0,0 @@
-package search
-
-import (
-	"github.com/huichen/wukong/engine"
-	"github.com/huichen/wukong/types"
-)
-
-var searcher engine.Engine
-
-func init()  {
-	searcher.Init(types.EngineInitOptions{
-		SegmenterDictionaries: "data/dictionary.txt",
-		StopTokenFile:         "data/stop_tokens.txt",
-		IndexerInitOptions: &types.IndexerInitOptions{
-			IndexType: types.LocationsIndex,
-		},
-	})
-}

+ 17 - 0
vendor/github.com/astaxie/beego/.github/ISSUE_TEMPLATE

@@ -0,0 +1,17 @@
+Please answer these questions before submitting your issue. Thanks!
+
+1. What version of Go and beego are you using (`bee version`)?
+
+
+2. What operating system and processor architecture are you using (`go env`)?
+
+
+3. What did you do?
+If possible, provide a recipe for reproducing the error.
+A complete runnable program is good.
+
+
+4. What did you expect to see?
+
+
+5. What did you see instead?

+ 6 - 0
vendor/github.com/astaxie/beego/.gitignore

@@ -0,0 +1,6 @@
+.idea
+.vscode
+.DS_Store
+*.swp
+*.swo
+beego.iml

+ 62 - 0
vendor/github.com/astaxie/beego/.travis.yml

@@ -0,0 +1,62 @@
+language: go
+
+go:
+  - 1.6.4
+  - 1.7.5
+  - 1.8.1
+services:
+  - redis-server
+  - mysql
+  - postgresql
+  - memcached
+env:
+  - ORM_DRIVER=sqlite3   ORM_SOURCE=$TRAVIS_BUILD_DIR/orm_test.db
+  - ORM_DRIVER=mysql    ORM_SOURCE="root:@/orm_test?charset=utf8"
+  - ORM_DRIVER=postgres ORM_SOURCE="user=postgres dbname=orm_test sslmode=disable"
+before_install:
+ - git clone git://github.com/ideawu/ssdb.git
+ - cd ssdb
+ - make
+ - cd ..
+install:
+  - go get github.com/lib/pq
+  - go get github.com/go-sql-driver/mysql
+  - go get github.com/mattn/go-sqlite3
+  - go get github.com/bradfitz/gomemcache/memcache
+  - go get github.com/garyburd/redigo/redis
+  - go get github.com/beego/x2j
+  - go get github.com/couchbase/go-couchbase
+  - go get github.com/beego/goyaml2
+  - go get github.com/belogik/goes
+  - go get github.com/siddontang/ledisdb/config
+  - go get github.com/siddontang/ledisdb/ledis
+  - 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"
+  - sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi"
+  - sh -c "if [ '$ORM_DRIVER' = 'sqlite' ]; then touch $TRAVIS_BUILD_DIR/orm_test.db; fi"
+  - sh -c "if [ $(go version) == *1.[5-9]* ]; then go get github.com/golang/lint/golint; golint ./...; fi"
+  - sh -c "if [ $(go version) == *1.[5-9]* ]; then go tool vet .; fi"
+  - mkdir -p res/var
+  - ./ssdb/ssdb-server ./ssdb/ssdb.conf -d
+after_script:
+  -killall -w ssdb-server
+  - rm -rf ./res/var/*
+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"

+ 52 - 0
vendor/github.com/astaxie/beego/CONTRIBUTING.md

@@ -0,0 +1,52 @@
+# Contributing to beego
+
+beego is an open source project.
+
+It is the work of hundreds of contributors. We appreciate your help!
+
+Here are instructions to get you started. They are probably not perfect, 
+please let us know if anything feels wrong or incomplete.
+
+## Contribution guidelines
+
+### Pull requests
+
+First of all. beego follow the gitflow. So please send you pull request 
+to **develop** branch. We will close the pull request to master branch.
+
+We are always happy to receive pull requests, and do our best to
+review them as fast as possible. Not sure if that typo is worth a pull
+request? Do it! We will appreciate it.
+
+If your pull request is not accepted on the first try, don't be
+discouraged! Sometimes we can make a mistake, please do more explaining 
+for us. We will appreciate it.
+
+We're trying very hard to keep beego simple and fast. We don't want it
+to do everything for everybody. This means that we might decide against
+incorporating a new feature. But we will give you some advice on how to 
+do it in other way.
+
+### Create issues
+
+Any significant improvement should be documented as [a GitHub
+issue](https://github.com/astaxie/beego/issues) before anybody
+starts working on it. 
+
+Also when filing an issue, make sure to answer these five questions:
+
+- What version of beego are you using (bee version)?
+- What operating system and processor architecture are you using?
+- What did you do?
+- What did you expect to see?
+- What did you see instead?
+
+### but check existing issues and docs first!
+
+Please take a moment to check that an issue doesn't already exist
+documenting your bug report or improvement proposal. If it does, it
+never hurts to add a quick "+1" or "I have this problem too". This will
+help prioritize the most common problems and requests.
+
+Also if you don't know how to use it. please make sure you have read though
+the docs in http://beego.me/docs

+ 2 - 2
vendor/github.com/huichen/wukong/license.txt → vendor/github.com/astaxie/beego/LICENSE

@@ -1,4 +1,4 @@
-Copyright 2013 Hui Chen
+Copyright 2014 astaxie
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -10,4 +10,4 @@ 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.
+limitations under the License.

+ 60 - 0
vendor/github.com/astaxie/beego/README.md

@@ -0,0 +1,60 @@
+# Beego [![Build Status](https://travis-ci.org/astaxie/beego.svg?branch=master)](https://travis-ci.org/astaxie/beego) [![GoDoc](http://godoc.org/github.com/astaxie/beego?status.svg)](http://godoc.org/github.com/astaxie/beego) [![Foundation](https://img.shields.io/badge/Golang-Foundation-green.svg)](http://golangfoundation.org)
+
+beego is used for rapid development of RESTful APIs, web apps and backend services in Go.
+It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific features such as interfaces and struct embedding.
+
+###### More info at [beego.me](http://beego.me).
+
+## Quick Start
+
+#### Download and install
+
+    go get github.com/astaxie/beego
+
+#### Create file `hello.go`
+```go
+package main
+
+import "github.com/astaxie/beego"
+
+func main(){
+    beego.Run()
+}
+```
+#### Build and run
+
+    go build hello.go
+    ./hello
+
+#### Go to [http://localhost:8080](http://localhost:8080)
+
+Congratulations! You've just built your first **beego** app.
+
+###### Please see [Documentation](http://beego.me/docs) for more.
+
+## Features
+
+* RESTful support
+* MVC architecture
+* Modularity
+* Auto API documents
+* Annotation router
+* Namespace
+* Powerful development tools
+* Full stack for Web & API
+
+## Documentation
+
+* [English](http://beego.me/docs/intro/)
+* [中文文档](http://beego.me/docs/intro/)
+* [Русский](http://beego.me/docs/intro/)
+
+## Community
+
+* [http://beego.me/community](http://beego.me/community)
+* Welcome to join us in Slack: [https://beego.slack.com](https://beego.slack.com), you can get invited from [here](https://github.com/beego/beedoc/issues/232)
+
+## License
+
+beego source code is licensed under the Apache Licence, Version 2.0
+(http://www.apache.org/licenses/LICENSE-2.0.html).

+ 404 - 0
vendor/github.com/astaxie/beego/admin.go

@@ -0,0 +1,404 @@
+// 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 beego
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"os"
+	"text/template"
+	"time"
+
+	"reflect"
+
+	"github.com/astaxie/beego/grace"
+	"github.com/astaxie/beego/logs"
+	"github.com/astaxie/beego/toolbox"
+	"github.com/astaxie/beego/utils"
+)
+
+// BeeAdminApp is the default adminApp used by admin module.
+var beeAdminApp *adminApp
+
+// FilterMonitorFunc is default monitor filter when admin module is enable.
+// if this func returns, admin module records qbs for this request by condition of this function logic.
+// usage:
+// 	func MyFilterMonitor(method, requestPath string, t time.Duration) bool {
+//	 	if method == "POST" {
+//			return false
+//	 	}
+//	 	if t.Nanoseconds() < 100 {
+//			return false
+//	 	}
+//	 	if strings.HasPrefix(requestPath, "/astaxie") {
+//			return false
+//	 	}
+//	 	return true
+// 	}
+// 	beego.FilterMonitorFunc = MyFilterMonitor.
+var FilterMonitorFunc func(string, string, time.Duration) bool
+
+func init() {
+	beeAdminApp = &adminApp{
+		routers: make(map[string]http.HandlerFunc),
+	}
+	beeAdminApp.Route("/", adminIndex)
+	beeAdminApp.Route("/qps", qpsIndex)
+	beeAdminApp.Route("/prof", profIndex)
+	beeAdminApp.Route("/healthcheck", healthcheck)
+	beeAdminApp.Route("/task", taskStatus)
+	beeAdminApp.Route("/listconf", listConf)
+	FilterMonitorFunc = func(string, string, time.Duration) bool { return true }
+}
+
+// AdminIndex is the default http.Handler for admin module.
+// it matches url pattern "/".
+func adminIndex(rw http.ResponseWriter, r *http.Request) {
+	execTpl(rw, map[interface{}]interface{}{}, indexTpl, defaultScriptsTpl)
+}
+
+// QpsIndex is the http.Handler for writing qbs statistics map result info in http.ResponseWriter.
+// it's registered with url pattern "/qbs" in admin module.
+func qpsIndex(rw http.ResponseWriter, r *http.Request) {
+	data := make(map[interface{}]interface{})
+	data["Content"] = toolbox.StatisticsMap.GetMap()
+	execTpl(rw, data, qpsTpl, defaultScriptsTpl)
+}
+
+// ListConf is the http.Handler of displaying all beego configuration values as key/value pair.
+// it's registered with url pattern "/listconf" in admin module.
+func listConf(rw http.ResponseWriter, r *http.Request) {
+	r.ParseForm()
+	command := r.Form.Get("command")
+	if command == "" {
+		rw.Write([]byte("command not support"))
+		return
+	}
+
+	data := make(map[interface{}]interface{})
+	switch command {
+	case "conf":
+		m := make(map[string]interface{})
+		list("BConfig", BConfig, m)
+		m["AppConfigPath"] = appConfigPath
+		m["AppConfigProvider"] = appConfigProvider
+		tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
+		tmpl = template.Must(tmpl.Parse(configTpl))
+		tmpl = template.Must(tmpl.Parse(defaultScriptsTpl))
+
+		data["Content"] = m
+
+		tmpl.Execute(rw, data)
+
+	case "router":
+		content := PrintTree()
+		content["Fields"] = []string{
+			"Router Pattern",
+			"Methods",
+			"Controller",
+		}
+		data["Content"] = content
+		data["Title"] = "Routers"
+		execTpl(rw, data, routerAndFilterTpl, defaultScriptsTpl)
+	case "filter":
+		var (
+			content = map[string]interface{}{
+				"Fields": []string{
+					"Router Pattern",
+					"Filter Function",
+				},
+			}
+			filterTypes    = []string{}
+			filterTypeData = make(map[string]interface{})
+		)
+
+		if BeeApp.Handlers.enableFilter {
+			var filterType string
+			for k, fr := range map[int]string{
+				BeforeStatic: "Before Static",
+				BeforeRouter: "Before Router",
+				BeforeExec:   "Before Exec",
+				AfterExec:    "After Exec",
+				FinishRouter: "Finish Router"} {
+				if bf := BeeApp.Handlers.filters[k]; len(bf) > 0 {
+					filterType = fr
+					filterTypes = append(filterTypes, filterType)
+					resultList := new([][]string)
+					for _, f := range bf {
+						var result = []string{
+							f.pattern,
+							utils.GetFuncName(f.filterFunc),
+						}
+						*resultList = append(*resultList, result)
+					}
+					filterTypeData[filterType] = resultList
+				}
+			}
+		}
+
+		content["Data"] = filterTypeData
+		content["Methods"] = filterTypes
+
+		data["Content"] = content
+		data["Title"] = "Filters"
+		execTpl(rw, data, routerAndFilterTpl, defaultScriptsTpl)
+	default:
+		rw.Write([]byte("command not support"))
+	}
+}
+
+func list(root string, p interface{}, m map[string]interface{}) {
+	pt := reflect.TypeOf(p)
+	pv := reflect.ValueOf(p)
+	if pt.Kind() == reflect.Ptr {
+		pt = pt.Elem()
+		pv = pv.Elem()
+	}
+	for i := 0; i < pv.NumField(); i++ {
+		var key string
+		if root == "" {
+			key = pt.Field(i).Name
+		} else {
+			key = root + "." + pt.Field(i).Name
+		}
+		if pv.Field(i).Kind() == reflect.Struct {
+			list(key, pv.Field(i).Interface(), m)
+		} else {
+			m[key] = pv.Field(i).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)
+	}
+	if t.wildcard != nil {
+		printTree(resultList, t.wildcard)
+	}
+	for _, l := range t.leaves {
+		if v, ok := l.runObject.(*ControllerInfo); ok {
+			if v.routerType == routerTypeBeego {
+				var result = []string{
+					v.pattern,
+					fmt.Sprintf("%s", v.methods),
+					v.controllerType.String(),
+				}
+				*resultList = append(*resultList, result)
+			} else if v.routerType == routerTypeRESTFul {
+				var result = []string{
+					v.pattern,
+					fmt.Sprintf("%s", v.methods),
+					"",
+				}
+				*resultList = append(*resultList, result)
+			} else if v.routerType == routerTypeHandler {
+				var result = []string{
+					v.pattern,
+					"",
+					"",
+				}
+				*resultList = append(*resultList, result)
+			}
+		}
+	}
+}
+
+// ProfIndex is a http.Handler for showing profile command.
+// it's in url pattern "/prof" in admin module.
+func profIndex(rw http.ResponseWriter, r *http.Request) {
+	r.ParseForm()
+	command := r.Form.Get("command")
+	if command == "" {
+		return
+	}
+
+	var (
+		format = r.Form.Get("format")
+		data   = make(map[interface{}]interface{})
+		result bytes.Buffer
+	)
+	toolbox.ProcessInput(command, &result)
+	data["Content"] = result.String()
+
+	if format == "json" && command == "gc summary" {
+		dataJSON, err := json.Marshal(data)
+		if err != nil {
+			http.Error(rw, err.Error(), http.StatusInternalServerError)
+			return
+		}
+
+		rw.Header().Set("Content-Type", "application/json")
+		rw.Write(dataJSON)
+		return
+	}
+
+	data["Title"] = command
+	defaultTpl := defaultScriptsTpl
+	if command == "gc summary" {
+		defaultTpl = gcAjaxTpl
+	}
+	execTpl(rw, data, profillingTpl, defaultTpl)
+}
+
+// Healthcheck is a http.Handler calling health checking and showing the result.
+// it's in "/healthcheck" pattern in admin module.
+func healthcheck(rw http.ResponseWriter, req *http.Request) {
+	var (
+		result     []string
+		data       = make(map[interface{}]interface{})
+		resultList = new([][]string)
+		content    = map[string]interface{}{
+			"Fields": []string{"Name", "Message", "Status"},
+		}
+	)
+
+	for name, h := range toolbox.AdminCheckList {
+		if err := h.Check(); err != nil {
+			result = []string{
+				"error",
+				name,
+				err.Error(),
+			}
+		} else {
+			result = []string{
+				"success",
+				name,
+				"OK",
+			}
+		}
+		*resultList = append(*resultList, result)
+	}
+
+	content["Data"] = resultList
+	data["Content"] = content
+	data["Title"] = "Health Check"
+	execTpl(rw, data, healthCheckTpl, defaultScriptsTpl)
+}
+
+// TaskStatus is a http.Handler with running task status (task name, status and the last execution).
+// it's in "/task" pattern in admin module.
+func taskStatus(rw http.ResponseWriter, req *http.Request) {
+	data := make(map[interface{}]interface{})
+
+	// Run Task
+	req.ParseForm()
+	taskname := req.Form.Get("taskname")
+	if taskname != "" {
+		if t, ok := toolbox.AdminTaskList[taskname]; ok {
+			if err := t.Run(); err != nil {
+				data["Message"] = []string{"error", fmt.Sprintf("%s", err)}
+			}
+			data["Message"] = []string{"success", fmt.Sprintf("%s run success,Now the Status is <br>%s", taskname, t.GetStatus())}
+		} else {
+			data["Message"] = []string{"warning", fmt.Sprintf("there's no task which named: %s", taskname)}
+		}
+	}
+
+	// List Tasks
+	content := make(map[string]interface{})
+	resultList := new([][]string)
+	var fields = []string{
+		"Task Name",
+		"Task Spec",
+		"Task Status",
+		"Last Time",
+		"",
+	}
+	for tname, tk := range toolbox.AdminTaskList {
+		result := []string{
+			tname,
+			tk.GetSpec(),
+			tk.GetStatus(),
+			tk.GetPrev().String(),
+		}
+		*resultList = append(*resultList, result)
+	}
+
+	content["Fields"] = fields
+	content["Data"] = resultList
+	data["Content"] = content
+	data["Title"] = "Tasks"
+	execTpl(rw, data, tasksTpl, defaultScriptsTpl)
+}
+
+func execTpl(rw http.ResponseWriter, data map[interface{}]interface{}, tpls ...string) {
+	tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
+	for _, tpl := range tpls {
+		tmpl = template.Must(tmpl.Parse(tpl))
+	}
+	tmpl.Execute(rw, data)
+}
+
+// adminApp is an http.HandlerFunc map used as beeAdminApp.
+type adminApp struct {
+	routers map[string]http.HandlerFunc
+}
+
+// Route adds http.HandlerFunc to adminApp with url pattern.
+func (admin *adminApp) Route(pattern string, f http.HandlerFunc) {
+	admin.routers[pattern] = f
+}
+
+// Run adminApp http server.
+// Its addr is defined in configuration file as adminhttpaddr and adminhttpport.
+func (admin *adminApp) Run() {
+	if len(toolbox.AdminTaskList) > 0 {
+		toolbox.StartTask()
+	}
+	addr := BConfig.Listen.AdminAddr
+
+	if BConfig.Listen.AdminPort != 0 {
+		addr = fmt.Sprintf("%s:%d", BConfig.Listen.AdminAddr, BConfig.Listen.AdminPort)
+	}
+	for p, f := range admin.routers {
+		http.Handle(p, f)
+	}
+	logs.Info("Admin server Running on %s", addr)
+
+	var err error
+	if BConfig.Listen.Graceful {
+		err = grace.ListenAndServe(addr, nil)
+	} else {
+		err = http.ListenAndServe(addr, nil)
+	}
+	if err != nil {
+		logs.Critical("Admin ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid()))
+	}
+}

+ 73 - 0
vendor/github.com/astaxie/beego/admin_test.go

@@ -0,0 +1,73 @@
+package beego
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestList_01(t *testing.T) {
+	m := make(map[string]interface{})
+	list("BConfig", BConfig, m)
+	t.Log(m)
+	om := oldMap()
+	for k, v := range om {
+		if fmt.Sprint(m[k]) != fmt.Sprint(v) {
+			t.Log(k, "old-key", v, "new-key", m[k])
+			t.FailNow()
+		}
+	}
+}
+
+func oldMap() map[string]interface{} {
+	m := make(map[string]interface{})
+	m["BConfig.AppName"] = BConfig.AppName
+	m["BConfig.RunMode"] = BConfig.RunMode
+	m["BConfig.RouterCaseSensitive"] = BConfig.RouterCaseSensitive
+	m["BConfig.ServerName"] = BConfig.ServerName
+	m["BConfig.RecoverPanic"] = BConfig.RecoverPanic
+	m["BConfig.CopyRequestBody"] = BConfig.CopyRequestBody
+	m["BConfig.EnableGzip"] = BConfig.EnableGzip
+	m["BConfig.MaxMemory"] = BConfig.MaxMemory
+	m["BConfig.EnableErrorsShow"] = BConfig.EnableErrorsShow
+	m["BConfig.Listen.Graceful"] = BConfig.Listen.Graceful
+	m["BConfig.Listen.ServerTimeOut"] = BConfig.Listen.ServerTimeOut
+	m["BConfig.Listen.ListenTCP4"] = BConfig.Listen.ListenTCP4
+	m["BConfig.Listen.EnableHTTP"] = BConfig.Listen.EnableHTTP
+	m["BConfig.Listen.HTTPAddr"] = BConfig.Listen.HTTPAddr
+	m["BConfig.Listen.HTTPPort"] = BConfig.Listen.HTTPPort
+	m["BConfig.Listen.EnableHTTPS"] = BConfig.Listen.EnableHTTPS
+	m["BConfig.Listen.HTTPSAddr"] = BConfig.Listen.HTTPSAddr
+	m["BConfig.Listen.HTTPSPort"] = BConfig.Listen.HTTPSPort
+	m["BConfig.Listen.HTTPSCertFile"] = BConfig.Listen.HTTPSCertFile
+	m["BConfig.Listen.HTTPSKeyFile"] = BConfig.Listen.HTTPSKeyFile
+	m["BConfig.Listen.EnableAdmin"] = BConfig.Listen.EnableAdmin
+	m["BConfig.Listen.AdminAddr"] = BConfig.Listen.AdminAddr
+	m["BConfig.Listen.AdminPort"] = BConfig.Listen.AdminPort
+	m["BConfig.Listen.EnableFcgi"] = BConfig.Listen.EnableFcgi
+	m["BConfig.Listen.EnableStdIo"] = BConfig.Listen.EnableStdIo
+	m["BConfig.WebConfig.AutoRender"] = BConfig.WebConfig.AutoRender
+	m["BConfig.WebConfig.EnableDocs"] = BConfig.WebConfig.EnableDocs
+	m["BConfig.WebConfig.FlashName"] = BConfig.WebConfig.FlashName
+	m["BConfig.WebConfig.FlashSeparator"] = BConfig.WebConfig.FlashSeparator
+	m["BConfig.WebConfig.DirectoryIndex"] = BConfig.WebConfig.DirectoryIndex
+	m["BConfig.WebConfig.StaticDir"] = BConfig.WebConfig.StaticDir
+	m["BConfig.WebConfig.StaticExtensionsToGzip"] = BConfig.WebConfig.StaticExtensionsToGzip
+	m["BConfig.WebConfig.TemplateLeft"] = BConfig.WebConfig.TemplateLeft
+	m["BConfig.WebConfig.TemplateRight"] = BConfig.WebConfig.TemplateRight
+	m["BConfig.WebConfig.ViewsPath"] = BConfig.WebConfig.ViewsPath
+	m["BConfig.WebConfig.EnableXSRF"] = BConfig.WebConfig.EnableXSRF
+	m["BConfig.WebConfig.XSRFExpire"] = BConfig.WebConfig.XSRFExpire
+	m["BConfig.WebConfig.Session.SessionOn"] = BConfig.WebConfig.Session.SessionOn
+	m["BConfig.WebConfig.Session.SessionProvider"] = BConfig.WebConfig.Session.SessionProvider
+	m["BConfig.WebConfig.Session.SessionName"] = BConfig.WebConfig.Session.SessionName
+	m["BConfig.WebConfig.Session.SessionGCMaxLifetime"] = BConfig.WebConfig.Session.SessionGCMaxLifetime
+	m["BConfig.WebConfig.Session.SessionProviderConfig"] = BConfig.WebConfig.Session.SessionProviderConfig
+	m["BConfig.WebConfig.Session.SessionCookieLifeTime"] = BConfig.WebConfig.Session.SessionCookieLifeTime
+	m["BConfig.WebConfig.Session.SessionAutoSetCookie"] = BConfig.WebConfig.Session.SessionAutoSetCookie
+	m["BConfig.WebConfig.Session.SessionDomain"] = BConfig.WebConfig.Session.SessionDomain
+	m["BConfig.WebConfig.Session.SessionDisableHTTPOnly"] = BConfig.WebConfig.Session.SessionDisableHTTPOnly
+	m["BConfig.Log.AccessLogs"] = BConfig.Log.AccessLogs
+	m["BConfig.Log.FileLineNum"] = BConfig.Log.FileLineNum
+	m["BConfig.Log.Outputs"] = BConfig.Log.Outputs
+	return m
+}

File diff suppressed because it is too large
+ 286 - 0
vendor/github.com/astaxie/beego/adminui.go


+ 366 - 0
vendor/github.com/astaxie/beego/app.go

@@ -0,0 +1,366 @@
+// 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 beego
+
+import (
+	"fmt"
+	"net"
+	"net/http"
+	"net/http/fcgi"
+	"os"
+	"path"
+	"time"
+
+	"github.com/astaxie/beego/grace"
+	"github.com/astaxie/beego/logs"
+	"github.com/astaxie/beego/utils"
+)
+
+var (
+	// BeeApp is an application instance
+	BeeApp *App
+)
+
+func init() {
+	// create beego application
+	BeeApp = NewApp()
+}
+
+// App defines beego application with a new PatternServeMux.
+type App struct {
+	Handlers *ControllerRegister
+	Server   *http.Server
+}
+
+// NewApp returns a new beego application.
+func NewApp() *App {
+	cr := NewControllerRegister()
+	app := &App{Handlers: cr, Server: &http.Server{}}
+	return app
+}
+
+// Run beego application.
+func (app *App) Run() {
+	addr := BConfig.Listen.HTTPAddr
+
+	if BConfig.Listen.HTTPPort != 0 {
+		addr = fmt.Sprintf("%s:%d", BConfig.Listen.HTTPAddr, BConfig.Listen.HTTPPort)
+	}
+
+	var (
+		err        error
+		l          net.Listener
+		endRunning = make(chan bool, 1)
+	)
+
+	// run cgi server
+	if BConfig.Listen.EnableFcgi {
+		if BConfig.Listen.EnableStdIo {
+			if err = fcgi.Serve(nil, app.Handlers); err == nil { // standard I/O
+				logs.Info("Use FCGI via standard I/O")
+			} else {
+				logs.Critical("Cannot use FCGI via standard I/O", err)
+			}
+			return
+		}
+		if BConfig.Listen.HTTPPort == 0 {
+			// remove the Socket file before start
+			if utils.FileExists(addr) {
+				os.Remove(addr)
+			}
+			l, err = net.Listen("unix", addr)
+		} else {
+			l, err = net.Listen("tcp", addr)
+		}
+		if err != nil {
+			logs.Critical("Listen: ", err)
+		}
+		if err = fcgi.Serve(l, app.Handlers); err != nil {
+			logs.Critical("fcgi.Serve: ", err)
+		}
+		return
+	}
+
+	app.Server.Handler = app.Handlers
+	app.Server.ReadTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second
+	app.Server.WriteTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second
+	app.Server.ErrorLog = logs.GetLogger("HTTP")
+
+	// run graceful mode
+	if BConfig.Listen.Graceful {
+		httpsAddr := BConfig.Listen.HTTPSAddr
+		app.Server.Addr = httpsAddr
+		if BConfig.Listen.EnableHTTPS {
+			go func() {
+				time.Sleep(20 * time.Microsecond)
+				if BConfig.Listen.HTTPSPort != 0 {
+					httpsAddr = fmt.Sprintf("%s:%d", BConfig.Listen.HTTPSAddr, BConfig.Listen.HTTPSPort)
+					app.Server.Addr = httpsAddr
+				}
+				server := grace.NewServer(httpsAddr, app.Handlers)
+				server.Server.ReadTimeout = app.Server.ReadTimeout
+				server.Server.WriteTimeout = app.Server.WriteTimeout
+				if err := server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil {
+					logs.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid()))
+					time.Sleep(100 * time.Microsecond)
+					endRunning <- true
+				}
+			}()
+		}
+		if BConfig.Listen.EnableHTTP {
+			go func() {
+				server := grace.NewServer(addr, app.Handlers)
+				server.Server.ReadTimeout = app.Server.ReadTimeout
+				server.Server.WriteTimeout = app.Server.WriteTimeout
+				if BConfig.Listen.ListenTCP4 {
+					server.Network = "tcp4"
+				}
+				if err := server.ListenAndServe(); err != nil {
+					logs.Critical("ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid()))
+					time.Sleep(100 * time.Microsecond)
+					endRunning <- true
+				}
+			}()
+		}
+		<-endRunning
+		return
+	}
+
+	// run normal mode
+	if BConfig.Listen.EnableHTTPS {
+		go func() {
+			time.Sleep(20 * time.Microsecond)
+			if BConfig.Listen.HTTPSPort != 0 {
+				app.Server.Addr = fmt.Sprintf("%s:%d", BConfig.Listen.HTTPSAddr, BConfig.Listen.HTTPSPort)
+			} else if BConfig.Listen.EnableHTTP {
+				BeeLogger.Info("Start https server error, confict with http.Please reset https port")
+				return
+			}
+			logs.Info("https server Running on https://%s", app.Server.Addr)
+			if err := app.Server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil {
+				logs.Critical("ListenAndServeTLS: ", err)
+				time.Sleep(100 * time.Microsecond)
+				endRunning <- true
+			}
+		}()
+	}
+	if BConfig.Listen.EnableHTTP {
+		go func() {
+			app.Server.Addr = addr
+			logs.Info("http server Running on http://%s", app.Server.Addr)
+			if BConfig.Listen.ListenTCP4 {
+				ln, err := net.Listen("tcp4", app.Server.Addr)
+				if err != nil {
+					logs.Critical("ListenAndServe: ", err)
+					time.Sleep(100 * time.Microsecond)
+					endRunning <- true
+					return
+				}
+				if err = app.Server.Serve(ln); err != nil {
+					logs.Critical("ListenAndServe: ", err)
+					time.Sleep(100 * time.Microsecond)
+					endRunning <- true
+					return
+				}
+			} else {
+				if err := app.Server.ListenAndServe(); err != nil {
+					logs.Critical("ListenAndServe: ", err)
+					time.Sleep(100 * time.Microsecond)
+					endRunning <- true
+				}
+			}
+		}()
+	}
+	<-endRunning
+}
+
+// Router adds a patterned controller handler to BeeApp.
+// it's an alias method of App.Router.
+// usage:
+//  simple router
+//  beego.Router("/admin", &admin.UserController{})
+//  beego.Router("/admin/index", &admin.ArticleController{})
+//
+//  regex router
+//
+//  beego.Router("/api/:id([0-9]+)", &controllers.RController{})
+//
+//  custom rules
+//  beego.Router("/api/list",&RestController{},"*:ListFood")
+//  beego.Router("/api/create",&RestController{},"post:CreateFood")
+//  beego.Router("/api/update",&RestController{},"put:UpdateFood")
+//  beego.Router("/api/delete",&RestController{},"delete:DeleteFood")
+func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *App {
+	BeeApp.Handlers.Add(rootpath, c, mappingMethods...)
+	return BeeApp
+}
+
+// Include will generate router file in the router/xxx.go from the controller's comments
+// usage:
+// beego.Include(&BankAccount{}, &OrderController{},&RefundController{},&ReceiptController{})
+// type BankAccount struct{
+//   beego.Controller
+// }
+//
+// register the function
+// func (b *BankAccount)Mapping(){
+//  b.Mapping("ShowAccount" , b.ShowAccount)
+//  b.Mapping("ModifyAccount", b.ModifyAccount)
+//}
+//
+// //@router /account/:id  [get]
+// func (b *BankAccount) ShowAccount(){
+//    //logic
+// }
+//
+//
+// //@router /account/:id  [post]
+// func (b *BankAccount) ModifyAccount(){
+//    //logic
+// }
+//
+// the comments @router url methodlist
+// url support all the function Router's pattern
+// methodlist [get post head put delete options *]
+func Include(cList ...ControllerInterface) *App {
+	BeeApp.Handlers.Include(cList...)
+	return BeeApp
+}
+
+// RESTRouter adds a restful controller handler to BeeApp.
+// its' controller implements beego.ControllerInterface and
+// defines a param "pattern/:objectId" to visit each resource.
+func RESTRouter(rootpath string, c ControllerInterface) *App {
+	Router(rootpath, c)
+	Router(path.Join(rootpath, ":objectId"), c)
+	return BeeApp
+}
+
+// AutoRouter adds defined controller handler to BeeApp.
+// it's same to App.AutoRouter.
+// if beego.AddAuto(&MainContorlller{}) and MainController has methods List and Page,
+// visit the url /main/list to exec List function or /main/page to exec Page function.
+func AutoRouter(c ControllerInterface) *App {
+	BeeApp.Handlers.AddAuto(c)
+	return BeeApp
+}
+
+// AutoPrefix adds controller handler to BeeApp with prefix.
+// it's same to App.AutoRouterWithPrefix.
+// if beego.AutoPrefix("/admin",&MainContorlller{}) and MainController has methods List and Page,
+// visit the url /admin/main/list to exec List function or /admin/main/page to exec Page function.
+func AutoPrefix(prefix string, c ControllerInterface) *App {
+	BeeApp.Handlers.AddAutoPrefix(prefix, c)
+	return BeeApp
+}
+
+// Get used to register router for Get method
+// usage:
+//    beego.Get("/", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Get(rootpath string, f FilterFunc) *App {
+	BeeApp.Handlers.Get(rootpath, f)
+	return BeeApp
+}
+
+// Post used to register router for Post method
+// usage:
+//    beego.Post("/api", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Post(rootpath string, f FilterFunc) *App {
+	BeeApp.Handlers.Post(rootpath, f)
+	return BeeApp
+}
+
+// Delete used to register router for Delete method
+// usage:
+//    beego.Delete("/api", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Delete(rootpath string, f FilterFunc) *App {
+	BeeApp.Handlers.Delete(rootpath, f)
+	return BeeApp
+}
+
+// Put used to register router for Put method
+// usage:
+//    beego.Put("/api", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Put(rootpath string, f FilterFunc) *App {
+	BeeApp.Handlers.Put(rootpath, f)
+	return BeeApp
+}
+
+// Head used to register router for Head method
+// usage:
+//    beego.Head("/api", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Head(rootpath string, f FilterFunc) *App {
+	BeeApp.Handlers.Head(rootpath, f)
+	return BeeApp
+}
+
+// Options used to register router for Options method
+// usage:
+//    beego.Options("/api", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Options(rootpath string, f FilterFunc) *App {
+	BeeApp.Handlers.Options(rootpath, f)
+	return BeeApp
+}
+
+// Patch used to register router for Patch method
+// usage:
+//    beego.Patch("/api", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Patch(rootpath string, f FilterFunc) *App {
+	BeeApp.Handlers.Patch(rootpath, f)
+	return BeeApp
+}
+
+// Any used to register router for all methods
+// usage:
+//    beego.Any("/api", func(ctx *context.Context){
+//          ctx.Output.Body("hello world")
+//    })
+func Any(rootpath string, f FilterFunc) *App {
+	BeeApp.Handlers.Any(rootpath, f)
+	return BeeApp
+}
+
+// Handler used to register a Handler router
+// usage:
+//    beego.Handler("/api", http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
+//          fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
+//    }))
+func Handler(rootpath string, h http.Handler, options ...interface{}) *App {
+	BeeApp.Handlers.Handler(rootpath, h, options...)
+	return BeeApp
+}
+
+// InsertFilter adds a FilterFunc with pattern condition and action constant.
+// The pos means action constant including
+// beego.BeforeStatic, beego.BeforeRouter, beego.BeforeExec, beego.AfterExec and beego.FinishRouter.
+// The bool params is for setting the returnOnOutput value (false allows multiple filters to execute)
+func InsertFilter(pattern string, pos int, filter FilterFunc, params ...bool) *App {
+	BeeApp.Handlers.InsertFilter(pattern, pos, filter, params...)
+	return BeeApp
+}

+ 100 - 0
vendor/github.com/astaxie/beego/beego.go

@@ -0,0 +1,100 @@
+// 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 beego
+
+import (
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+)
+
+const (
+	// VERSION represent beego web framework version.
+	VERSION = "1.8.3"
+
+	// DEV is for develop
+	DEV = "dev"
+	// PROD is for production
+	PROD = "prod"
+)
+
+//hook function to run
+type hookfunc func() error
+
+var (
+	hooks = make([]hookfunc, 0) //hook function slice to store the hookfunc
+)
+
+// AddAPPStartHook is used to register the hookfunc
+// The hookfuncs will run in beego.Run()
+// such as sessionInit, middlerware start, buildtemplate, admin start
+func AddAPPStartHook(hf hookfunc) {
+	hooks = append(hooks, hf)
+}
+
+// Run beego application.
+// beego.Run() default run on HttpPort
+// beego.Run("localhost")
+// beego.Run(":8089")
+// beego.Run("127.0.0.1:8089")
+func Run(params ...string) {
+
+	initBeforeHTTPRun()
+
+	if len(params) > 0 && params[0] != "" {
+		strs := strings.Split(params[0], ":")
+		if len(strs) > 0 && strs[0] != "" {
+			BConfig.Listen.HTTPAddr = strs[0]
+		}
+		if len(strs) > 1 && strs[1] != "" {
+			BConfig.Listen.HTTPPort, _ = strconv.Atoi(strs[1])
+		}
+	}
+
+	BeeApp.Run()
+}
+
+func initBeforeHTTPRun() {
+	//init hooks
+	AddAPPStartHook(registerMime)
+	AddAPPStartHook(registerDefaultErrorHandler)
+	AddAPPStartHook(registerSession)
+	AddAPPStartHook(registerTemplate)
+	AddAPPStartHook(registerAdmin)
+	AddAPPStartHook(registerGzip)
+
+	for _, hk := range hooks {
+		if err := hk(); err != nil {
+			panic(err)
+		}
+	}
+}
+
+// TestBeegoInit is for test package init
+func TestBeegoInit(ap string) {
+	path := filepath.Join(ap, "conf", "app.conf")
+	os.Chdir(ap)
+	InitBeegoBeforeTest(path)
+}
+
+// InitBeegoBeforeTest is for test package init
+func InitBeegoBeforeTest(appConfigPath string) {
+	if err := LoadAppConfig(appConfigProvider, appConfigPath); err != nil {
+		panic(err)
+	}
+	BConfig.RunMode = "test"
+	initBeforeHTTPRun()
+}

+ 59 - 0
vendor/github.com/astaxie/beego/cache/README.md

@@ -0,0 +1,59 @@
+## cache
+cache is a Go cache manager. It can use many cache adapters. The repo is inspired by `database/sql` .
+
+
+## How to install?
+
+	go get github.com/astaxie/beego/cache
+
+
+## What adapters are supported?
+
+As of now this cache support memory, Memcache and Redis.
+
+
+## How to use it?
+
+First you must import it
+
+	import (
+		"github.com/astaxie/beego/cache"
+	)
+
+Then init a Cache (example with memory adapter)
+
+	bm, err := cache.NewCache("memory", `{"interval":60}`)	
+
+Use it like this:	
+	
+	bm.Put("astaxie", 1, 10 * time.Second)
+	bm.Get("astaxie")
+	bm.IsExist("astaxie")
+	bm.Delete("astaxie")
+
+
+## Memory adapter
+
+Configure memory adapter like this:
+
+	{"interval":60}
+
+interval means the gc time. The cache will check at each time interval, whether item has expired.
+
+
+## Memcache adapter
+
+Memcache adapter use the [gomemcache](http://github.com/bradfitz/gomemcache) client.
+
+Configure like this:
+
+	{"conn":"127.0.0.1:11211"}
+
+
+## Redis adapter
+
+Redis adapter use the [redigo](http://github.com/garyburd/redigo) client.
+
+Configure like this:
+
+	{"conn":":6039"}

+ 103 - 0
vendor/github.com/astaxie/beego/cache/cache.go

@@ -0,0 +1,103 @@
+// 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 cache provide a Cache interface and some implemetn engine
+// Usage:
+//
+// import(
+//   "github.com/astaxie/beego/cache"
+// )
+//
+// bm, err := cache.NewCache("memory", `{"interval":60}`)
+//
+// Use it like this:
+//
+//	bm.Put("astaxie", 1, 10 * time.Second)
+//	bm.Get("astaxie")
+//	bm.IsExist("astaxie")
+//	bm.Delete("astaxie")
+//
+//  more docs http://beego.me/docs/module/cache.md
+package cache
+
+import (
+	"fmt"
+	"time"
+)
+
+// Cache interface contains all behaviors for cache adapter.
+// usage:
+//	cache.Register("file",cache.NewFileCache) // this operation is run in init method of file.go.
+//	c,err := cache.NewCache("file","{....}")
+//	c.Put("key",value, 3600 * time.Second)
+//	v := c.Get("key")
+//
+//	c.Incr("counter")  // now is 1
+//	c.Incr("counter")  // now is 2
+//	count := c.Get("counter").(int)
+type Cache interface {
+	// get cached value by key.
+	Get(key string) interface{}
+	// GetMulti is a batch version of Get.
+	GetMulti(keys []string) []interface{}
+	// set cached value with key and expire time.
+	Put(key string, val interface{}, timeout time.Duration) error
+	// delete cached value by key.
+	Delete(key string) error
+	// increase cached int value by key, as a counter.
+	Incr(key string) error
+	// decrease cached int value by key, as a counter.
+	Decr(key string) error
+	// check if cached value exists or not.
+	IsExist(key string) bool
+	// clear all cache.
+	ClearAll() error
+	// start gc routine based on config string settings.
+	StartAndGC(config string) error
+}
+
+// Instance is a function create a new Cache Instance
+type Instance func() Cache
+
+var adapters = make(map[string]Instance)
+
+// Register makes a cache adapter available by the adapter name.
+// If Register is called twice with the same name or if driver is nil,
+// it panics.
+func Register(name string, adapter Instance) {
+	if adapter == nil {
+		panic("cache: Register adapter is nil")
+	}
+	if _, ok := adapters[name]; ok {
+		panic("cache: Register called twice for adapter " + name)
+	}
+	adapters[name] = adapter
+}
+
+// NewCache Create a new cache driver by adapter name and config string.
+// config need to be correct JSON as string: {"interval":360}.
+// it will start gc automatically.
+func NewCache(adapterName, config string) (adapter Cache, err error) {
+	instanceFunc, ok := adapters[adapterName]
+	if !ok {
+		err = fmt.Errorf("cache: unknown adapter name %q (forgot to import?)", adapterName)
+		return
+	}
+	adapter = instanceFunc()
+	err = adapter.StartAndGC(config)
+	if err != nil {
+		adapter = nil
+	}
+	return
+}

+ 168 - 0
vendor/github.com/astaxie/beego/cache/cache_test.go

@@ -0,0 +1,168 @@
+// 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 cache
+
+import (
+	"os"
+	"testing"
+	"time"
+)
+
+func TestCache(t *testing.T) {
+	bm, err := NewCache("memory", `{"interval":20}`)
+	if err != nil {
+		t.Error("init err")
+	}
+	timeoutDuration := 10 * time.Second
+	if err = bm.Put("astaxie", 1, timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+
+	if v := bm.Get("astaxie"); v.(int) != 1 {
+		t.Error("get err")
+	}
+
+	time.Sleep(30 * time.Second)
+
+	if bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+
+	if err = bm.Put("astaxie", 1, timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+
+	if err = bm.Incr("astaxie"); err != nil {
+		t.Error("Incr Error", err)
+	}
+
+	if v := bm.Get("astaxie"); v.(int) != 2 {
+		t.Error("get err")
+	}
+
+	if err = bm.Decr("astaxie"); err != nil {
+		t.Error("Decr Error", err)
+	}
+
+	if v := bm.Get("astaxie"); v.(int) != 1 {
+		t.Error("get err")
+	}
+	bm.Delete("astaxie")
+	if bm.IsExist("astaxie") {
+		t.Error("delete err")
+	}
+
+	//test GetMulti
+	if err = bm.Put("astaxie", "author", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+	if v := bm.Get("astaxie"); v.(string) != "author" {
+		t.Error("get err")
+	}
+
+	if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie1") {
+		t.Error("check err")
+	}
+
+	vv := bm.GetMulti([]string{"astaxie", "astaxie1"})
+	if len(vv) != 2 {
+		t.Error("GetMulti ERROR")
+	}
+	if vv[0].(string) != "author" {
+		t.Error("GetMulti ERROR")
+	}
+	if vv[1].(string) != "author1" {
+		t.Error("GetMulti ERROR")
+	}
+}
+
+func TestFileCache(t *testing.T) {
+	bm, err := NewCache("file", `{"CachePath":"cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0}`)
+	if err != nil {
+		t.Error("init err")
+	}
+	timeoutDuration := 10 * time.Second
+	if err = bm.Put("astaxie", 1, timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+
+	if v := bm.Get("astaxie"); v.(int) != 1 {
+		t.Error("get err")
+	}
+
+	if err = bm.Incr("astaxie"); err != nil {
+		t.Error("Incr Error", err)
+	}
+
+	if v := bm.Get("astaxie"); v.(int) != 2 {
+		t.Error("get err")
+	}
+
+	if err = bm.Decr("astaxie"); err != nil {
+		t.Error("Decr Error", err)
+	}
+
+	if v := bm.Get("astaxie"); v.(int) != 1 {
+		t.Error("get err")
+	}
+	bm.Delete("astaxie")
+	if bm.IsExist("astaxie") {
+		t.Error("delete err")
+	}
+
+	//test string
+	if err = bm.Put("astaxie", "author", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+	if v := bm.Get("astaxie"); v.(string) != "author" {
+		t.Error("get err")
+	}
+
+	//test GetMulti
+	if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie1") {
+		t.Error("check err")
+	}
+
+	vv := bm.GetMulti([]string{"astaxie", "astaxie1"})
+	if len(vv) != 2 {
+		t.Error("GetMulti ERROR")
+	}
+	if vv[0].(string) != "author" {
+		t.Error("GetMulti ERROR")
+	}
+	if vv[1].(string) != "author1" {
+		t.Error("GetMulti ERROR")
+	}
+
+	os.RemoveAll("cache")
+}

+ 100 - 0
vendor/github.com/astaxie/beego/cache/conv.go

@@ -0,0 +1,100 @@
+// 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 cache
+
+import (
+	"fmt"
+	"strconv"
+)
+
+// GetString convert interface to string.
+func GetString(v interface{}) string {
+	switch result := v.(type) {
+	case string:
+		return result
+	case []byte:
+		return string(result)
+	default:
+		if v != nil {
+			return fmt.Sprint(result)
+		}
+	}
+	return ""
+}
+
+// GetInt convert interface to int.
+func GetInt(v interface{}) int {
+	switch result := v.(type) {
+	case int:
+		return result
+	case int32:
+		return int(result)
+	case int64:
+		return int(result)
+	default:
+		if d := GetString(v); d != "" {
+			value, _ := strconv.Atoi(d)
+			return value
+		}
+	}
+	return 0
+}
+
+// GetInt64 convert interface to int64.
+func GetInt64(v interface{}) int64 {
+	switch result := v.(type) {
+	case int:
+		return int64(result)
+	case int32:
+		return int64(result)
+	case int64:
+		return result
+	default:
+
+		if d := GetString(v); d != "" {
+			value, _ := strconv.ParseInt(d, 10, 64)
+			return value
+		}
+	}
+	return 0
+}
+
+// GetFloat64 convert interface to float64.
+func GetFloat64(v interface{}) float64 {
+	switch result := v.(type) {
+	case float64:
+		return result
+	default:
+		if d := GetString(v); d != "" {
+			value, _ := strconv.ParseFloat(d, 64)
+			return value
+		}
+	}
+	return 0
+}
+
+// GetBool convert interface to bool.
+func GetBool(v interface{}) bool {
+	switch result := v.(type) {
+	case bool:
+		return result
+	default:
+		if d := GetString(v); d != "" {
+			value, _ := strconv.ParseBool(d)
+			return value
+		}
+	}
+	return false
+}

+ 143 - 0
vendor/github.com/astaxie/beego/cache/conv_test.go

@@ -0,0 +1,143 @@
+// 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 cache
+
+import (
+	"testing"
+)
+
+func TestGetString(t *testing.T) {
+	var t1 = "test1"
+	if "test1" != GetString(t1) {
+		t.Error("get string from string error")
+	}
+	var t2 = []byte("test2")
+	if "test2" != GetString(t2) {
+		t.Error("get string from byte array error")
+	}
+	var t3 = 1
+	if "1" != GetString(t3) {
+		t.Error("get string from int error")
+	}
+	var t4 int64 = 1
+	if "1" != GetString(t4) {
+		t.Error("get string from int64 error")
+	}
+	var t5 = 1.1
+	if "1.1" != GetString(t5) {
+		t.Error("get string from float64 error")
+	}
+
+	if "" != GetString(nil) {
+		t.Error("get string from nil error")
+	}
+}
+
+func TestGetInt(t *testing.T) {
+	var t1 = 1
+	if 1 != GetInt(t1) {
+		t.Error("get int from int error")
+	}
+	var t2 int32 = 32
+	if 32 != GetInt(t2) {
+		t.Error("get int from int32 error")
+	}
+	var t3 int64 = 64
+	if 64 != GetInt(t3) {
+		t.Error("get int from int64 error")
+	}
+	var t4 = "128"
+	if 128 != GetInt(t4) {
+		t.Error("get int from num string error")
+	}
+	if 0 != GetInt(nil) {
+		t.Error("get int from nil error")
+	}
+}
+
+func TestGetInt64(t *testing.T) {
+	var i int64 = 1
+	var t1 = 1
+	if i != GetInt64(t1) {
+		t.Error("get int64 from int error")
+	}
+	var t2 int32 = 1
+	if i != GetInt64(t2) {
+		t.Error("get int64 from int32 error")
+	}
+	var t3 int64 = 1
+	if i != GetInt64(t3) {
+		t.Error("get int64 from int64 error")
+	}
+	var t4 = "1"
+	if i != GetInt64(t4) {
+		t.Error("get int64 from num string error")
+	}
+	if 0 != GetInt64(nil) {
+		t.Error("get int64 from nil")
+	}
+}
+
+func TestGetFloat64(t *testing.T) {
+	var f = 1.11
+	var t1 float32 = 1.11
+	if f != GetFloat64(t1) {
+		t.Error("get float64 from float32 error")
+	}
+	var t2 = 1.11
+	if f != GetFloat64(t2) {
+		t.Error("get float64 from float64 error")
+	}
+	var t3 = "1.11"
+	if f != GetFloat64(t3) {
+		t.Error("get float64 from string error")
+	}
+
+	var f2 float64 = 1
+	var t4 = 1
+	if f2 != GetFloat64(t4) {
+		t.Error("get float64 from int error")
+	}
+
+	if 0 != GetFloat64(nil) {
+		t.Error("get float64 from nil error")
+	}
+}
+
+func TestGetBool(t *testing.T) {
+	var t1 = true
+	if !GetBool(t1) {
+		t.Error("get bool from bool error")
+	}
+	var t2 = "true"
+	if !GetBool(t2) {
+		t.Error("get bool from string error")
+	}
+	if GetBool(nil) {
+		t.Error("get bool from nil error")
+	}
+}
+
+func byteArrayEquals(a []byte, b []byte) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	for i, v := range a {
+		if v != b[i] {
+			return false
+		}
+	}
+	return true
+}

+ 255 - 0
vendor/github.com/astaxie/beego/cache/file.go

@@ -0,0 +1,255 @@
+// 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 cache
+
+import (
+	"bytes"
+	"crypto/md5"
+	"encoding/gob"
+	"encoding/hex"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"reflect"
+	"strconv"
+	"time"
+)
+
+// FileCacheItem is basic unit of file cache adapter.
+// it contains data and expire time.
+type FileCacheItem struct {
+	Data       interface{}
+	Lastaccess time.Time
+	Expired    time.Time
+}
+
+// FileCache Config
+var (
+	FileCachePath           = "cache"     // cache directory
+	FileCacheFileSuffix     = ".bin"      // cache file suffix
+	FileCacheDirectoryLevel = 2           // cache file deep level if auto generated cache files.
+	FileCacheEmbedExpiry    time.Duration // cache expire time, default is no expire forever.
+)
+
+// FileCache is cache adapter for file storage.
+type FileCache struct {
+	CachePath      string
+	FileSuffix     string
+	DirectoryLevel int
+	EmbedExpiry    int
+}
+
+// NewFileCache Create new file cache with no config.
+// the level and expiry need set in method StartAndGC as config string.
+func NewFileCache() Cache {
+	//    return &FileCache{CachePath:FileCachePath, FileSuffix:FileCacheFileSuffix}
+	return &FileCache{}
+}
+
+// StartAndGC will start and begin gc for file cache.
+// the config need to be like {CachePath:"/cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0}
+func (fc *FileCache) StartAndGC(config string) error {
+
+	var cfg map[string]string
+	json.Unmarshal([]byte(config), &cfg)
+	if _, ok := cfg["CachePath"]; !ok {
+		cfg["CachePath"] = FileCachePath
+	}
+	if _, ok := cfg["FileSuffix"]; !ok {
+		cfg["FileSuffix"] = FileCacheFileSuffix
+	}
+	if _, ok := cfg["DirectoryLevel"]; !ok {
+		cfg["DirectoryLevel"] = strconv.Itoa(FileCacheDirectoryLevel)
+	}
+	if _, ok := cfg["EmbedExpiry"]; !ok {
+		cfg["EmbedExpiry"] = strconv.FormatInt(int64(FileCacheEmbedExpiry.Seconds()), 10)
+	}
+	fc.CachePath = cfg["CachePath"]
+	fc.FileSuffix = cfg["FileSuffix"]
+	fc.DirectoryLevel, _ = strconv.Atoi(cfg["DirectoryLevel"])
+	fc.EmbedExpiry, _ = strconv.Atoi(cfg["EmbedExpiry"])
+
+	fc.Init()
+	return nil
+}
+
+// Init will make new dir for file cache if not exist.
+func (fc *FileCache) Init() {
+	if ok, _ := exists(fc.CachePath); !ok { // todo : error handle
+		_ = os.MkdirAll(fc.CachePath, os.ModePerm) // todo : error handle
+	}
+}
+
+// get cached file name. it's md5 encoded.
+func (fc *FileCache) getCacheFileName(key string) string {
+	m := md5.New()
+	io.WriteString(m, key)
+	keyMd5 := hex.EncodeToString(m.Sum(nil))
+	cachePath := fc.CachePath
+	switch fc.DirectoryLevel {
+	case 2:
+		cachePath = filepath.Join(cachePath, keyMd5[0:2], keyMd5[2:4])
+	case 1:
+		cachePath = filepath.Join(cachePath, keyMd5[0:2])
+	}
+
+	if ok, _ := exists(cachePath); !ok { // todo : error handle
+		_ = os.MkdirAll(cachePath, os.ModePerm) // todo : error handle
+	}
+
+	return filepath.Join(cachePath, fmt.Sprintf("%s%s", keyMd5, fc.FileSuffix))
+}
+
+// Get value from file cache.
+// if non-exist or expired, return empty string.
+func (fc *FileCache) Get(key string) interface{} {
+	fileData, err := FileGetContents(fc.getCacheFileName(key))
+	if err != nil {
+		return ""
+	}
+	var to FileCacheItem
+	GobDecode(fileData, &to)
+	if to.Expired.Before(time.Now()) {
+		return ""
+	}
+	return to.Data
+}
+
+// GetMulti gets values from file cache.
+// if non-exist or expired, return empty string.
+func (fc *FileCache) GetMulti(keys []string) []interface{} {
+	var rc []interface{}
+	for _, key := range keys {
+		rc = append(rc, fc.Get(key))
+	}
+	return rc
+}
+
+// Put value into file cache.
+// timeout means how long to keep this file, unit of ms.
+// if timeout equals FileCacheEmbedExpiry(default is 0), cache this item forever.
+func (fc *FileCache) Put(key string, val interface{}, timeout time.Duration) error {
+	gob.Register(val)
+
+	item := FileCacheItem{Data: val}
+	if timeout == FileCacheEmbedExpiry {
+		item.Expired = time.Now().Add((86400 * 365 * 10) * time.Second) // ten years
+	} else {
+		item.Expired = time.Now().Add(timeout)
+	}
+	item.Lastaccess = time.Now()
+	data, err := GobEncode(item)
+	if err != nil {
+		return err
+	}
+	return FilePutContents(fc.getCacheFileName(key), data)
+}
+
+// Delete file cache value.
+func (fc *FileCache) Delete(key string) error {
+	filename := fc.getCacheFileName(key)
+	if ok, _ := exists(filename); ok {
+		return os.Remove(filename)
+	}
+	return nil
+}
+
+// Incr will increase cached int value.
+// fc value is saving forever unless Delete.
+func (fc *FileCache) Incr(key string) error {
+	data := fc.Get(key)
+	var incr int
+	if reflect.TypeOf(data).Name() != "int" {
+		incr = 0
+	} else {
+		incr = data.(int) + 1
+	}
+	fc.Put(key, incr, FileCacheEmbedExpiry)
+	return nil
+}
+
+// Decr will decrease cached int value.
+func (fc *FileCache) Decr(key string) error {
+	data := fc.Get(key)
+	var decr int
+	if reflect.TypeOf(data).Name() != "int" || data.(int)-1 <= 0 {
+		decr = 0
+	} else {
+		decr = data.(int) - 1
+	}
+	fc.Put(key, decr, FileCacheEmbedExpiry)
+	return nil
+}
+
+// IsExist check value is exist.
+func (fc *FileCache) IsExist(key string) bool {
+	ret, _ := exists(fc.getCacheFileName(key))
+	return ret
+}
+
+// ClearAll will clean cached files.
+// not implemented.
+func (fc *FileCache) ClearAll() error {
+	return nil
+}
+
+// check file exist.
+func exists(path string) (bool, error) {
+	_, err := os.Stat(path)
+	if err == nil {
+		return true, nil
+	}
+	if os.IsNotExist(err) {
+		return false, nil
+	}
+	return false, err
+}
+
+// FileGetContents Get bytes to file.
+// if non-exist, create this file.
+func FileGetContents(filename string) (data []byte, e error) {
+	return ioutil.ReadFile(filename)
+}
+
+// FilePutContents Put bytes to file.
+// if non-exist, create this file.
+func FilePutContents(filename string, content []byte) error {
+	return ioutil.WriteFile(filename, content, os.ModePerm)
+}
+
+// GobEncode Gob encodes file cache item.
+func GobEncode(data interface{}) ([]byte, error) {
+	buf := bytes.NewBuffer(nil)
+	enc := gob.NewEncoder(buf)
+	err := enc.Encode(data)
+	if err != nil {
+		return nil, err
+	}
+	return buf.Bytes(), err
+}
+
+// GobDecode Gob decodes file cache item.
+func GobDecode(data []byte, to *FileCacheItem) error {
+	buf := bytes.NewBuffer(data)
+	dec := gob.NewDecoder(buf)
+	return dec.Decode(&to)
+}
+
+func init() {
+	Register("file", NewFileCache)
+}

+ 188 - 0
vendor/github.com/astaxie/beego/cache/memcache/memcache.go

@@ -0,0 +1,188 @@
+// 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 memcache for cache provider
+//
+// depend on github.com/bradfitz/gomemcache/memcache
+//
+// go install github.com/bradfitz/gomemcache/memcache
+//
+// Usage:
+// import(
+//   _ "github.com/astaxie/beego/cache/memcache"
+//   "github.com/astaxie/beego/cache"
+// )
+//
+//  bm, err := cache.NewCache("memcache", `{"conn":"127.0.0.1:11211"}`)
+//
+//  more docs http://beego.me/docs/module/cache.md
+package memcache
+
+import (
+	"encoding/json"
+	"errors"
+	"strings"
+	"time"
+
+	"github.com/astaxie/beego/cache"
+	"github.com/bradfitz/gomemcache/memcache"
+)
+
+// Cache Memcache adapter.
+type Cache struct {
+	conn     *memcache.Client
+	conninfo []string
+}
+
+// NewMemCache create new memcache adapter.
+func NewMemCache() cache.Cache {
+	return &Cache{}
+}
+
+// Get get value from memcache.
+func (rc *Cache) Get(key string) interface{} {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	if item, err := rc.conn.Get(key); err == nil {
+		return item.Value
+	}
+	return nil
+}
+
+// GetMulti get value from memcache.
+func (rc *Cache) GetMulti(keys []string) []interface{} {
+	size := len(keys)
+	var rv []interface{}
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			for i := 0; i < size; i++ {
+				rv = append(rv, err)
+			}
+			return rv
+		}
+	}
+	mv, err := rc.conn.GetMulti(keys)
+	if err == nil {
+		for _, v := range mv {
+			rv = append(rv, v.Value)
+		}
+		return rv
+	}
+	for i := 0; i < size; i++ {
+		rv = append(rv, err)
+	}
+	return rv
+}
+
+// Put put value to memcache.
+func (rc *Cache) Put(key string, val interface{}, timeout time.Duration) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	item := memcache.Item{Key: key, Expiration: int32(timeout / time.Second)}
+	if v, ok := val.([]byte); ok {
+		item.Value = v
+	} else if str, ok := val.(string); ok {
+		item.Value = []byte(str)
+	} else {
+		return errors.New("val only support string and []byte")
+	}
+	return rc.conn.Set(&item)
+}
+
+// Delete delete value in memcache.
+func (rc *Cache) Delete(key string) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	return rc.conn.Delete(key)
+}
+
+// Incr increase counter.
+func (rc *Cache) Incr(key string) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	_, err := rc.conn.Increment(key, 1)
+	return err
+}
+
+// Decr decrease counter.
+func (rc *Cache) Decr(key string) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	_, err := rc.conn.Decrement(key, 1)
+	return err
+}
+
+// IsExist check value exists in memcache.
+func (rc *Cache) IsExist(key string) bool {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return false
+		}
+	}
+	_, err := rc.conn.Get(key)
+	return !(err != nil)
+}
+
+// ClearAll clear all cached in memcache.
+func (rc *Cache) ClearAll() error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	return rc.conn.FlushAll()
+}
+
+// StartAndGC start memcache adapter.
+// config string is like {"conn":"connection info"}.
+// if connecting error, return.
+func (rc *Cache) StartAndGC(config string) error {
+	var cf map[string]string
+	json.Unmarshal([]byte(config), &cf)
+	if _, ok := cf["conn"]; !ok {
+		return errors.New("config has no conn key")
+	}
+	rc.conninfo = strings.Split(cf["conn"], ";")
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// connect to memcache and keep the connection.
+func (rc *Cache) connectInit() error {
+	rc.conn = memcache.New(rc.conninfo...)
+	return nil
+}
+
+func init() {
+	cache.Register("memcache", NewMemCache)
+}

+ 108 - 0
vendor/github.com/astaxie/beego/cache/memcache/memcache_test.go

@@ -0,0 +1,108 @@
+// 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 memcache
+
+import (
+	_ "github.com/bradfitz/gomemcache/memcache"
+
+	"strconv"
+	"testing"
+	"time"
+
+	"github.com/astaxie/beego/cache"
+)
+
+func TestMemcacheCache(t *testing.T) {
+	bm, err := cache.NewCache("memcache", `{"conn": "127.0.0.1:11211"}`)
+	if err != nil {
+		t.Error("init err")
+	}
+	timeoutDuration := 10 * time.Second
+	if err = bm.Put("astaxie", "1", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+
+	time.Sleep(11 * time.Second)
+
+	if bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+	if err = bm.Put("astaxie", "1", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+
+	if v, err := strconv.Atoi(string(bm.Get("astaxie").([]byte))); err != nil || v != 1 {
+		t.Error("get err")
+	}
+
+	if err = bm.Incr("astaxie"); err != nil {
+		t.Error("Incr Error", err)
+	}
+
+	if v, err := strconv.Atoi(string(bm.Get("astaxie").([]byte))); err != nil || v != 2 {
+		t.Error("get err")
+	}
+
+	if err = bm.Decr("astaxie"); err != nil {
+		t.Error("Decr Error", err)
+	}
+
+	if v, err := strconv.Atoi(string(bm.Get("astaxie").([]byte))); err != nil || v != 1 {
+		t.Error("get err")
+	}
+	bm.Delete("astaxie")
+	if bm.IsExist("astaxie") {
+		t.Error("delete err")
+	}
+
+	//test string
+	if err = bm.Put("astaxie", "author", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+
+	if v := bm.Get("astaxie").([]byte); string(v) != "author" {
+		t.Error("get err")
+	}
+
+	//test GetMulti
+	if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie1") {
+		t.Error("check err")
+	}
+
+	vv := bm.GetMulti([]string{"astaxie", "astaxie1"})
+	if len(vv) != 2 {
+		t.Error("GetMulti ERROR")
+	}
+	if string(vv[0].([]byte)) != "author" && string(vv[0].([]byte)) != "author1" {
+		t.Error("GetMulti ERROR")
+	}
+	if string(vv[1].([]byte)) != "author1" && string(vv[1].([]byte)) != "author" {
+		t.Error("GetMulti ERROR")
+	}
+
+	// test clear all
+	if err = bm.ClearAll(); err != nil {
+		t.Error("clear all err")
+	}
+}

+ 244 - 0
vendor/github.com/astaxie/beego/cache/memory.go

@@ -0,0 +1,244 @@
+// 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 cache
+
+import (
+	"encoding/json"
+	"errors"
+	"sync"
+	"time"
+)
+
+var (
+	// DefaultEvery means the clock time of recycling the expired cache items in memory.
+	DefaultEvery = 60 // 1 minute
+)
+
+// MemoryItem store memory cache item.
+type MemoryItem struct {
+	val         interface{}
+	createdTime time.Time
+	lifespan    time.Duration
+}
+
+func (mi *MemoryItem) isExpire() bool {
+	// 0 means forever
+	if mi.lifespan == 0 {
+		return false
+	}
+	return time.Now().Sub(mi.createdTime) > mi.lifespan
+}
+
+// MemoryCache is Memory cache adapter.
+// it contains a RW locker for safe map storage.
+type MemoryCache struct {
+	sync.RWMutex
+	dur   time.Duration
+	items map[string]*MemoryItem
+	Every int // run an expiration check Every clock time
+}
+
+// NewMemoryCache returns a new MemoryCache.
+func NewMemoryCache() Cache {
+	cache := MemoryCache{items: make(map[string]*MemoryItem)}
+	return &cache
+}
+
+// Get cache from memory.
+// if non-existed or expired, return nil.
+func (bc *MemoryCache) Get(name string) interface{} {
+	bc.RLock()
+	defer bc.RUnlock()
+	if itm, ok := bc.items[name]; ok {
+		if itm.isExpire() {
+			return nil
+		}
+		return itm.val
+	}
+	return nil
+}
+
+// GetMulti gets caches from memory.
+// if non-existed or expired, return nil.
+func (bc *MemoryCache) GetMulti(names []string) []interface{} {
+	var rc []interface{}
+	for _, name := range names {
+		rc = append(rc, bc.Get(name))
+	}
+	return rc
+}
+
+// Put cache to memory.
+// if lifespan is 0, it will be forever till restart.
+func (bc *MemoryCache) Put(name string, value interface{}, lifespan time.Duration) error {
+	bc.Lock()
+	defer bc.Unlock()
+	bc.items[name] = &MemoryItem{
+		val:         value,
+		createdTime: time.Now(),
+		lifespan:    lifespan,
+	}
+	return nil
+}
+
+// Delete cache in memory.
+func (bc *MemoryCache) Delete(name string) error {
+	bc.Lock()
+	defer bc.Unlock()
+	if _, ok := bc.items[name]; !ok {
+		return errors.New("key not exist")
+	}
+	delete(bc.items, name)
+	if _, ok := bc.items[name]; ok {
+		return errors.New("delete key error")
+	}
+	return nil
+}
+
+// Incr increase cache counter in memory.
+// it supports int,int32,int64,uint,uint32,uint64.
+func (bc *MemoryCache) Incr(key string) error {
+	bc.RLock()
+	defer bc.RUnlock()
+	itm, ok := bc.items[key]
+	if !ok {
+		return errors.New("key not exist")
+	}
+	switch itm.val.(type) {
+	case int:
+		itm.val = itm.val.(int) + 1
+	case int32:
+		itm.val = itm.val.(int32) + 1
+	case int64:
+		itm.val = itm.val.(int64) + 1
+	case uint:
+		itm.val = itm.val.(uint) + 1
+	case uint32:
+		itm.val = itm.val.(uint32) + 1
+	case uint64:
+		itm.val = itm.val.(uint64) + 1
+	default:
+		return errors.New("item val is not (u)int (u)int32 (u)int64")
+	}
+	return nil
+}
+
+// Decr decrease counter in memory.
+func (bc *MemoryCache) Decr(key string) error {
+	bc.RLock()
+	defer bc.RUnlock()
+	itm, ok := bc.items[key]
+	if !ok {
+		return errors.New("key not exist")
+	}
+	switch itm.val.(type) {
+	case int:
+		itm.val = itm.val.(int) - 1
+	case int64:
+		itm.val = itm.val.(int64) - 1
+	case int32:
+		itm.val = itm.val.(int32) - 1
+	case uint:
+		if itm.val.(uint) > 0 {
+			itm.val = itm.val.(uint) - 1
+		} else {
+			return errors.New("item val is less than 0")
+		}
+	case uint32:
+		if itm.val.(uint32) > 0 {
+			itm.val = itm.val.(uint32) - 1
+		} else {
+			return errors.New("item val is less than 0")
+		}
+	case uint64:
+		if itm.val.(uint64) > 0 {
+			itm.val = itm.val.(uint64) - 1
+		} else {
+			return errors.New("item val is less than 0")
+		}
+	default:
+		return errors.New("item val is not int int64 int32")
+	}
+	return nil
+}
+
+// IsExist check cache exist in memory.
+func (bc *MemoryCache) IsExist(name string) bool {
+	bc.RLock()
+	defer bc.RUnlock()
+	if v, ok := bc.items[name]; ok {
+		return !v.isExpire()
+	}
+	return false
+}
+
+// ClearAll will delete all cache in memory.
+func (bc *MemoryCache) ClearAll() error {
+	bc.Lock()
+	defer bc.Unlock()
+	bc.items = make(map[string]*MemoryItem)
+	return nil
+}
+
+// StartAndGC start memory cache. it will check expiration in every clock time.
+func (bc *MemoryCache) StartAndGC(config string) error {
+	var cf map[string]int
+	json.Unmarshal([]byte(config), &cf)
+	if _, ok := cf["interval"]; !ok {
+		cf = make(map[string]int)
+		cf["interval"] = DefaultEvery
+	}
+	dur := time.Duration(cf["interval"]) * time.Second
+	bc.Every = cf["interval"]
+	bc.dur = dur
+	go bc.vaccuum()
+	return nil
+}
+
+// check expiration.
+func (bc *MemoryCache) vaccuum() {
+	if bc.Every < 1 {
+		return
+	}
+	for {
+		<-time.After(bc.dur)
+		if bc.items == nil {
+			return
+		}
+		for name := range bc.items {
+			bc.itemExpired(name)
+		}
+	}
+}
+
+// itemExpired returns true if an item is expired.
+func (bc *MemoryCache) itemExpired(name string) bool {
+	bc.Lock()
+	defer bc.Unlock()
+
+	itm, ok := bc.items[name]
+	if !ok {
+		return true
+	}
+	if itm.isExpire() {
+		delete(bc.items, name)
+		return true
+	}
+	return false
+}
+
+func init() {
+	Register("memory", NewMemoryCache)
+}

+ 240 - 0
vendor/github.com/astaxie/beego/cache/redis/redis.go

@@ -0,0 +1,240 @@
+// 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 redis for cache provider
+//
+// depend on github.com/garyburd/redigo/redis
+//
+// go install github.com/garyburd/redigo/redis
+//
+// Usage:
+// import(
+//   _ "github.com/astaxie/beego/cache/redis"
+//   "github.com/astaxie/beego/cache"
+// )
+//
+//  bm, err := cache.NewCache("redis", `{"conn":"127.0.0.1:11211"}`)
+//
+//  more docs http://beego.me/docs/module/cache.md
+package redis
+
+import (
+	"encoding/json"
+	"errors"
+	"strconv"
+	"time"
+
+	"github.com/garyburd/redigo/redis"
+
+	"github.com/astaxie/beego/cache"
+)
+
+var (
+	// DefaultKey the collection name of redis for cache adapter.
+	DefaultKey = "beecacheRedis"
+)
+
+// Cache is Redis cache adapter.
+type Cache struct {
+	p        *redis.Pool // redis connection pool
+	conninfo string
+	dbNum    int
+	key      string
+	password string
+}
+
+// NewRedisCache create new redis cache with default collection name.
+func NewRedisCache() cache.Cache {
+	return &Cache{key: DefaultKey}
+}
+
+// actually do the redis cmds
+func (rc *Cache) do(commandName string, args ...interface{}) (reply interface{}, err error) {
+	c := rc.p.Get()
+	defer c.Close()
+
+	return c.Do(commandName, args...)
+}
+
+// Get cache from redis.
+func (rc *Cache) Get(key string) interface{} {
+	if v, err := rc.do("GET", key); err == nil {
+		return v
+	}
+	return nil
+}
+
+// GetMulti get cache from redis.
+func (rc *Cache) GetMulti(keys []string) []interface{} {
+	size := len(keys)
+	var rv []interface{}
+	c := rc.p.Get()
+	defer c.Close()
+	var err error
+	for _, key := range keys {
+		err = c.Send("GET", key)
+		if err != nil {
+			goto ERROR
+		}
+	}
+	if err = c.Flush(); err != nil {
+		goto ERROR
+	}
+	for i := 0; i < size; i++ {
+		if v, err := c.Receive(); err == nil {
+			rv = append(rv, v.([]byte))
+		} else {
+			rv = append(rv, err)
+		}
+	}
+	return rv
+ERROR:
+	rv = rv[0:0]
+	for i := 0; i < size; i++ {
+		rv = append(rv, nil)
+	}
+
+	return rv
+}
+
+// Put put cache to redis.
+func (rc *Cache) Put(key string, val interface{}, timeout time.Duration) error {
+	var err error
+	if _, err = rc.do("SETEX", key, int64(timeout/time.Second), val); err != nil {
+		return err
+	}
+
+	if _, err = rc.do("HSET", rc.key, key, true); err != nil {
+		return err
+	}
+	return err
+}
+
+// Delete delete cache in redis.
+func (rc *Cache) Delete(key string) error {
+	var err error
+	if _, err = rc.do("DEL", key); err != nil {
+		return err
+	}
+	_, err = rc.do("HDEL", rc.key, key)
+	return err
+}
+
+// IsExist check cache's existence in redis.
+func (rc *Cache) IsExist(key string) bool {
+	v, err := redis.Bool(rc.do("EXISTS", key))
+	if err != nil {
+		return false
+	}
+	if !v {
+		if _, err = rc.do("HDEL", rc.key, key); err != nil {
+			return false
+		}
+	}
+	return v
+}
+
+// Incr increase counter in redis.
+func (rc *Cache) Incr(key string) error {
+	_, err := redis.Bool(rc.do("INCRBY", key, 1))
+	return err
+}
+
+// Decr decrease counter in redis.
+func (rc *Cache) Decr(key string) error {
+	_, err := redis.Bool(rc.do("INCRBY", key, -1))
+	return err
+}
+
+// ClearAll clean all cache in redis. delete this redis collection.
+func (rc *Cache) ClearAll() error {
+	cachedKeys, err := redis.Strings(rc.do("HKEYS", rc.key))
+	if err != nil {
+		return err
+	}
+	for _, str := range cachedKeys {
+		if _, err = rc.do("DEL", str); err != nil {
+			return err
+		}
+	}
+	_, err = rc.do("DEL", rc.key)
+	return err
+}
+
+// StartAndGC start redis cache adapter.
+// config is like {"key":"collection key","conn":"connection info","dbNum":"0"}
+// the cache item in redis are stored forever,
+// so no gc operation.
+func (rc *Cache) StartAndGC(config string) error {
+	var cf map[string]string
+	json.Unmarshal([]byte(config), &cf)
+
+	if _, ok := cf["key"]; !ok {
+		cf["key"] = DefaultKey
+	}
+	if _, ok := cf["conn"]; !ok {
+		return errors.New("config has no conn key")
+	}
+	if _, ok := cf["dbNum"]; !ok {
+		cf["dbNum"] = "0"
+	}
+	if _, ok := cf["password"]; !ok {
+		cf["password"] = ""
+	}
+	rc.key = cf["key"]
+	rc.conninfo = cf["conn"]
+	rc.dbNum, _ = strconv.Atoi(cf["dbNum"])
+	rc.password = cf["password"]
+
+	rc.connectInit()
+
+	c := rc.p.Get()
+	defer c.Close()
+
+	return c.Err()
+}
+
+// connect to redis.
+func (rc *Cache) connectInit() {
+	dialFunc := func() (c redis.Conn, err error) {
+		c, err = redis.Dial("tcp", rc.conninfo)
+		if err != nil {
+			return nil, err
+		}
+
+		if rc.password != "" {
+			if _, err := c.Do("AUTH", rc.password); err != nil {
+				c.Close()
+				return nil, err
+			}
+		}
+
+		_, selecterr := c.Do("SELECT", rc.dbNum)
+		if selecterr != nil {
+			c.Close()
+			return nil, selecterr
+		}
+		return
+	}
+	// initialize a new pool
+	rc.p = &redis.Pool{
+		MaxIdle:     3,
+		IdleTimeout: 180 * time.Second,
+		Dial:        dialFunc,
+	}
+}
+
+func init() {
+	cache.Register("redis", NewRedisCache)
+}

+ 106 - 0
vendor/github.com/astaxie/beego/cache/redis/redis_test.go

@@ -0,0 +1,106 @@
+// 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 redis
+
+import (
+	"testing"
+	"time"
+
+	"github.com/astaxie/beego/cache"
+	"github.com/garyburd/redigo/redis"
+)
+
+func TestRedisCache(t *testing.T) {
+	bm, err := cache.NewCache("redis", `{"conn": "127.0.0.1:6379"}`)
+	if err != nil {
+		t.Error("init err")
+	}
+	timeoutDuration := 10 * time.Second
+	if err = bm.Put("astaxie", 1, timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+
+	time.Sleep(11 * time.Second)
+
+	if bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+	if err = bm.Put("astaxie", 1, timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+
+	if v, _ := redis.Int(bm.Get("astaxie"), err); v != 1 {
+		t.Error("get err")
+	}
+
+	if err = bm.Incr("astaxie"); err != nil {
+		t.Error("Incr Error", err)
+	}
+
+	if v, _ := redis.Int(bm.Get("astaxie"), err); v != 2 {
+		t.Error("get err")
+	}
+
+	if err = bm.Decr("astaxie"); err != nil {
+		t.Error("Decr Error", err)
+	}
+
+	if v, _ := redis.Int(bm.Get("astaxie"), err); v != 1 {
+		t.Error("get err")
+	}
+	bm.Delete("astaxie")
+	if bm.IsExist("astaxie") {
+		t.Error("delete err")
+	}
+
+	//test string
+	if err = bm.Put("astaxie", "author", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie") {
+		t.Error("check err")
+	}
+
+	if v, _ := redis.String(bm.Get("astaxie"), err); v != "author" {
+		t.Error("get err")
+	}
+
+	//test GetMulti
+	if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !bm.IsExist("astaxie1") {
+		t.Error("check err")
+	}
+
+	vv := bm.GetMulti([]string{"astaxie", "astaxie1"})
+	if len(vv) != 2 {
+		t.Error("GetMulti ERROR")
+	}
+	if v, _ := redis.String(vv[0], nil); v != "author" {
+		t.Error("GetMulti ERROR")
+	}
+	if v, _ := redis.String(vv[1], nil); v != "author1" {
+		t.Error("GetMulti ERROR")
+	}
+
+	// test clear all
+	if err = bm.ClearAll(); err != nil {
+		t.Error("clear all err")
+	}
+}

+ 231 - 0
vendor/github.com/astaxie/beego/cache/ssdb/ssdb.go

@@ -0,0 +1,231 @@
+package ssdb
+
+import (
+	"encoding/json"
+	"errors"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/ssdb/gossdb/ssdb"
+
+	"github.com/astaxie/beego/cache"
+)
+
+// Cache SSDB adapter
+type Cache struct {
+	conn     *ssdb.Client
+	conninfo []string
+}
+
+//NewSsdbCache create new ssdb adapter.
+func NewSsdbCache() cache.Cache {
+	return &Cache{}
+}
+
+// Get get value from memcache.
+func (rc *Cache) Get(key string) interface{} {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return nil
+		}
+	}
+	value, err := rc.conn.Get(key)
+	if err == nil {
+		return value
+	}
+	return nil
+}
+
+// GetMulti get value from memcache.
+func (rc *Cache) GetMulti(keys []string) []interface{} {
+	size := len(keys)
+	var values []interface{}
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			for i := 0; i < size; i++ {
+				values = append(values, err)
+			}
+			return values
+		}
+	}
+	res, err := rc.conn.Do("multi_get", keys)
+	resSize := len(res)
+	if err == nil {
+		for i := 1; i < resSize; i += 2 {
+			values = append(values, res[i+1])
+		}
+		return values
+	}
+	for i := 0; i < size; i++ {
+		values = append(values, err)
+	}
+	return values
+}
+
+// DelMulti get value from memcache.
+func (rc *Cache) DelMulti(keys []string) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	_, err := rc.conn.Do("multi_del", keys)
+	return err
+}
+
+// Put put value to memcache. only support string.
+func (rc *Cache) Put(key string, value interface{}, timeout time.Duration) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	v, ok := value.(string)
+	if !ok {
+		return errors.New("value must string")
+	}
+	var resp []string
+	var err error
+	ttl := int(timeout / time.Second)
+	if ttl < 0 {
+		resp, err = rc.conn.Do("set", key, v)
+	} else {
+		resp, err = rc.conn.Do("setx", key, v, ttl)
+	}
+	if err != nil {
+		return err
+	}
+	if len(resp) == 2 && resp[0] == "ok" {
+		return nil
+	}
+	return errors.New("bad response")
+}
+
+// Delete delete value in memcache.
+func (rc *Cache) Delete(key string) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	_, err := rc.conn.Del(key)
+	return err
+}
+
+// Incr increase counter.
+func (rc *Cache) Incr(key string) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	_, err := rc.conn.Do("incr", key, 1)
+	return err
+}
+
+// Decr decrease counter.
+func (rc *Cache) Decr(key string) error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	_, err := rc.conn.Do("incr", key, -1)
+	return err
+}
+
+// IsExist check value exists in memcache.
+func (rc *Cache) IsExist(key string) bool {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return false
+		}
+	}
+	resp, err := rc.conn.Do("exists", key)
+	if err != nil {
+		return false
+	}
+	if len(resp) == 2 && resp[1] == "1" {
+		return true
+	}
+	return false
+
+}
+
+// ClearAll clear all cached in memcache.
+func (rc *Cache) ClearAll() error {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	keyStart, keyEnd, limit := "", "", 50
+	resp, err := rc.Scan(keyStart, keyEnd, limit)
+	for err == nil {
+		size := len(resp)
+		if size == 1 {
+			return nil
+		}
+		keys := []string{}
+		for i := 1; i < size; i += 2 {
+			keys = append(keys, resp[i])
+		}
+		_, e := rc.conn.Do("multi_del", keys)
+		if e != nil {
+			return e
+		}
+		keyStart = resp[size-2]
+		resp, err = rc.Scan(keyStart, keyEnd, limit)
+	}
+	return err
+}
+
+// Scan key all cached in ssdb.
+func (rc *Cache) Scan(keyStart string, keyEnd string, limit int) ([]string, error) {
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return nil, err
+		}
+	}
+	resp, err := rc.conn.Do("scan", keyStart, keyEnd, limit)
+	if err != nil {
+		return nil, err
+	}
+	return resp, nil
+}
+
+// StartAndGC start memcache adapter.
+// config string is like {"conn":"connection info"}.
+// if connecting error, return.
+func (rc *Cache) StartAndGC(config string) error {
+	var cf map[string]string
+	json.Unmarshal([]byte(config), &cf)
+	if _, ok := cf["conn"]; !ok {
+		return errors.New("config has no conn key")
+	}
+	rc.conninfo = strings.Split(cf["conn"], ";")
+	if rc.conn == nil {
+		if err := rc.connectInit(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// connect to memcache and keep the connection.
+func (rc *Cache) connectInit() error {
+	conninfoArray := strings.Split(rc.conninfo[0], ":")
+	host := conninfoArray[0]
+	port, e := strconv.Atoi(conninfoArray[1])
+	if e != nil {
+		return e
+	}
+	var err error
+	rc.conn, err = ssdb.Connect(host, port)
+	return err
+}
+
+func init() {
+	cache.Register("ssdb", NewSsdbCache)
+}

+ 104 - 0
vendor/github.com/astaxie/beego/cache/ssdb/ssdb_test.go

@@ -0,0 +1,104 @@
+package ssdb
+
+import (
+	"strconv"
+	"testing"
+	"time"
+
+	"github.com/astaxie/beego/cache"
+)
+
+func TestSsdbcacheCache(t *testing.T) {
+	ssdb, err := cache.NewCache("ssdb", `{"conn": "127.0.0.1:8888"}`)
+	if err != nil {
+		t.Error("init err")
+	}
+
+	// test put and exist
+	if ssdb.IsExist("ssdb") {
+		t.Error("check err")
+	}
+	timeoutDuration := 10 * time.Second
+	//timeoutDuration := -10*time.Second   if timeoutDuration is negtive,it means permanent
+	if err = ssdb.Put("ssdb", "ssdb", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if !ssdb.IsExist("ssdb") {
+		t.Error("check err")
+	}
+
+	// Get test done
+	if err = ssdb.Put("ssdb", "ssdb", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+
+	if v := ssdb.Get("ssdb"); v != "ssdb" {
+		t.Error("get Error")
+	}
+
+	//inc/dec test done
+	if err = ssdb.Put("ssdb", "2", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if err = ssdb.Incr("ssdb"); err != nil {
+		t.Error("incr Error", err)
+	}
+
+	if v, err := strconv.Atoi(ssdb.Get("ssdb").(string)); err != nil || v != 3 {
+		t.Error("get err")
+	}
+
+	if err = ssdb.Decr("ssdb"); err != nil {
+		t.Error("decr error")
+	}
+
+	// test del
+	if err = ssdb.Put("ssdb", "3", timeoutDuration); err != nil {
+		t.Error("set Error", err)
+	}
+	if v, err := strconv.Atoi(ssdb.Get("ssdb").(string)); err != nil || v != 3 {
+		t.Error("get err")
+	}
+	if err := ssdb.Delete("ssdb"); err == nil {
+		if ssdb.IsExist("ssdb") {
+			t.Error("delete err")
+		}
+	}
+
+	//test string
+	if err = ssdb.Put("ssdb", "ssdb", -10*time.Second); err != nil {
+		t.Error("set Error", err)
+	}
+	if !ssdb.IsExist("ssdb") {
+		t.Error("check err")
+	}
+	if v := ssdb.Get("ssdb").(string); v != "ssdb" {
+		t.Error("get err")
+	}
+
+	//test GetMulti done
+	if err = ssdb.Put("ssdb1", "ssdb1", -10*time.Second); err != nil {
+		t.Error("set Error", err)
+	}
+	if !ssdb.IsExist("ssdb1") {
+		t.Error("check err")
+	}
+	vv := ssdb.GetMulti([]string{"ssdb", "ssdb1"})
+	if len(vv) != 2 {
+		t.Error("getmulti error")
+	}
+	if vv[0].(string) != "ssdb" {
+		t.Error("getmulti error")
+	}
+	if vv[1].(string) != "ssdb1" {
+		t.Error("getmulti error")
+	}
+
+	// test clear all done
+	if err = ssdb.ClearAll(); err != nil {
+		t.Error("clear all err")
+	}
+	if ssdb.IsExist("ssdb") || ssdb.IsExist("ssdb1") {
+		t.Error("check err")
+	}
+}

+ 489 - 0
vendor/github.com/astaxie/beego/config.go

@@ -0,0 +1,489 @@
+// 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 beego
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"reflect"
+	"runtime"
+	"strings"
+
+	"github.com/astaxie/beego/config"
+	"github.com/astaxie/beego/context"
+	"github.com/astaxie/beego/logs"
+	"github.com/astaxie/beego/session"
+	"github.com/astaxie/beego/utils"
+)
+
+// Config is the main struct for BConfig
+type Config struct {
+	AppName             string //Application name
+	RunMode             string //Running Mode: dev | prod
+	RouterCaseSensitive bool
+	ServerName          string
+	RecoverPanic        bool
+	RecoverFunc         func(*context.Context)
+	CopyRequestBody     bool
+	EnableGzip          bool
+	MaxMemory           int64
+	EnableErrorsShow    bool
+	EnableErrorsRender  bool
+	Listen              Listen
+	WebConfig           WebConfig
+	Log                 LogConfig
+}
+
+// Listen holds for http and https related config
+type Listen struct {
+	Graceful      bool // Graceful means use graceful module to start the server
+	ServerTimeOut int64
+	ListenTCP4    bool
+	EnableHTTP    bool
+	HTTPAddr      string
+	HTTPPort      int
+	EnableHTTPS   bool
+	HTTPSAddr     string
+	HTTPSPort     int
+	HTTPSCertFile string
+	HTTPSKeyFile  string
+	EnableAdmin   bool
+	AdminAddr     string
+	AdminPort     int
+	EnableFcgi    bool
+	EnableStdIo   bool // EnableStdIo works with EnableFcgi Use FCGI via standard I/O
+}
+
+// WebConfig holds web related config
+type WebConfig struct {
+	AutoRender             bool
+	EnableDocs             bool
+	FlashName              string
+	FlashSeparator         string
+	DirectoryIndex         bool
+	StaticDir              map[string]string
+	StaticExtensionsToGzip []string
+	TemplateLeft           string
+	TemplateRight          string
+	ViewsPath              string
+	EnableXSRF             bool
+	XSRFKey                string
+	XSRFExpire             int
+	Session                SessionConfig
+}
+
+// SessionConfig holds session related config
+type SessionConfig struct {
+	SessionOn                    bool
+	SessionProvider              string
+	SessionName                  string
+	SessionGCMaxLifetime         int64
+	SessionProviderConfig        string
+	SessionCookieLifeTime        int
+	SessionAutoSetCookie         bool
+	SessionDomain                string
+	SessionDisableHTTPOnly       bool // used to allow for cross domain cookies/javascript cookies.
+	SessionEnableSidInHTTPHeader bool //	enable store/get the sessionId into/from http headers
+	SessionNameInHTTPHeader      string
+	SessionEnableSidInURLQuery   bool //	enable get the sessionId from Url Query params
+}
+
+// LogConfig holds Log related config
+type LogConfig struct {
+	AccessLogs  bool
+	FileLineNum bool
+	Outputs     map[string]string // Store Adaptor : config
+}
+
+var (
+	// BConfig is the default config for Application
+	BConfig *Config
+	// AppConfig is the instance of Config, store the config information from file
+	AppConfig *beegoAppConfig
+	// AppPath is the absolute path to the app
+	AppPath string
+	// GlobalSessions is the instance for the session manager
+	GlobalSessions *session.Manager
+
+	// appConfigPath is the path to the config files
+	appConfigPath string
+	// appConfigProvider is the provider for the config, default is ini
+	appConfigProvider = "ini"
+)
+
+func init() {
+	BConfig = newBConfig()
+	var err error
+	if AppPath, err = filepath.Abs(filepath.Dir(os.Args[0])); err != nil {
+		panic(err)
+	}
+	workPath, err := os.Getwd()
+	if err != nil {
+		panic(err)
+	}
+	appConfigPath = filepath.Join(workPath, "conf", "app.conf")
+	if !utils.FileExists(appConfigPath) {
+		appConfigPath = filepath.Join(AppPath, "conf", "app.conf")
+		if !utils.FileExists(appConfigPath) {
+			AppConfig = &beegoAppConfig{innerConfig: config.NewFakeConfig()}
+			return
+		}
+	}
+	if err = parseConfig(appConfigPath); err != nil {
+		panic(err)
+	}
+}
+
+func recoverPanic(ctx *context.Context) {
+	if err := recover(); err != nil {
+		if err == ErrAbort {
+			return
+		}
+		if !BConfig.RecoverPanic {
+			panic(err)
+		}
+		if BConfig.EnableErrorsShow {
+			if _, ok := ErrorMaps[fmt.Sprint(err)]; ok {
+				exception(fmt.Sprint(err), ctx)
+				return
+			}
+		}
+		var stack string
+		logs.Critical("the request url is ", ctx.Input.URL())
+		logs.Critical("Handler crashed with error", err)
+		for i := 1; ; i++ {
+			_, file, line, ok := runtime.Caller(i)
+			if !ok {
+				break
+			}
+			logs.Critical(fmt.Sprintf("%s:%d", file, line))
+			stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line))
+		}
+		if BConfig.RunMode == DEV && BConfig.EnableErrorsRender {
+			showErr(err, ctx, stack)
+		}
+	}
+}
+
+func newBConfig() *Config {
+	return &Config{
+		AppName:             "beego",
+		RunMode:             DEV,
+		RouterCaseSensitive: true,
+		ServerName:          "beegoServer:" + VERSION,
+		RecoverPanic:        true,
+		RecoverFunc:         recoverPanic,
+		CopyRequestBody:     false,
+		EnableGzip:          false,
+		MaxMemory:           1 << 26, //64MB
+		EnableErrorsShow:    true,
+		EnableErrorsRender:  true,
+		Listen: Listen{
+			Graceful:      false,
+			ServerTimeOut: 0,
+			ListenTCP4:    false,
+			EnableHTTP:    true,
+			HTTPAddr:      "",
+			HTTPPort:      8080,
+			EnableHTTPS:   false,
+			HTTPSAddr:     "",
+			HTTPSPort:     10443,
+			HTTPSCertFile: "",
+			HTTPSKeyFile:  "",
+			EnableAdmin:   false,
+			AdminAddr:     "",
+			AdminPort:     8088,
+			EnableFcgi:    false,
+			EnableStdIo:   false,
+		},
+		WebConfig: WebConfig{
+			AutoRender:             true,
+			EnableDocs:             false,
+			FlashName:              "BEEGO_FLASH",
+			FlashSeparator:         "BEEGOFLASH",
+			DirectoryIndex:         false,
+			StaticDir:              map[string]string{"/static": "static"},
+			StaticExtensionsToGzip: []string{".css", ".js"},
+			TemplateLeft:           "{{",
+			TemplateRight:          "}}",
+			ViewsPath:              "views",
+			EnableXSRF:             false,
+			XSRFKey:                "beegoxsrf",
+			XSRFExpire:             0,
+			Session: SessionConfig{
+				SessionOn:                    false,
+				SessionProvider:              "memory",
+				SessionName:                  "beegosessionID",
+				SessionGCMaxLifetime:         3600,
+				SessionProviderConfig:        "",
+				SessionDisableHTTPOnly:       false,
+				SessionCookieLifeTime:        0, //set cookie default is the browser life
+				SessionAutoSetCookie:         true,
+				SessionDomain:                "",
+				SessionEnableSidInHTTPHeader: false, //	enable store/get the sessionId into/from http headers
+				SessionNameInHTTPHeader:      "Beegosessionid",
+				SessionEnableSidInURLQuery:   false, //	enable get the sessionId from Url Query params
+			},
+		},
+		Log: LogConfig{
+			AccessLogs:  false,
+			FileLineNum: true,
+			Outputs:     map[string]string{"console": ""},
+		},
+	}
+}
+
+// now only support ini, next will support json.
+func parseConfig(appConfigPath string) (err error) {
+	AppConfig, err = newAppConfig(appConfigProvider, appConfigPath)
+	if err != nil {
+		return err
+	}
+	return assignConfig(AppConfig)
+}
+
+func assignConfig(ac config.Configer) error {
+	for _, i := range []interface{}{BConfig, &BConfig.Listen, &BConfig.WebConfig, &BConfig.Log, &BConfig.WebConfig.Session} {
+		assignSingleConfig(i, ac)
+	}
+	// set the run mode first
+	if envRunMode := os.Getenv("BEEGO_RUNMODE"); envRunMode != "" {
+		BConfig.RunMode = envRunMode
+	} else if runMode := ac.String("RunMode"); runMode != "" {
+		BConfig.RunMode = runMode
+	}
+
+	if sd := ac.String("StaticDir"); sd != "" {
+		BConfig.WebConfig.StaticDir = map[string]string{}
+		sds := strings.Fields(sd)
+		for _, v := range sds {
+			if url2fsmap := strings.SplitN(v, ":", 2); len(url2fsmap) == 2 {
+				BConfig.WebConfig.StaticDir["/"+strings.Trim(url2fsmap[0], "/")] = url2fsmap[1]
+			} else {
+				BConfig.WebConfig.StaticDir["/"+strings.Trim(url2fsmap[0], "/")] = url2fsmap[0]
+			}
+		}
+	}
+
+	if sgz := ac.String("StaticExtensionsToGzip"); sgz != "" {
+		extensions := strings.Split(sgz, ",")
+		fileExts := []string{}
+		for _, ext := range extensions {
+			ext = strings.TrimSpace(ext)
+			if ext == "" {
+				continue
+			}
+			if !strings.HasPrefix(ext, ".") {
+				ext = "." + ext
+			}
+			fileExts = append(fileExts, ext)
+		}
+		if len(fileExts) > 0 {
+			BConfig.WebConfig.StaticExtensionsToGzip = fileExts
+		}
+	}
+
+	if lo := ac.String("LogOutputs"); lo != "" {
+		// if lo is not nil or empty
+		// means user has set his own LogOutputs
+		// clear the default setting to BConfig.Log.Outputs
+		BConfig.Log.Outputs = make(map[string]string)
+		los := strings.Split(lo, ";")
+		for _, v := range los {
+			if logType2Config := strings.SplitN(v, ",", 2); len(logType2Config) == 2 {
+				BConfig.Log.Outputs[logType2Config[0]] = logType2Config[1]
+			} else {
+				continue
+			}
+		}
+	}
+
+	//init log
+	logs.Reset()
+	for adaptor, config := range BConfig.Log.Outputs {
+		err := logs.SetLogger(adaptor, config)
+		if err != nil {
+			fmt.Fprintln(os.Stderr, fmt.Sprintf("%s with the config %q got err:%s", adaptor, config, err.Error()))
+		}
+	}
+	logs.SetLogFuncCall(BConfig.Log.FileLineNum)
+
+	return nil
+}
+
+func assignSingleConfig(p interface{}, ac config.Configer) {
+	pt := reflect.TypeOf(p)
+	if pt.Kind() != reflect.Ptr {
+		return
+	}
+	pt = pt.Elem()
+	if pt.Kind() != reflect.Struct {
+		return
+	}
+	pv := reflect.ValueOf(p).Elem()
+
+	for i := 0; i < pt.NumField(); i++ {
+		pf := pv.Field(i)
+		if !pf.CanSet() {
+			continue
+		}
+		name := pt.Field(i).Name
+		switch pf.Kind() {
+		case reflect.String:
+			pf.SetString(ac.DefaultString(name, pf.String()))
+		case reflect.Int, reflect.Int64:
+			pf.SetInt(ac.DefaultInt64(name, pf.Int()))
+		case reflect.Bool:
+			pf.SetBool(ac.DefaultBool(name, pf.Bool()))
+		case reflect.Struct:
+		default:
+			//do nothing here
+		}
+	}
+
+}
+
+// LoadAppConfig allow developer to apply a config file
+func LoadAppConfig(adapterName, configPath string) error {
+	absConfigPath, err := filepath.Abs(configPath)
+	if err != nil {
+		return err
+	}
+
+	if !utils.FileExists(absConfigPath) {
+		return fmt.Errorf("the target config file: %s don't exist", configPath)
+	}
+
+	appConfigPath = absConfigPath
+	appConfigProvider = adapterName
+
+	return parseConfig(appConfigPath)
+}
+
+type beegoAppConfig struct {
+	innerConfig config.Configer
+}
+
+func newAppConfig(appConfigProvider, appConfigPath string) (*beegoAppConfig, error) {
+	ac, err := config.NewConfig(appConfigProvider, appConfigPath)
+	if err != nil {
+		return nil, err
+	}
+	return &beegoAppConfig{ac}, nil
+}
+
+func (b *beegoAppConfig) Set(key, val string) error {
+	if err := b.innerConfig.Set(BConfig.RunMode+"::"+key, val); err != nil {
+		return err
+	}
+	return b.innerConfig.Set(key, val)
+}
+
+func (b *beegoAppConfig) String(key string) string {
+	if v := b.innerConfig.String(BConfig.RunMode + "::" + key); v != "" {
+		return v
+	}
+	return b.innerConfig.String(key)
+}
+
+func (b *beegoAppConfig) Strings(key string) []string {
+	if v := b.innerConfig.Strings(BConfig.RunMode + "::" + key); len(v) > 0 {
+		return v
+	}
+	return b.innerConfig.Strings(key)
+}
+
+func (b *beegoAppConfig) Int(key string) (int, error) {
+	if v, err := b.innerConfig.Int(BConfig.RunMode + "::" + key); err == nil {
+		return v, nil
+	}
+	return b.innerConfig.Int(key)
+}
+
+func (b *beegoAppConfig) Int64(key string) (int64, error) {
+	if v, err := b.innerConfig.Int64(BConfig.RunMode + "::" + key); err == nil {
+		return v, nil
+	}
+	return b.innerConfig.Int64(key)
+}
+
+func (b *beegoAppConfig) Bool(key string) (bool, error) {
+	if v, err := b.innerConfig.Bool(BConfig.RunMode + "::" + key); err == nil {
+		return v, nil
+	}
+	return b.innerConfig.Bool(key)
+}
+
+func (b *beegoAppConfig) Float(key string) (float64, error) {
+	if v, err := b.innerConfig.Float(BConfig.RunMode + "::" + key); err == nil {
+		return v, nil
+	}
+	return b.innerConfig.Float(key)
+}
+
+func (b *beegoAppConfig) DefaultString(key string, defaultVal string) string {
+	if v := b.String(key); v != "" {
+		return v
+	}
+	return defaultVal
+}
+
+func (b *beegoAppConfig) DefaultStrings(key string, defaultVal []string) []string {
+	if v := b.Strings(key); len(v) != 0 {
+		return v
+	}
+	return defaultVal
+}
+
+func (b *beegoAppConfig) DefaultInt(key string, defaultVal int) int {
+	if v, err := b.Int(key); err == nil {
+		return v
+	}
+	return defaultVal
+}
+
+func (b *beegoAppConfig) DefaultInt64(key string, defaultVal int64) int64 {
+	if v, err := b.Int64(key); err == nil {
+		return v
+	}
+	return defaultVal
+}
+
+func (b *beegoAppConfig) DefaultBool(key string, defaultVal bool) bool {
+	if v, err := b.Bool(key); err == nil {
+		return v
+	}
+	return defaultVal
+}
+
+func (b *beegoAppConfig) DefaultFloat(key string, defaultVal float64) float64 {
+	if v, err := b.Float(key); err == nil {
+		return v
+	}
+	return defaultVal
+}
+
+func (b *beegoAppConfig) DIY(key string) (interface{}, error) {
+	return b.innerConfig.DIY(key)
+}
+
+func (b *beegoAppConfig) GetSection(section string) (map[string]string, error) {
+	return b.innerConfig.GetSection(section)
+}
+
+func (b *beegoAppConfig) SaveConfigFile(filename string) error {
+	return b.innerConfig.SaveConfigFile(filename)
+}

+ 242 - 0
vendor/github.com/astaxie/beego/config/config.go

@@ -0,0 +1,242 @@
+// 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 config is used to parse config.
+// Usage:
+//  import "github.com/astaxie/beego/config"
+//Examples.
+//
+//  cnf, err := config.NewConfig("ini", "config.conf")
+//
+//  cnf APIS:
+//
+//  cnf.Set(key, val string) error
+//  cnf.String(key string) string
+//  cnf.Strings(key string) []string
+//  cnf.Int(key string) (int, error)
+//  cnf.Int64(key string) (int64, error)
+//  cnf.Bool(key string) (bool, error)
+//  cnf.Float(key string) (float64, error)
+//  cnf.DefaultString(key string, defaultVal string) string
+//  cnf.DefaultStrings(key string, defaultVal []string) []string
+//  cnf.DefaultInt(key string, defaultVal int) int
+//  cnf.DefaultInt64(key string, defaultVal int64) int64
+//  cnf.DefaultBool(key string, defaultVal bool) bool
+//  cnf.DefaultFloat(key string, defaultVal float64) float64
+//  cnf.DIY(key string) (interface{}, error)
+//  cnf.GetSection(section string) (map[string]string, error)
+//  cnf.SaveConfigFile(filename string) error
+//More docs http://beego.me/docs/module/config.md
+package config
+
+import (
+	"fmt"
+	"os"
+	"reflect"
+	"time"
+)
+
+// Configer defines how to get and set value from configuration raw data.
+type Configer interface {
+	Set(key, val string) error   //support section::key type in given key when using ini type.
+	String(key string) string    //support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same.
+	Strings(key string) []string //get string slice
+	Int(key string) (int, error)
+	Int64(key string) (int64, error)
+	Bool(key string) (bool, error)
+	Float(key string) (float64, error)
+	DefaultString(key string, defaultVal string) string      // support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same.
+	DefaultStrings(key string, defaultVal []string) []string //get string slice
+	DefaultInt(key string, defaultVal int) int
+	DefaultInt64(key string, defaultVal int64) int64
+	DefaultBool(key string, defaultVal bool) bool
+	DefaultFloat(key string, defaultVal float64) float64
+	DIY(key string) (interface{}, error)
+	GetSection(section string) (map[string]string, error)
+	SaveConfigFile(filename string) error
+}
+
+// Config is the adapter interface for parsing config file to get raw data to Configer.
+type Config interface {
+	Parse(key string) (Configer, error)
+	ParseData(data []byte) (Configer, error)
+}
+
+var adapters = make(map[string]Config)
+
+// Register makes a config adapter available by the adapter name.
+// If Register is called twice with the same name or if driver is nil,
+// it panics.
+func Register(name string, adapter Config) {
+	if adapter == nil {
+		panic("config: Register adapter is nil")
+	}
+	if _, ok := adapters[name]; ok {
+		panic("config: Register called twice for adapter " + name)
+	}
+	adapters[name] = adapter
+}
+
+// NewConfig adapterName is ini/json/xml/yaml.
+// filename is the config file path.
+func NewConfig(adapterName, filename string) (Configer, error) {
+	adapter, ok := adapters[adapterName]
+	if !ok {
+		return nil, fmt.Errorf("config: unknown adaptername %q (forgotten import?)", adapterName)
+	}
+	return adapter.Parse(filename)
+}
+
+// NewConfigData adapterName is ini/json/xml/yaml.
+// data is the config data.
+func NewConfigData(adapterName string, data []byte) (Configer, error) {
+	adapter, ok := adapters[adapterName]
+	if !ok {
+		return nil, fmt.Errorf("config: unknown adaptername %q (forgotten import?)", adapterName)
+	}
+	return adapter.ParseData(data)
+}
+
+// ExpandValueEnvForMap convert all string value with environment variable.
+func ExpandValueEnvForMap(m map[string]interface{}) map[string]interface{} {
+	for k, v := range m {
+		switch value := v.(type) {
+		case string:
+			m[k] = ExpandValueEnv(value)
+		case map[string]interface{}:
+			m[k] = ExpandValueEnvForMap(value)
+		case map[string]string:
+			for k2, v2 := range value {
+				value[k2] = ExpandValueEnv(v2)
+			}
+			m[k] = value
+		}
+	}
+	return m
+}
+
+// ExpandValueEnv returns value of convert with environment variable.
+//
+// Return environment variable if value start with "${" and end with "}".
+// Return default value if environment variable is empty or not exist.
+//
+// It accept value formats "${env}" , "${env||}}" , "${env||defaultValue}" , "defaultvalue".
+// Examples:
+//	v1 := config.ExpandValueEnv("${GOPATH}")			// return the GOPATH environment variable.
+//	v2 := config.ExpandValueEnv("${GOAsta||/usr/local/go}")	// return the default value "/usr/local/go/".
+//	v3 := config.ExpandValueEnv("Astaxie")				// return the value "Astaxie".
+func ExpandValueEnv(value string) (realValue string) {
+	realValue = value
+
+	vLen := len(value)
+	// 3 = ${}
+	if vLen < 3 {
+		return
+	}
+	// Need start with "${" and end with "}", then return.
+	if value[0] != '$' || value[1] != '{' || value[vLen-1] != '}' {
+		return
+	}
+
+	key := ""
+	defalutV := ""
+	// value start with "${"
+	for i := 2; i < vLen; i++ {
+		if value[i] == '|' && (i+1 < vLen && value[i+1] == '|') {
+			key = value[2:i]
+			defalutV = value[i+2 : vLen-1] // other string is default value.
+			break
+		} else if value[i] == '}' {
+			key = value[2:i]
+			break
+		}
+	}
+
+	realValue = os.Getenv(key)
+	if realValue == "" {
+		realValue = defalutV
+	}
+
+	return
+}
+
+// ParseBool returns the boolean value represented by the string.
+//
+// It accepts 1, 1.0, t, T, TRUE, true, True, YES, yes, Yes,Y, y, ON, on, On,
+// 0, 0.0, f, F, FALSE, false, False, NO, no, No, N,n, OFF, off, Off.
+// Any other value returns an error.
+func ParseBool(val interface{}) (value bool, err error) {
+	if val != nil {
+		switch v := val.(type) {
+		case bool:
+			return v, nil
+		case string:
+			switch v {
+			case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "Y", "y", "ON", "on", "On":
+				return true, nil
+			case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "N", "n", "OFF", "off", "Off":
+				return false, nil
+			}
+		case int8, int32, int64:
+			strV := fmt.Sprintf("%s", v)
+			if strV == "1" {
+				return true, nil
+			} else if strV == "0" {
+				return false, nil
+			}
+		case float64:
+			if v == 1 {
+				return true, nil
+			} else if v == 0 {
+				return false, nil
+			}
+		}
+		return false, fmt.Errorf("parsing %q: invalid syntax", val)
+	}
+	return false, fmt.Errorf("parsing <nil>: invalid syntax")
+}
+
+// ToString converts values of any type to string.
+func ToString(x interface{}) string {
+	switch y := x.(type) {
+
+	// Handle dates with special logic
+	// This needs to come above the fmt.Stringer
+	// test since time.Time's have a .String()
+	// method
+	case time.Time:
+		return y.Format("A Monday")
+
+	// Handle type string
+	case string:
+		return y
+
+	// Handle type with .String() method
+	case fmt.Stringer:
+		return y.String()
+
+	// Handle type with .Error() method
+	case error:
+		return y.Error()
+
+	}
+
+	// Handle named string type
+	if v := reflect.ValueOf(x); v.Kind() == reflect.String {
+		return v.String()
+	}
+
+	// Fallback to fmt package for anything else like numeric types
+	return fmt.Sprint(x)
+}

+ 55 - 0
vendor/github.com/astaxie/beego/config/config_test.go

@@ -0,0 +1,55 @@
+// Copyright 2016 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 config
+
+import (
+	"os"
+	"testing"
+)
+
+func TestExpandValueEnv(t *testing.T) {
+
+	testCases := []struct {
+		item string
+		want string
+	}{
+		{"", ""},
+		{"$", "$"},
+		{"{", "{"},
+		{"{}", "{}"},
+		{"${}", ""},
+		{"${|}", ""},
+		{"${}", ""},
+		{"${{}}", ""},
+		{"${{||}}", "}"},
+		{"${pwd||}", ""},
+		{"${pwd||}", ""},
+		{"${pwd||}", ""},
+		{"${pwd||}}", "}"},
+		{"${pwd||{{||}}}", "{{||}}"},
+		{"${GOPATH}", os.Getenv("GOPATH")},
+		{"${GOPATH||}", os.Getenv("GOPATH")},
+		{"${GOPATH||root}", os.Getenv("GOPATH")},
+		{"${GOPATH_NOT||root}", "root"},
+		{"${GOPATH_NOT||||root}", "||root"},
+	}
+
+	for _, c := range testCases {
+		if got := ExpandValueEnv(c.item); got != c.want {
+			t.Errorf("expand value error, item %q want %q, got %q", c.item, c.want, got)
+		}
+	}
+
+}

+ 87 - 0
vendor/github.com/astaxie/beego/config/env/env.go

@@ -0,0 +1,87 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+// Copyright 2017 Faissal Elamraoui. 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 env is used to parse environment.
+package env
+
+import (
+	"fmt"
+	"os"
+	"strings"
+
+	"github.com/astaxie/beego/utils"
+)
+
+var env *utils.BeeMap
+
+func init() {
+	env = utils.NewBeeMap()
+	for _, e := range os.Environ() {
+		splits := strings.Split(e, "=")
+		env.Set(splits[0], os.Getenv(splits[0]))
+	}
+}
+
+// Get returns a value by key.
+// If the key does not exist, the default value will be returned.
+func Get(key string, defVal string) string {
+	if val := env.Get(key); val != nil {
+		return val.(string)
+	}
+	return defVal
+}
+
+// MustGet returns a value by key.
+// If the key does not exist, it will return an error.
+func MustGet(key string) (string, error) {
+	if val := env.Get(key); val != nil {
+		return val.(string), nil
+	}
+	return "", fmt.Errorf("no env variable with %s", key)
+}
+
+// Set sets a value in the ENV copy.
+// This does not affect the child process environment.
+func Set(key string, value string) {
+	env.Set(key, value)
+}
+
+// MustSet sets a value in the ENV copy and the child process environment.
+// It returns an error in case the set operation failed.
+func MustSet(key string, value string) error {
+	err := os.Setenv(key, value)
+	if err != nil {
+		return err
+	}
+	env.Set(key, value)
+	return nil
+}
+
+// GetAll returns all keys/values in the current child process environment.
+func GetAll() map[string]string {
+	items := env.Items()
+	envs := make(map[string]string, env.Count())
+
+	for key, val := range items {
+		switch key := key.(type) {
+		case string:
+			switch val := val.(type) {
+			case string:
+				envs[key] = val
+			}
+		}
+	}
+	return envs
+}

+ 75 - 0
vendor/github.com/astaxie/beego/config/env/env_test.go

@@ -0,0 +1,75 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+// Copyright 2017 Faissal Elamraoui. 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 env
+
+import (
+	"os"
+	"testing"
+)
+
+func TestEnvGet(t *testing.T) {
+	gopath := Get("GOPATH", "")
+	if gopath != os.Getenv("GOPATH") {
+		t.Error("expected GOPATH not empty.")
+	}
+
+	noExistVar := Get("NOEXISTVAR", "foo")
+	if noExistVar != "foo" {
+		t.Errorf("expected NOEXISTVAR to equal foo, got %s.", noExistVar)
+	}
+}
+
+func TestEnvMustGet(t *testing.T) {
+	gopath, err := MustGet("GOPATH")
+	if err != nil {
+		t.Error(err)
+	}
+
+	if gopath != os.Getenv("GOPATH") {
+		t.Errorf("expected GOPATH to be the same, got %s.", gopath)
+	}
+
+	_, err = MustGet("NOEXISTVAR")
+	if err == nil {
+		t.Error("expected error to be non-nil")
+	}
+}
+
+func TestEnvSet(t *testing.T) {
+	Set("MYVAR", "foo")
+	myVar := Get("MYVAR", "bar")
+	if myVar != "foo" {
+		t.Errorf("expected MYVAR to equal foo, got %s.", myVar)
+	}
+}
+
+func TestEnvMustSet(t *testing.T) {
+	err := MustSet("FOO", "bar")
+	if err != nil {
+		t.Error(err)
+	}
+
+	fooVar := os.Getenv("FOO")
+	if fooVar != "bar" {
+		t.Errorf("expected FOO variable to equal bar, got %s.", fooVar)
+	}
+}
+
+func TestEnvGetAll(t *testing.T) {
+	envMap := GetAll()
+	if len(envMap) == 0 {
+		t.Error("expected environment not empty.")
+	}
+}

+ 134 - 0
vendor/github.com/astaxie/beego/config/fake.go

@@ -0,0 +1,134 @@
+// 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 config
+
+import (
+	"errors"
+	"strconv"
+	"strings"
+)
+
+type fakeConfigContainer struct {
+	data map[string]string
+}
+
+func (c *fakeConfigContainer) getData(key string) string {
+	return c.data[strings.ToLower(key)]
+}
+
+func (c *fakeConfigContainer) Set(key, val string) error {
+	c.data[strings.ToLower(key)] = val
+	return nil
+}
+
+func (c *fakeConfigContainer) String(key string) string {
+	return c.getData(key)
+}
+
+func (c *fakeConfigContainer) DefaultString(key string, defaultval string) string {
+	v := c.String(key)
+	if v == "" {
+		return defaultval
+	}
+	return v
+}
+
+func (c *fakeConfigContainer) Strings(key string) []string {
+	v := c.String(key)
+	if v == "" {
+		return nil
+	}
+	return strings.Split(v, ";")
+}
+
+func (c *fakeConfigContainer) DefaultStrings(key string, defaultval []string) []string {
+	v := c.Strings(key)
+	if v == nil {
+		return defaultval
+	}
+	return v
+}
+
+func (c *fakeConfigContainer) Int(key string) (int, error) {
+	return strconv.Atoi(c.getData(key))
+}
+
+func (c *fakeConfigContainer) DefaultInt(key string, defaultval int) int {
+	v, err := c.Int(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+func (c *fakeConfigContainer) Int64(key string) (int64, error) {
+	return strconv.ParseInt(c.getData(key), 10, 64)
+}
+
+func (c *fakeConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
+	v, err := c.Int64(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+func (c *fakeConfigContainer) Bool(key string) (bool, error) {
+	return ParseBool(c.getData(key))
+}
+
+func (c *fakeConfigContainer) DefaultBool(key string, defaultval bool) bool {
+	v, err := c.Bool(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+func (c *fakeConfigContainer) Float(key string) (float64, error) {
+	return strconv.ParseFloat(c.getData(key), 64)
+}
+
+func (c *fakeConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
+	v, err := c.Float(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+func (c *fakeConfigContainer) DIY(key string) (interface{}, error) {
+	if v, ok := c.data[strings.ToLower(key)]; ok {
+		return v, nil
+	}
+	return nil, errors.New("key not find")
+}
+
+func (c *fakeConfigContainer) GetSection(section string) (map[string]string, error) {
+	return nil, errors.New("not implement in the fakeConfigContainer")
+}
+
+func (c *fakeConfigContainer) SaveConfigFile(filename string) error {
+	return errors.New("not implement in the fakeConfigContainer")
+}
+
+var _ Configer = new(fakeConfigContainer)
+
+// NewFakeConfig return a fake Congiger
+func NewFakeConfig() Configer {
+	return &fakeConfigContainer{
+		data: make(map[string]string),
+	}
+}

+ 482 - 0
vendor/github.com/astaxie/beego/config/ini.go

@@ -0,0 +1,482 @@
+// 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 config
+
+import (
+	"bufio"
+	"bytes"
+	"errors"
+	"io"
+	"io/ioutil"
+	"os"
+	"os/user"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"sync"
+)
+
+var (
+	defaultSection = "default"   // default section means if some ini items not in a section, make them in default section,
+	bNumComment    = []byte{'#'} // number signal
+	bSemComment    = []byte{';'} // semicolon signal
+	bEmpty         = []byte{}
+	bEqual         = []byte{'='} // equal signal
+	bDQuote        = []byte{'"'} // quote signal
+	sectionStart   = []byte{'['} // section start signal
+	sectionEnd     = []byte{']'} // section end signal
+	lineBreak      = "\n"
+)
+
+// IniConfig implements Config to parse ini file.
+type IniConfig struct {
+}
+
+// Parse creates a new Config and parses the file configuration from the named file.
+func (ini *IniConfig) Parse(name string) (Configer, error) {
+	return ini.parseFile(name)
+}
+
+func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) {
+	data, err := ioutil.ReadFile(name)
+	if err != nil {
+		return nil, err
+	}
+
+	return ini.parseData(filepath.Dir(name), data)
+}
+
+func (ini *IniConfig) parseData(dir string, data []byte) (*IniConfigContainer, error) {
+	cfg := &IniConfigContainer{
+		data:           make(map[string]map[string]string),
+		sectionComment: make(map[string]string),
+		keyComment:     make(map[string]string),
+		RWMutex:        sync.RWMutex{},
+	}
+	cfg.Lock()
+	defer cfg.Unlock()
+
+	var comment bytes.Buffer
+	buf := bufio.NewReader(bytes.NewBuffer(data))
+	// check the BOM
+	head, err := buf.Peek(3)
+	if err == nil && head[0] == 239 && head[1] == 187 && head[2] == 191 {
+		for i := 1; i <= 3; i++ {
+			buf.ReadByte()
+		}
+	}
+	section := defaultSection
+	for {
+		line, _, err := buf.ReadLine()
+		if err == io.EOF {
+			break
+		}
+		//It might be a good idea to throw a error on all unknonw errors?
+		if _, ok := err.(*os.PathError); ok {
+			return nil, err
+		}
+		line = bytes.TrimSpace(line)
+		if bytes.Equal(line, bEmpty) {
+			continue
+		}
+		var bComment []byte
+		switch {
+		case bytes.HasPrefix(line, bNumComment):
+			bComment = bNumComment
+		case bytes.HasPrefix(line, bSemComment):
+			bComment = bSemComment
+		}
+		if bComment != nil {
+			line = bytes.TrimLeft(line, string(bComment))
+			// Need append to a new line if multi-line comments.
+			if comment.Len() > 0 {
+				comment.WriteByte('\n')
+			}
+			comment.Write(line)
+			continue
+		}
+
+		if bytes.HasPrefix(line, sectionStart) && bytes.HasSuffix(line, sectionEnd) {
+			section = strings.ToLower(string(line[1 : len(line)-1])) // section name case insensitive
+			if comment.Len() > 0 {
+				cfg.sectionComment[section] = comment.String()
+				comment.Reset()
+			}
+			if _, ok := cfg.data[section]; !ok {
+				cfg.data[section] = make(map[string]string)
+			}
+			continue
+		}
+
+		if _, ok := cfg.data[section]; !ok {
+			cfg.data[section] = make(map[string]string)
+		}
+		keyValue := bytes.SplitN(line, bEqual, 2)
+
+		key := string(bytes.TrimSpace(keyValue[0])) // key name case insensitive
+		key = strings.ToLower(key)
+
+		// handle include "other.conf"
+		if len(keyValue) == 1 && strings.HasPrefix(key, "include") {
+
+			includefiles := strings.Fields(key)
+			if includefiles[0] == "include" && len(includefiles) == 2 {
+
+				otherfile := strings.Trim(includefiles[1], "\"")
+				if !filepath.IsAbs(otherfile) {
+					otherfile = filepath.Join(dir, otherfile)
+				}
+
+				i, err := ini.parseFile(otherfile)
+				if err != nil {
+					return nil, err
+				}
+
+				for sec, dt := range i.data {
+					if _, ok := cfg.data[sec]; !ok {
+						cfg.data[sec] = make(map[string]string)
+					}
+					for k, v := range dt {
+						cfg.data[sec][k] = v
+					}
+				}
+
+				for sec, comm := range i.sectionComment {
+					cfg.sectionComment[sec] = comm
+				}
+
+				for k, comm := range i.keyComment {
+					cfg.keyComment[k] = comm
+				}
+
+				continue
+			}
+		}
+
+		if len(keyValue) != 2 {
+			return nil, errors.New("read the content error: \"" + string(line) + "\", should key = val")
+		}
+		val := bytes.TrimSpace(keyValue[1])
+		if bytes.HasPrefix(val, bDQuote) {
+			val = bytes.Trim(val, `"`)
+		}
+
+		cfg.data[section][key] = ExpandValueEnv(string(val))
+		if comment.Len() > 0 {
+			cfg.keyComment[section+"."+key] = comment.String()
+			comment.Reset()
+		}
+
+	}
+	return cfg, nil
+}
+
+// ParseData parse ini the data
+// When include other.conf,other.conf is either absolute directory
+// or under beego in default temporary directory(/tmp/beego[-username]).
+func (ini *IniConfig) ParseData(data []byte) (Configer, error) {
+	dir := "beego"
+	currentUser, err := user.Current()
+	if err == nil {
+		dir = "beego-" + currentUser.Username
+	}
+	dir = filepath.Join(os.TempDir(), dir)
+	if err = os.MkdirAll(dir, os.ModePerm); err != nil {
+		return nil, err
+	}
+
+	return ini.parseData(dir, data)
+}
+
+// IniConfigContainer A Config represents the ini configuration.
+// When set and get value, support key as section:name type.
+type IniConfigContainer struct {
+	data           map[string]map[string]string // section=> key:val
+	sectionComment map[string]string            // section : comment
+	keyComment     map[string]string            // id: []{comment, key...}; id 1 is for main comment.
+	sync.RWMutex
+}
+
+// Bool returns the boolean value for a given key.
+func (c *IniConfigContainer) Bool(key string) (bool, error) {
+	return ParseBool(c.getdata(key))
+}
+
+// DefaultBool returns the boolean value for a given key.
+// if err != nil return defaltval
+func (c *IniConfigContainer) DefaultBool(key string, defaultval bool) bool {
+	v, err := c.Bool(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// Int returns the integer value for a given key.
+func (c *IniConfigContainer) Int(key string) (int, error) {
+	return strconv.Atoi(c.getdata(key))
+}
+
+// DefaultInt returns the integer value for a given key.
+// if err != nil return defaltval
+func (c *IniConfigContainer) DefaultInt(key string, defaultval int) int {
+	v, err := c.Int(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// Int64 returns the int64 value for a given key.
+func (c *IniConfigContainer) Int64(key string) (int64, error) {
+	return strconv.ParseInt(c.getdata(key), 10, 64)
+}
+
+// DefaultInt64 returns the int64 value for a given key.
+// if err != nil return defaltval
+func (c *IniConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
+	v, err := c.Int64(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// Float returns the float value for a given key.
+func (c *IniConfigContainer) Float(key string) (float64, error) {
+	return strconv.ParseFloat(c.getdata(key), 64)
+}
+
+// DefaultFloat returns the float64 value for a given key.
+// if err != nil return defaltval
+func (c *IniConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
+	v, err := c.Float(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// String returns the string value for a given key.
+func (c *IniConfigContainer) String(key string) string {
+	return c.getdata(key)
+}
+
+// DefaultString returns the string value for a given key.
+// if err != nil return defaltval
+func (c *IniConfigContainer) DefaultString(key string, defaultval string) string {
+	v := c.String(key)
+	if v == "" {
+		return defaultval
+	}
+	return v
+}
+
+// Strings returns the []string value for a given key.
+// Return nil if config value does not exist or is empty.
+func (c *IniConfigContainer) Strings(key string) []string {
+	v := c.String(key)
+	if v == "" {
+		return nil
+	}
+	return strings.Split(v, ";")
+}
+
+// DefaultStrings returns the []string value for a given key.
+// if err != nil return defaltval
+func (c *IniConfigContainer) DefaultStrings(key string, defaultval []string) []string {
+	v := c.Strings(key)
+	if v == nil {
+		return defaultval
+	}
+	return v
+}
+
+// GetSection returns map for the given section
+func (c *IniConfigContainer) GetSection(section string) (map[string]string, error) {
+	if v, ok := c.data[section]; ok {
+		return v, nil
+	}
+	return nil, errors.New("not exist section")
+}
+
+// SaveConfigFile save the config into file.
+//
+// BUG(env): The environment variable config item will be saved with real value in SaveConfigFile Funcation.
+func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) {
+	// Write configuration file by filename.
+	f, err := os.Create(filename)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	// Get section or key comments. Fixed #1607
+	getCommentStr := func(section, key string) string {
+		var (
+			comment string
+			ok      bool
+		)
+		if len(key) == 0 {
+			comment, ok = c.sectionComment[section]
+		} else {
+			comment, ok = c.keyComment[section+"."+key]
+		}
+
+		if ok {
+			// Empty comment
+			if len(comment) == 0 || len(strings.TrimSpace(comment)) == 0 {
+				return string(bNumComment)
+			}
+			prefix := string(bNumComment)
+			// Add the line head character "#"
+			return prefix + strings.Replace(comment, lineBreak, lineBreak+prefix, -1)
+		}
+		return ""
+	}
+
+	buf := bytes.NewBuffer(nil)
+	// Save default section at first place
+	if dt, ok := c.data[defaultSection]; ok {
+		for key, val := range dt {
+			if key != " " {
+				// Write key comments.
+				if v := getCommentStr(defaultSection, key); len(v) > 0 {
+					if _, err = buf.WriteString(v + lineBreak); err != nil {
+						return err
+					}
+				}
+
+				// Write key and value.
+				if _, err = buf.WriteString(key + string(bEqual) + val + lineBreak); err != nil {
+					return err
+				}
+			}
+		}
+
+		// Put a line between sections.
+		if _, err = buf.WriteString(lineBreak); err != nil {
+			return err
+		}
+	}
+	// Save named sections
+	for section, dt := range c.data {
+		if section != defaultSection {
+			// Write section comments.
+			if v := getCommentStr(section, ""); len(v) > 0 {
+				if _, err = buf.WriteString(v + lineBreak); err != nil {
+					return err
+				}
+			}
+
+			// Write section name.
+			if _, err = buf.WriteString(string(sectionStart) + section + string(sectionEnd) + lineBreak); err != nil {
+				return err
+			}
+
+			for key, val := range dt {
+				if key != " " {
+					// Write key comments.
+					if v := getCommentStr(section, key); len(v) > 0 {
+						if _, err = buf.WriteString(v + lineBreak); err != nil {
+							return err
+						}
+					}
+
+					// Write key and value.
+					if _, err = buf.WriteString(key + string(bEqual) + val + lineBreak); err != nil {
+						return err
+					}
+				}
+			}
+
+			// Put a line between sections.
+			if _, err = buf.WriteString(lineBreak); err != nil {
+				return err
+			}
+		}
+	}
+	_, err = buf.WriteTo(f)
+	return err
+}
+
+// Set writes a new value for key.
+// if write to one section, the key need be "section::key".
+// if the section is not existed, it panics.
+func (c *IniConfigContainer) Set(key, value string) error {
+	c.Lock()
+	defer c.Unlock()
+	if len(key) == 0 {
+		return errors.New("key is empty")
+	}
+
+	var (
+		section, k string
+		sectionKey = strings.Split(strings.ToLower(key), "::")
+	)
+
+	if len(sectionKey) >= 2 {
+		section = sectionKey[0]
+		k = sectionKey[1]
+	} else {
+		section = defaultSection
+		k = sectionKey[0]
+	}
+
+	if _, ok := c.data[section]; !ok {
+		c.data[section] = make(map[string]string)
+	}
+	c.data[section][k] = value
+	return nil
+}
+
+// DIY returns the raw value by a given key.
+func (c *IniConfigContainer) DIY(key string) (v interface{}, err error) {
+	if v, ok := c.data[strings.ToLower(key)]; ok {
+		return v, nil
+	}
+	return v, errors.New("key not find")
+}
+
+// section.key or key
+func (c *IniConfigContainer) getdata(key string) string {
+	if len(key) == 0 {
+		return ""
+	}
+	c.RLock()
+	defer c.RUnlock()
+
+	var (
+		section, k string
+		sectionKey = strings.Split(strings.ToLower(key), "::")
+	)
+	if len(sectionKey) >= 2 {
+		section = sectionKey[0]
+		k = sectionKey[1]
+	} else {
+		section = defaultSection
+		k = sectionKey[0]
+	}
+	if v, ok := c.data[section]; ok {
+		if vv, ok := v[k]; ok {
+			return vv
+		}
+	}
+	return ""
+}
+
+func init() {
+	Register("ini", &IniConfig{})
+}

+ 190 - 0
vendor/github.com/astaxie/beego/config/ini_test.go

@@ -0,0 +1,190 @@
+// 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 config
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"strings"
+	"testing"
+)
+
+func TestIni(t *testing.T) {
+
+	var (
+		inicontext = `
+;comment one
+#comment two
+appname = beeapi
+httpport = 8080
+mysqlport = 3600
+PI = 3.1415976
+runmode = "dev"
+autorender = false
+copyrequestbody = true
+session= on
+cookieon= off
+newreg = OFF
+needlogin = ON
+enableSession = Y
+enableCookie = N
+flag = 1
+path1 = ${GOPATH}
+path2 = ${GOPATH||/home/go}
+[demo]
+key1="asta"
+key2 = "xie"
+CaseInsensitive = true
+peers = one;two;three
+password = ${GOPATH}
+`
+
+		keyValue = map[string]interface{}{
+			"appname":               "beeapi",
+			"httpport":              8080,
+			"mysqlport":             int64(3600),
+			"pi":                    3.1415976,
+			"runmode":               "dev",
+			"autorender":            false,
+			"copyrequestbody":       true,
+			"session":               true,
+			"cookieon":              false,
+			"newreg":                false,
+			"needlogin":             true,
+			"enableSession":         true,
+			"enableCookie":          false,
+			"flag":                  true,
+			"path1":                 os.Getenv("GOPATH"),
+			"path2":                 os.Getenv("GOPATH"),
+			"demo::key1":            "asta",
+			"demo::key2":            "xie",
+			"demo::CaseInsensitive": true,
+			"demo::peers":           []string{"one", "two", "three"},
+			"demo::password":        os.Getenv("GOPATH"),
+			"null":                  "",
+			"demo2::key1":           "",
+			"error":                 "",
+			"emptystrings":          []string{},
+		}
+	)
+
+	f, err := os.Create("testini.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = f.WriteString(inicontext)
+	if err != nil {
+		f.Close()
+		t.Fatal(err)
+	}
+	f.Close()
+	defer os.Remove("testini.conf")
+	iniconf, err := NewConfig("ini", "testini.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+	for k, v := range keyValue {
+		var err error
+		var value interface{}
+		switch v.(type) {
+		case int:
+			value, err = iniconf.Int(k)
+		case int64:
+			value, err = iniconf.Int64(k)
+		case float64:
+			value, err = iniconf.Float(k)
+		case bool:
+			value, err = iniconf.Bool(k)
+		case []string:
+			value = iniconf.Strings(k)
+		case string:
+			value = iniconf.String(k)
+		default:
+			value, err = iniconf.DIY(k)
+		}
+		if err != nil {
+			t.Fatalf("get key %q value fail,err %s", k, err)
+		} else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) {
+			t.Fatalf("get key %q value, want %v got %v .", k, v, value)
+		}
+
+	}
+	if err = iniconf.Set("name", "astaxie"); err != nil {
+		t.Fatal(err)
+	}
+	if iniconf.String("name") != "astaxie" {
+		t.Fatal("get name error")
+	}
+
+}
+
+func TestIniSave(t *testing.T) {
+
+	const (
+		inicontext = `
+app = app
+;comment one
+#comment two
+# comment three
+appname = beeapi
+httpport = 8080
+# DB Info
+# enable db
+[dbinfo]
+# db type name
+# suport mysql,sqlserver
+name = mysql
+`
+
+		saveResult = `
+app=app
+#comment one
+#comment two
+# comment three
+appname=beeapi
+httpport=8080
+
+# DB Info
+# enable db
+[dbinfo]
+# db type name
+# suport mysql,sqlserver
+name=mysql
+`
+	)
+	cfg, err := NewConfigData("ini", []byte(inicontext))
+	if err != nil {
+		t.Fatal(err)
+	}
+	name := "newIniConfig.ini"
+	if err := cfg.SaveConfigFile(name); err != nil {
+		t.Fatal(err)
+	}
+	defer os.Remove(name)
+
+	if data, err := ioutil.ReadFile(name); err != nil {
+		t.Fatal(err)
+	} else {
+		cfgData := string(data)
+		datas := strings.Split(saveResult, "\n")
+		for _, line := range datas {
+			if !strings.Contains(cfgData, line+"\n") {
+				t.Fatalf("different after save ini config file. need contains %q", line)
+			}
+		}
+
+	}
+}

+ 266 - 0
vendor/github.com/astaxie/beego/config/json.go

@@ -0,0 +1,266 @@
+// 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 config
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"strings"
+	"sync"
+)
+
+// JSONConfig is a json config parser and implements Config interface.
+type JSONConfig struct {
+}
+
+// Parse returns a ConfigContainer with parsed json config map.
+func (js *JSONConfig) Parse(filename string) (Configer, error) {
+	file, err := os.Open(filename)
+	if err != nil {
+		return nil, err
+	}
+	defer file.Close()
+	content, err := ioutil.ReadAll(file)
+	if err != nil {
+		return nil, err
+	}
+
+	return js.ParseData(content)
+}
+
+// ParseData returns a ConfigContainer with json string
+func (js *JSONConfig) ParseData(data []byte) (Configer, error) {
+	x := &JSONConfigContainer{
+		data: make(map[string]interface{}),
+	}
+	err := json.Unmarshal(data, &x.data)
+	if err != nil {
+		var wrappingArray []interface{}
+		err2 := json.Unmarshal(data, &wrappingArray)
+		if err2 != nil {
+			return nil, err
+		}
+		x.data["rootArray"] = wrappingArray
+	}
+
+	x.data = ExpandValueEnvForMap(x.data)
+
+	return x, nil
+}
+
+// JSONConfigContainer A Config represents the json configuration.
+// Only when get value, support key as section:name type.
+type JSONConfigContainer struct {
+	data map[string]interface{}
+	sync.RWMutex
+}
+
+// Bool returns the boolean value for a given key.
+func (c *JSONConfigContainer) Bool(key string) (bool, error) {
+	val := c.getData(key)
+	if val != nil {
+		return ParseBool(val)
+	}
+	return false, fmt.Errorf("not exist key: %q", key)
+}
+
+// DefaultBool return the bool value if has no error
+// otherwise return the defaultval
+func (c *JSONConfigContainer) DefaultBool(key string, defaultval bool) bool {
+	if v, err := c.Bool(key); err == nil {
+		return v
+	}
+	return defaultval
+}
+
+// Int returns the integer value for a given key.
+func (c *JSONConfigContainer) Int(key string) (int, error) {
+	val := c.getData(key)
+	if val != nil {
+		if v, ok := val.(float64); ok {
+			return int(v), nil
+		}
+		return 0, errors.New("not int value")
+	}
+	return 0, errors.New("not exist key:" + key)
+}
+
+// DefaultInt returns the integer value for a given key.
+// if err != nil return defaltval
+func (c *JSONConfigContainer) DefaultInt(key string, defaultval int) int {
+	if v, err := c.Int(key); err == nil {
+		return v
+	}
+	return defaultval
+}
+
+// Int64 returns the int64 value for a given key.
+func (c *JSONConfigContainer) Int64(key string) (int64, error) {
+	val := c.getData(key)
+	if val != nil {
+		if v, ok := val.(float64); ok {
+			return int64(v), nil
+		}
+		return 0, errors.New("not int64 value")
+	}
+	return 0, errors.New("not exist key:" + key)
+}
+
+// DefaultInt64 returns the int64 value for a given key.
+// if err != nil return defaltval
+func (c *JSONConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
+	if v, err := c.Int64(key); err == nil {
+		return v
+	}
+	return defaultval
+}
+
+// Float returns the float value for a given key.
+func (c *JSONConfigContainer) Float(key string) (float64, error) {
+	val := c.getData(key)
+	if val != nil {
+		if v, ok := val.(float64); ok {
+			return v, nil
+		}
+		return 0.0, errors.New("not float64 value")
+	}
+	return 0.0, errors.New("not exist key:" + key)
+}
+
+// DefaultFloat returns the float64 value for a given key.
+// if err != nil return defaltval
+func (c *JSONConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
+	if v, err := c.Float(key); err == nil {
+		return v
+	}
+	return defaultval
+}
+
+// String returns the string value for a given key.
+func (c *JSONConfigContainer) String(key string) string {
+	val := c.getData(key)
+	if val != nil {
+		if v, ok := val.(string); ok {
+			return v
+		}
+	}
+	return ""
+}
+
+// DefaultString returns the string value for a given key.
+// if err != nil return defaltval
+func (c *JSONConfigContainer) DefaultString(key string, defaultval string) string {
+	// TODO FIXME should not use "" to replace non existence
+	if v := c.String(key); v != "" {
+		return v
+	}
+	return defaultval
+}
+
+// Strings returns the []string value for a given key.
+func (c *JSONConfigContainer) Strings(key string) []string {
+	stringVal := c.String(key)
+	if stringVal == "" {
+		return nil
+	}
+	return strings.Split(c.String(key), ";")
+}
+
+// DefaultStrings returns the []string value for a given key.
+// if err != nil return defaltval
+func (c *JSONConfigContainer) DefaultStrings(key string, defaultval []string) []string {
+	if v := c.Strings(key); v != nil {
+		return v
+	}
+	return defaultval
+}
+
+// GetSection returns map for the given section
+func (c *JSONConfigContainer) GetSection(section string) (map[string]string, error) {
+	if v, ok := c.data[section]; ok {
+		return v.(map[string]string), nil
+	}
+	return nil, errors.New("nonexist section " + section)
+}
+
+// SaveConfigFile save the config into file
+func (c *JSONConfigContainer) SaveConfigFile(filename string) (err error) {
+	// Write configuration file by filename.
+	f, err := os.Create(filename)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	b, err := json.MarshalIndent(c.data, "", "  ")
+	if err != nil {
+		return err
+	}
+	_, err = f.Write(b)
+	return err
+}
+
+// Set writes a new value for key.
+func (c *JSONConfigContainer) Set(key, val string) error {
+	c.Lock()
+	defer c.Unlock()
+	c.data[key] = val
+	return nil
+}
+
+// DIY returns the raw value by a given key.
+func (c *JSONConfigContainer) DIY(key string) (v interface{}, err error) {
+	val := c.getData(key)
+	if val != nil {
+		return val, nil
+	}
+	return nil, errors.New("not exist key")
+}
+
+// section.key or key
+func (c *JSONConfigContainer) getData(key string) interface{} {
+	if len(key) == 0 {
+		return nil
+	}
+
+	c.RLock()
+	defer c.RUnlock()
+
+	sectionKeys := strings.Split(key, "::")
+	if len(sectionKeys) >= 2 {
+		curValue, ok := c.data[sectionKeys[0]]
+		if !ok {
+			return nil
+		}
+		for _, key := range sectionKeys[1:] {
+			if v, ok := curValue.(map[string]interface{}); ok {
+				if curValue, ok = v[key]; !ok {
+					return nil
+				}
+			}
+		}
+		return curValue
+	}
+	if v, ok := c.data[key]; ok {
+		return v
+	}
+	return nil
+}
+
+func init() {
+	Register("json", &JSONConfig{})
+}

+ 222 - 0
vendor/github.com/astaxie/beego/config/json_test.go

@@ -0,0 +1,222 @@
+// 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 config
+
+import (
+	"fmt"
+	"os"
+	"testing"
+)
+
+func TestJsonStartsWithArray(t *testing.T) {
+
+	const jsoncontextwitharray = `[
+	{
+		"url": "user",
+		"serviceAPI": "http://www.test.com/user"
+	},
+	{
+		"url": "employee",
+		"serviceAPI": "http://www.test.com/employee"
+	}
+]`
+	f, err := os.Create("testjsonWithArray.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = f.WriteString(jsoncontextwitharray)
+	if err != nil {
+		f.Close()
+		t.Fatal(err)
+	}
+	f.Close()
+	defer os.Remove("testjsonWithArray.conf")
+	jsonconf, err := NewConfig("json", "testjsonWithArray.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+	rootArray, err := jsonconf.DIY("rootArray")
+	if err != nil {
+		t.Error("array does not exist as element")
+	}
+	rootArrayCasted := rootArray.([]interface{})
+	if rootArrayCasted == nil {
+		t.Error("array from root is nil")
+	} else {
+		elem := rootArrayCasted[0].(map[string]interface{})
+		if elem["url"] != "user" || elem["serviceAPI"] != "http://www.test.com/user" {
+			t.Error("array[0] values are not valid")
+		}
+
+		elem2 := rootArrayCasted[1].(map[string]interface{})
+		if elem2["url"] != "employee" || elem2["serviceAPI"] != "http://www.test.com/employee" {
+			t.Error("array[1] values are not valid")
+		}
+	}
+}
+
+func TestJson(t *testing.T) {
+
+	var (
+		jsoncontext = `{
+"appname": "beeapi",
+"testnames": "foo;bar",
+"httpport": 8080,
+"mysqlport": 3600,
+"PI": 3.1415976, 
+"runmode": "dev",
+"autorender": false,
+"copyrequestbody": true,
+"session": "on",
+"cookieon": "off",
+"newreg": "OFF",
+"needlogin": "ON",
+"enableSession": "Y",
+"enableCookie": "N",
+"flag": 1,
+"path1": "${GOPATH}",
+"path2": "${GOPATH||/home/go}",
+"database": {
+        "host": "host",
+        "port": "port",
+        "database": "database",
+        "username": "username",
+        "password": "${GOPATH}",
+		"conns":{
+			"maxconnection":12,
+			"autoconnect":true,
+			"connectioninfo":"info",
+			"root": "${GOPATH}"
+		}
+    }
+}`
+		keyValue = map[string]interface{}{
+			"appname":                         "beeapi",
+			"testnames":                       []string{"foo", "bar"},
+			"httpport":                        8080,
+			"mysqlport":                       int64(3600),
+			"PI":                              3.1415976,
+			"runmode":                         "dev",
+			"autorender":                      false,
+			"copyrequestbody":                 true,
+			"session":                         true,
+			"cookieon":                        false,
+			"newreg":                          false,
+			"needlogin":                       true,
+			"enableSession":                   true,
+			"enableCookie":                    false,
+			"flag":                            true,
+			"path1":                           os.Getenv("GOPATH"),
+			"path2":                           os.Getenv("GOPATH"),
+			"database::host":                  "host",
+			"database::port":                  "port",
+			"database::database":              "database",
+			"database::password":              os.Getenv("GOPATH"),
+			"database::conns::maxconnection":  12,
+			"database::conns::autoconnect":    true,
+			"database::conns::connectioninfo": "info",
+			"database::conns::root":           os.Getenv("GOPATH"),
+			"unknown":                         "",
+		}
+	)
+
+	f, err := os.Create("testjson.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = f.WriteString(jsoncontext)
+	if err != nil {
+		f.Close()
+		t.Fatal(err)
+	}
+	f.Close()
+	defer os.Remove("testjson.conf")
+	jsonconf, err := NewConfig("json", "testjson.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for k, v := range keyValue {
+		var err error
+		var value interface{}
+		switch v.(type) {
+		case int:
+			value, err = jsonconf.Int(k)
+		case int64:
+			value, err = jsonconf.Int64(k)
+		case float64:
+			value, err = jsonconf.Float(k)
+		case bool:
+			value, err = jsonconf.Bool(k)
+		case []string:
+			value = jsonconf.Strings(k)
+		case string:
+			value = jsonconf.String(k)
+		default:
+			value, err = jsonconf.DIY(k)
+		}
+		if err != nil {
+			t.Fatalf("get key %q value fatal,%v err %s", k, v, err)
+		} else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) {
+			t.Fatalf("get key %q value, want %v got %v .", k, v, value)
+		}
+
+	}
+	if err = jsonconf.Set("name", "astaxie"); err != nil {
+		t.Fatal(err)
+	}
+	if jsonconf.String("name") != "astaxie" {
+		t.Fatal("get name error")
+	}
+
+	if db, err := jsonconf.DIY("database"); err != nil {
+		t.Fatal(err)
+	} else if m, ok := db.(map[string]interface{}); !ok {
+		t.Log(db)
+		t.Fatal("db not map[string]interface{}")
+	} else {
+		if m["host"].(string) != "host" {
+			t.Fatal("get host err")
+		}
+	}
+
+	if _, err := jsonconf.Int("unknown"); err == nil {
+		t.Error("unknown keys should return an error when expecting an Int")
+	}
+
+	if _, err := jsonconf.Int64("unknown"); err == nil {
+		t.Error("unknown keys should return an error when expecting an Int64")
+	}
+
+	if _, err := jsonconf.Float("unknown"); err == nil {
+		t.Error("unknown keys should return an error when expecting a Float")
+	}
+
+	if _, err := jsonconf.DIY("unknown"); err == nil {
+		t.Error("unknown keys should return an error when expecting an interface{}")
+	}
+
+	if val := jsonconf.String("unknown"); val != "" {
+		t.Error("unknown keys should return an empty string when expecting a String")
+	}
+
+	if _, err := jsonconf.Bool("unknown"); err == nil {
+		t.Error("unknown keys should return an error when expecting a Bool")
+	}
+
+	if !jsonconf.DefaultBool("unknow", true) {
+		t.Error("unknown keys with default value wrong")
+	}
+}

+ 228 - 0
vendor/github.com/astaxie/beego/config/xml/xml.go

@@ -0,0 +1,228 @@
+// 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 xml for config provider.
+//
+// depend on github.com/beego/x2j.
+//
+// go install github.com/beego/x2j.
+//
+// Usage:
+//  import(
+//    _ "github.com/astaxie/beego/config/xml"
+//      "github.com/astaxie/beego/config"
+//  )
+//
+//  cnf, err := config.NewConfig("xml", "config.xml")
+//
+//More docs http://beego.me/docs/module/config.md
+package xml
+
+import (
+	"encoding/xml"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"strconv"
+	"strings"
+	"sync"
+
+	"github.com/astaxie/beego/config"
+	"github.com/beego/x2j"
+)
+
+// Config is a xml config parser and implements Config interface.
+// xml configurations should be included in <config></config> tag.
+// only support key/value pair as <key>value</key> as each item.
+type Config struct{}
+
+// Parse returns a ConfigContainer with parsed xml config map.
+func (xc *Config) Parse(filename string) (config.Configer, error) {
+	context, err := ioutil.ReadFile(filename)
+	if err != nil {
+		return nil, err
+	}
+
+	return xc.ParseData(context)
+}
+
+// ParseData xml data
+func (xc *Config) ParseData(data []byte) (config.Configer, error) {
+	x := &ConfigContainer{data: make(map[string]interface{})}
+
+	d, err := x2j.DocToMap(string(data))
+	if err != nil {
+		return nil, err
+	}
+
+	x.data = config.ExpandValueEnvForMap(d["config"].(map[string]interface{}))
+
+	return x, nil
+}
+
+// ConfigContainer A Config represents the xml configuration.
+type ConfigContainer struct {
+	data map[string]interface{}
+	sync.Mutex
+}
+
+// Bool returns the boolean value for a given key.
+func (c *ConfigContainer) Bool(key string) (bool, error) {
+	if v := c.data[key]; v != nil {
+		return config.ParseBool(v)
+	}
+	return false, fmt.Errorf("not exist key: %q", key)
+}
+
+// DefaultBool return the bool value if has no error
+// otherwise return the defaultval
+func (c *ConfigContainer) DefaultBool(key string, defaultval bool) bool {
+	v, err := c.Bool(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// Int returns the integer value for a given key.
+func (c *ConfigContainer) Int(key string) (int, error) {
+	return strconv.Atoi(c.data[key].(string))
+}
+
+// DefaultInt returns the integer value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultInt(key string, defaultval int) int {
+	v, err := c.Int(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// Int64 returns the int64 value for a given key.
+func (c *ConfigContainer) Int64(key string) (int64, error) {
+	return strconv.ParseInt(c.data[key].(string), 10, 64)
+}
+
+// DefaultInt64 returns the int64 value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
+	v, err := c.Int64(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+
+}
+
+// Float returns the float value for a given key.
+func (c *ConfigContainer) Float(key string) (float64, error) {
+	return strconv.ParseFloat(c.data[key].(string), 64)
+}
+
+// DefaultFloat returns the float64 value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
+	v, err := c.Float(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// String returns the string value for a given key.
+func (c *ConfigContainer) String(key string) string {
+	if v, ok := c.data[key].(string); ok {
+		return v
+	}
+	return ""
+}
+
+// DefaultString returns the string value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultString(key string, defaultval string) string {
+	v := c.String(key)
+	if v == "" {
+		return defaultval
+	}
+	return v
+}
+
+// Strings returns the []string value for a given key.
+func (c *ConfigContainer) Strings(key string) []string {
+	v := c.String(key)
+	if v == "" {
+		return nil
+	}
+	return strings.Split(v, ";")
+}
+
+// DefaultStrings returns the []string value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string {
+	v := c.Strings(key)
+	if v == nil {
+		return defaultval
+	}
+	return v
+}
+
+// GetSection returns map for the given section
+func (c *ConfigContainer) GetSection(section string) (map[string]string, error) {
+	if v, ok := c.data[section].(map[string]interface{}); ok {
+		mapstr := make(map[string]string)
+		for k, val := range v {
+			mapstr[k] = config.ToString(val)
+		}
+		return mapstr, nil
+	}
+	return nil, fmt.Errorf("section '%s' not found", section)
+}
+
+// SaveConfigFile save the config into file
+func (c *ConfigContainer) SaveConfigFile(filename string) (err error) {
+	// Write configuration file by filename.
+	f, err := os.Create(filename)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	b, err := xml.MarshalIndent(c.data, "  ", "    ")
+	if err != nil {
+		return err
+	}
+	_, err = f.Write(b)
+	return err
+}
+
+// Set writes a new value for key.
+func (c *ConfigContainer) Set(key, val string) error {
+	c.Lock()
+	defer c.Unlock()
+	c.data[key] = val
+	return nil
+}
+
+// DIY returns the raw value by a given key.
+func (c *ConfigContainer) DIY(key string) (v interface{}, err error) {
+	if v, ok := c.data[key]; ok {
+		return v, nil
+	}
+	return nil, errors.New("not exist key")
+}
+
+func init() {
+	config.Register("xml", &Config{})
+}

+ 125 - 0
vendor/github.com/astaxie/beego/config/xml/xml_test.go

@@ -0,0 +1,125 @@
+// 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 xml
+
+import (
+	"fmt"
+	"os"
+	"testing"
+
+	"github.com/astaxie/beego/config"
+)
+
+func TestXML(t *testing.T) {
+
+	var (
+		//xml parse should incluce in <config></config> tags
+		xmlcontext = `<?xml version="1.0" encoding="UTF-8"?>
+<config>
+<appname>beeapi</appname>
+<httpport>8080</httpport>
+<mysqlport>3600</mysqlport>
+<PI>3.1415976</PI>
+<runmode>dev</runmode>
+<autorender>false</autorender>
+<copyrequestbody>true</copyrequestbody>
+<path1>${GOPATH}</path1>
+<path2>${GOPATH||/home/go}</path2>
+<mysection>
+<id>1</id>
+<name>MySection</name>
+</mysection>
+</config>
+`
+		keyValue = map[string]interface{}{
+			"appname":         "beeapi",
+			"httpport":        8080,
+			"mysqlport":       int64(3600),
+			"PI":              3.1415976,
+			"runmode":         "dev",
+			"autorender":      false,
+			"copyrequestbody": true,
+			"path1":           os.Getenv("GOPATH"),
+			"path2":           os.Getenv("GOPATH"),
+			"error":           "",
+			"emptystrings":    []string{},
+		}
+	)
+
+	f, err := os.Create("testxml.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = f.WriteString(xmlcontext)
+	if err != nil {
+		f.Close()
+		t.Fatal(err)
+	}
+	f.Close()
+	defer os.Remove("testxml.conf")
+
+	xmlconf, err := config.NewConfig("xml", "testxml.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var xmlsection map[string]string
+	xmlsection, err = xmlconf.GetSection("mysection")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(xmlsection) == 0 {
+		t.Error("section should not be empty")
+	}
+
+	for k, v := range keyValue {
+
+		var (
+			value interface{}
+			err   error
+		)
+
+		switch v.(type) {
+		case int:
+			value, err = xmlconf.Int(k)
+		case int64:
+			value, err = xmlconf.Int64(k)
+		case float64:
+			value, err = xmlconf.Float(k)
+		case bool:
+			value, err = xmlconf.Bool(k)
+		case []string:
+			value = xmlconf.Strings(k)
+		case string:
+			value = xmlconf.String(k)
+		default:
+			value, err = xmlconf.DIY(k)
+		}
+		if err != nil {
+			t.Errorf("get key %q value fatal,%v err %s", k, v, err)
+		} else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) {
+			t.Errorf("get key %q value, want %v got %v .", k, v, value)
+		}
+
+	}
+
+	if err = xmlconf.Set("name", "astaxie"); err != nil {
+		t.Fatal(err)
+	}
+	if xmlconf.String("name") != "astaxie" {
+		t.Fatal("get name error")
+	}
+}

+ 297 - 0
vendor/github.com/astaxie/beego/config/yaml/yaml.go

@@ -0,0 +1,297 @@
+// 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 yaml for config provider
+//
+// depend on github.com/beego/goyaml2
+//
+// go install github.com/beego/goyaml2
+//
+// Usage:
+//  import(
+//   _ "github.com/astaxie/beego/config/yaml"
+//     "github.com/astaxie/beego/config"
+//  )
+//
+//  cnf, err := config.NewConfig("yaml", "config.yaml")
+//
+//More docs http://beego.me/docs/module/config.md
+package yaml
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"strings"
+	"sync"
+
+	"github.com/astaxie/beego/config"
+	"github.com/beego/goyaml2"
+)
+
+// Config is a yaml config parser and implements Config interface.
+type Config struct{}
+
+// Parse returns a ConfigContainer with parsed yaml config map.
+func (yaml *Config) Parse(filename string) (y config.Configer, err error) {
+	cnf, err := ReadYmlReader(filename)
+	if err != nil {
+		return
+	}
+	y = &ConfigContainer{
+		data: cnf,
+	}
+	return
+}
+
+// ParseData parse yaml data
+func (yaml *Config) ParseData(data []byte) (config.Configer, error) {
+	cnf, err := parseYML(data)
+	if err != nil {
+		return nil, err
+	}
+
+	return &ConfigContainer{
+		data: cnf,
+	}, nil
+}
+
+// ReadYmlReader Read yaml file to map.
+// if json like, use json package, unless goyaml2 package.
+func ReadYmlReader(path string) (cnf map[string]interface{}, err error) {
+	buf, err := ioutil.ReadFile(path)
+	if err != nil {
+		return
+	}
+
+	return parseYML(buf)
+}
+
+// parseYML parse yaml formatted []byte to map.
+func parseYML(buf []byte) (cnf map[string]interface{}, err error) {
+	if len(buf) < 3 {
+		return
+	}
+
+	if string(buf[0:1]) == "{" {
+		log.Println("Look like a Json, try json umarshal")
+		err = json.Unmarshal(buf, &cnf)
+		if err == nil {
+			log.Println("It is Json Map")
+			return
+		}
+	}
+
+	data, err := goyaml2.Read(bytes.NewBuffer(buf))
+	if err != nil {
+		log.Println("Goyaml2 ERR>", string(buf), err)
+		return
+	}
+
+	if data == nil {
+		log.Println("Goyaml2 output nil? Pls report bug\n" + string(buf))
+		return
+	}
+	cnf, ok := data.(map[string]interface{})
+	if !ok {
+		log.Println("Not a Map? >> ", string(buf), data)
+		cnf = nil
+	}
+	cnf = config.ExpandValueEnvForMap(cnf)
+	return
+}
+
+// ConfigContainer A Config represents the yaml configuration.
+type ConfigContainer struct {
+	data map[string]interface{}
+	sync.Mutex
+}
+
+// Bool returns the boolean value for a given key.
+func (c *ConfigContainer) Bool(key string) (bool, error) {
+	v, err := c.getData(key)
+	if err != nil {
+		return false, err
+	}
+	return config.ParseBool(v)
+}
+
+// DefaultBool return the bool value if has no error
+// otherwise return the defaultval
+func (c *ConfigContainer) DefaultBool(key string, defaultval bool) bool {
+	v, err := c.Bool(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// Int returns the integer value for a given key.
+func (c *ConfigContainer) Int(key string) (int, error) {
+	if v, err := c.getData(key); err != nil {
+		return 0, err
+	} else if vv, ok := v.(int); ok {
+		return vv, nil
+	} else if vv, ok := v.(int64); ok {
+		return int(vv), nil
+	}
+	return 0, errors.New("not int value")
+}
+
+// DefaultInt returns the integer value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultInt(key string, defaultval int) int {
+	v, err := c.Int(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// Int64 returns the int64 value for a given key.
+func (c *ConfigContainer) Int64(key string) (int64, error) {
+	if v, err := c.getData(key); err != nil {
+		return 0, err
+	} else if vv, ok := v.(int64); ok {
+		return vv, nil
+	}
+	return 0, errors.New("not bool value")
+}
+
+// DefaultInt64 returns the int64 value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
+	v, err := c.Int64(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// Float returns the float value for a given key.
+func (c *ConfigContainer) Float(key string) (float64, error) {
+	if v, err := c.getData(key); err != nil {
+		return 0.0, err
+	} else if vv, ok := v.(float64); ok {
+		return vv, nil
+	} else if vv, ok := v.(int); ok {
+		return float64(vv), nil
+	} else if vv, ok := v.(int64); ok {
+		return float64(vv), nil
+	}
+	return 0.0, errors.New("not float64 value")
+}
+
+// DefaultFloat returns the float64 value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
+	v, err := c.Float(key)
+	if err != nil {
+		return defaultval
+	}
+	return v
+}
+
+// String returns the string value for a given key.
+func (c *ConfigContainer) String(key string) string {
+	if v, err := c.getData(key); err == nil {
+		if vv, ok := v.(string); ok {
+			return vv
+		}
+	}
+	return ""
+}
+
+// DefaultString returns the string value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultString(key string, defaultval string) string {
+	v := c.String(key)
+	if v == "" {
+		return defaultval
+	}
+	return v
+}
+
+// Strings returns the []string value for a given key.
+func (c *ConfigContainer) Strings(key string) []string {
+	v := c.String(key)
+	if v == "" {
+		return nil
+	}
+	return strings.Split(v, ";")
+}
+
+// DefaultStrings returns the []string value for a given key.
+// if err != nil return defaltval
+func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string {
+	v := c.Strings(key)
+	if v == nil {
+		return defaultval
+	}
+	return v
+}
+
+// GetSection returns map for the given section
+func (c *ConfigContainer) GetSection(section string) (map[string]string, error) {
+
+	if v, ok := c.data[section]; ok {
+		return v.(map[string]string), nil
+	}
+	return nil, errors.New("not exist section")
+}
+
+// SaveConfigFile save the config into file
+func (c *ConfigContainer) SaveConfigFile(filename string) (err error) {
+	// Write configuration file by filename.
+	f, err := os.Create(filename)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	err = goyaml2.Write(f, c.data)
+	return err
+}
+
+// Set writes a new value for key.
+func (c *ConfigContainer) Set(key, val string) error {
+	c.Lock()
+	defer c.Unlock()
+	c.data[key] = val
+	return nil
+}
+
+// DIY returns the raw value by a given key.
+func (c *ConfigContainer) DIY(key string) (v interface{}, err error) {
+	return c.getData(key)
+}
+
+func (c *ConfigContainer) getData(key string) (interface{}, error) {
+
+	if len(key) == 0 {
+		return nil, errors.New("key is empty")
+	}
+
+	if v, ok := c.data[key]; ok {
+		return v, nil
+	}
+	return nil, fmt.Errorf("not exist key %q", key)
+}
+
+func init() {
+	config.Register("yaml", &Config{})
+}

+ 115 - 0
vendor/github.com/astaxie/beego/config/yaml/yaml_test.go

@@ -0,0 +1,115 @@
+// 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 yaml
+
+import (
+	"fmt"
+	"os"
+	"testing"
+
+	"github.com/astaxie/beego/config"
+)
+
+func TestYaml(t *testing.T) {
+
+	var (
+		yamlcontext = `
+"appname": beeapi
+"httpport": 8080
+"mysqlport": 3600
+"PI": 3.1415976
+"runmode": dev
+"autorender": false
+"copyrequestbody": true
+"PATH": GOPATH
+"path1": ${GOPATH}
+"path2": ${GOPATH||/home/go}
+"empty": "" 
+`
+
+		keyValue = map[string]interface{}{
+			"appname":         "beeapi",
+			"httpport":        8080,
+			"mysqlport":       int64(3600),
+			"PI":              3.1415976,
+			"runmode":         "dev",
+			"autorender":      false,
+			"copyrequestbody": true,
+			"PATH":            "GOPATH",
+			"path1":           os.Getenv("GOPATH"),
+			"path2":           os.Getenv("GOPATH"),
+			"error":           "",
+			"emptystrings":    []string{},
+		}
+	)
+	f, err := os.Create("testyaml.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = f.WriteString(yamlcontext)
+	if err != nil {
+		f.Close()
+		t.Fatal(err)
+	}
+	f.Close()
+	defer os.Remove("testyaml.conf")
+	yamlconf, err := config.NewConfig("yaml", "testyaml.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if yamlconf.String("appname") != "beeapi" {
+		t.Fatal("appname not equal to beeapi")
+	}
+
+	for k, v := range keyValue {
+
+		var (
+			value interface{}
+			err   error
+		)
+
+		switch v.(type) {
+		case int:
+			value, err = yamlconf.Int(k)
+		case int64:
+			value, err = yamlconf.Int64(k)
+		case float64:
+			value, err = yamlconf.Float(k)
+		case bool:
+			value, err = yamlconf.Bool(k)
+		case []string:
+			value = yamlconf.Strings(k)
+		case string:
+			value = yamlconf.String(k)
+		default:
+			value, err = yamlconf.DIY(k)
+		}
+		if err != nil {
+			t.Errorf("get key %q value fatal,%v err %s", k, v, err)
+		} else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) {
+			t.Errorf("get key %q value, want %v got %v .", k, v, value)
+		}
+
+	}
+
+	if err = yamlconf.Set("name", "astaxie"); err != nil {
+		t.Fatal(err)
+	}
+	if yamlconf.String("name") != "astaxie" {
+		t.Fatal("get name error")
+	}
+
+}

+ 138 - 0
vendor/github.com/astaxie/beego/config_test.go

@@ -0,0 +1,138 @@
+// 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 beego
+
+import (
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	"github.com/astaxie/beego/config"
+)
+
+func TestDefaults(t *testing.T) {
+	if BConfig.WebConfig.FlashName != "BEEGO_FLASH" {
+		t.Errorf("FlashName was not set to default.")
+	}
+
+	if BConfig.WebConfig.FlashSeparator != "BEEGOFLASH" {
+		t.Errorf("FlashName was not set to default.")
+	}
+}
+
+func TestAssignConfig_01(t *testing.T) {
+	_BConfig := &Config{}
+	_BConfig.AppName = "beego_test"
+	jcf := &config.JSONConfig{}
+	ac, _ := jcf.ParseData([]byte(`{"AppName":"beego_json"}`))
+	assignSingleConfig(_BConfig, ac)
+	if _BConfig.AppName != "beego_json" {
+		t.Log(_BConfig)
+		t.FailNow()
+	}
+}
+
+func TestAssignConfig_02(t *testing.T) {
+	_BConfig := &Config{}
+	bs, _ := json.Marshal(newBConfig())
+
+	jsonMap := map[string]interface{}{}
+	json.Unmarshal(bs, &jsonMap)
+
+	configMap := map[string]interface{}{}
+	for k, v := range jsonMap {
+		if reflect.TypeOf(v).Kind() == reflect.Map {
+			for k1, v1 := range v.(map[string]interface{}) {
+				if reflect.TypeOf(v1).Kind() == reflect.Map {
+					for k2, v2 := range v1.(map[string]interface{}) {
+						configMap[k2] = v2
+					}
+				} else {
+					configMap[k1] = v1
+				}
+			}
+		} else {
+			configMap[k] = v
+		}
+	}
+	configMap["MaxMemory"] = 1024
+	configMap["Graceful"] = true
+	configMap["XSRFExpire"] = 32
+	configMap["SessionProviderConfig"] = "file"
+	configMap["FileLineNum"] = true
+
+	jcf := &config.JSONConfig{}
+	bs, _ = json.Marshal(configMap)
+	ac, _ := jcf.ParseData([]byte(bs))
+
+	for _, i := range []interface{}{_BConfig, &_BConfig.Listen, &_BConfig.WebConfig, &_BConfig.Log, &_BConfig.WebConfig.Session} {
+		assignSingleConfig(i, ac)
+	}
+
+	if _BConfig.MaxMemory != 1024 {
+		t.Log(_BConfig.MaxMemory)
+		t.FailNow()
+	}
+
+	if !_BConfig.Listen.Graceful {
+		t.Log(_BConfig.Listen.Graceful)
+		t.FailNow()
+	}
+
+	if _BConfig.WebConfig.XSRFExpire != 32 {
+		t.Log(_BConfig.WebConfig.XSRFExpire)
+		t.FailNow()
+	}
+
+	if _BConfig.WebConfig.Session.SessionProviderConfig != "file" {
+		t.Log(_BConfig.WebConfig.Session.SessionProviderConfig)
+		t.FailNow()
+	}
+
+	if !_BConfig.Log.FileLineNum {
+		t.Log(_BConfig.Log.FileLineNum)
+		t.FailNow()
+	}
+
+}
+
+func TestAssignConfig_03(t *testing.T) {
+	jcf := &config.JSONConfig{}
+	ac, _ := jcf.ParseData([]byte(`{"AppName":"beego"}`))
+	ac.Set("AppName", "test_app")
+	ac.Set("RunMode", "online")
+	ac.Set("StaticDir", "download:down download2:down2")
+	ac.Set("StaticExtensionsToGzip", ".css,.js,.html,.jpg,.png")
+	assignConfig(ac)
+
+	t.Logf("%#v", BConfig)
+
+	if BConfig.AppName != "test_app" {
+		t.FailNow()
+	}
+
+	if BConfig.RunMode != "online" {
+		t.FailNow()
+	}
+	if BConfig.WebConfig.StaticDir["/download"] != "down" {
+		t.FailNow()
+	}
+	if BConfig.WebConfig.StaticDir["/download2"] != "down2" {
+		t.FailNow()
+	}
+	if len(BConfig.WebConfig.StaticExtensionsToGzip) != 5 {
+		t.FailNow()
+	}
+}

+ 232 - 0
vendor/github.com/astaxie/beego/context/acceptencoder.go

@@ -0,0 +1,232 @@
+// Copyright 2015 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 context
+
+import (
+	"bytes"
+	"compress/flate"
+	"compress/gzip"
+	"compress/zlib"
+	"io"
+	"net/http"
+	"os"
+	"strconv"
+	"strings"
+	"sync"
+)
+
+var (
+	//Default size==20B same as nginx
+	defaultGzipMinLength = 20
+	//Content will only be compressed if content length is either unknown or greater than gzipMinLength.
+	gzipMinLength = defaultGzipMinLength
+	//The compression level used for deflate compression. (0-9).
+	gzipCompressLevel int
+	//List of HTTP methods to compress. If not set, only GET requests are compressed.
+	includedMethods map[string]bool
+	getMethodOnly   bool
+)
+
+// InitGzip init the gzipcompress
+func InitGzip(minLength, compressLevel int, methods []string) {
+	if minLength >= 0 {
+		gzipMinLength = minLength
+	}
+	gzipCompressLevel = compressLevel
+	if gzipCompressLevel < flate.NoCompression || gzipCompressLevel > flate.BestCompression {
+		gzipCompressLevel = flate.BestSpeed
+	}
+	getMethodOnly = (len(methods) == 0) || (len(methods) == 1 && strings.ToUpper(methods[0]) == "GET")
+	includedMethods = make(map[string]bool, len(methods))
+	for _, v := range methods {
+		includedMethods[strings.ToUpper(v)] = true
+	}
+}
+
+type resetWriter interface {
+	io.Writer
+	Reset(w io.Writer)
+}
+
+type nopResetWriter struct {
+	io.Writer
+}
+
+func (n nopResetWriter) Reset(w io.Writer) {
+	//do nothing
+}
+
+type acceptEncoder struct {
+	name                    string
+	levelEncode             func(int) resetWriter
+	customCompressLevelPool *sync.Pool
+	bestCompressionPool     *sync.Pool
+}
+
+func (ac acceptEncoder) encode(wr io.Writer, level int) resetWriter {
+	if ac.customCompressLevelPool == nil || ac.bestCompressionPool == nil {
+		return nopResetWriter{wr}
+	}
+	var rwr resetWriter
+	switch level {
+	case flate.BestSpeed:
+		rwr = ac.customCompressLevelPool.Get().(resetWriter)
+	case flate.BestCompression:
+		rwr = ac.bestCompressionPool.Get().(resetWriter)
+	default:
+		rwr = ac.levelEncode(level)
+	}
+	rwr.Reset(wr)
+	return rwr
+}
+
+func (ac acceptEncoder) put(wr resetWriter, level int) {
+	if ac.customCompressLevelPool == nil || ac.bestCompressionPool == nil {
+		return
+	}
+	wr.Reset(nil)
+
+	//notice
+	//compressionLevel==BestCompression DOES NOT MATTER
+	//sync.Pool will not memory leak
+
+	switch level {
+	case gzipCompressLevel:
+		ac.customCompressLevelPool.Put(wr)
+	case flate.BestCompression:
+		ac.bestCompressionPool.Put(wr)
+	}
+}
+
+var (
+	noneCompressEncoder = acceptEncoder{"", nil, nil, nil}
+	gzipCompressEncoder = acceptEncoder{
+		name:                    "gzip",
+		levelEncode:             func(level int) resetWriter { wr, _ := gzip.NewWriterLevel(nil, level); return wr },
+		customCompressLevelPool: &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, gzipCompressLevel); return wr }},
+		bestCompressionPool:     &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestCompression); return wr }},
+	}
+
+	//according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed
+	//deflate
+	//The "zlib" format defined in RFC 1950 [31] in combination with
+	//the "deflate" compression mechanism described in RFC 1951 [29].
+	deflateCompressEncoder = acceptEncoder{
+		name:                    "deflate",
+		levelEncode:             func(level int) resetWriter { wr, _ := zlib.NewWriterLevel(nil, level); return wr },
+		customCompressLevelPool: &sync.Pool{New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, gzipCompressLevel); return wr }},
+		bestCompressionPool:     &sync.Pool{New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestCompression); return wr }},
+	}
+)
+
+var (
+	encoderMap = map[string]acceptEncoder{ // all the other compress methods will ignore
+		"gzip":     gzipCompressEncoder,
+		"deflate":  deflateCompressEncoder,
+		"*":        gzipCompressEncoder, // * means any compress will accept,we prefer gzip
+		"identity": noneCompressEncoder, // identity means none-compress
+	}
+)
+
+// WriteFile reads from file and writes to writer by the specific encoding(gzip/deflate)
+func WriteFile(encoding string, writer io.Writer, file *os.File) (bool, string, error) {
+	return writeLevel(encoding, writer, file, flate.BestCompression)
+}
+
+// WriteBody reads  writes content to writer by the specific encoding(gzip/deflate)
+func WriteBody(encoding string, writer io.Writer, content []byte) (bool, string, error) {
+	if encoding == "" || len(content) < gzipMinLength {
+		_, err := writer.Write(content)
+		return false, "", err
+	}
+	return writeLevel(encoding, writer, bytes.NewReader(content), gzipCompressLevel)
+}
+
+// writeLevel reads from reader,writes to writer by specific encoding and compress level
+// the compress level is defined by deflate package
+func writeLevel(encoding string, writer io.Writer, reader io.Reader, level int) (bool, string, error) {
+	var outputWriter resetWriter
+	var err error
+	var ce = noneCompressEncoder
+
+	if cf, ok := encoderMap[encoding]; ok {
+		ce = cf
+	}
+	encoding = ce.name
+	outputWriter = ce.encode(writer, level)
+	defer ce.put(outputWriter, level)
+
+	_, err = io.Copy(outputWriter, reader)
+	if err != nil {
+		return false, "", err
+	}
+
+	switch outputWriter.(type) {
+	case io.WriteCloser:
+		outputWriter.(io.WriteCloser).Close()
+	}
+	return encoding != "", encoding, nil
+}
+
+// ParseEncoding will extract the right encoding for response
+// the Accept-Encoding's sec is here:
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
+func ParseEncoding(r *http.Request) string {
+	if r == nil {
+		return ""
+	}
+	if (getMethodOnly && r.Method == "GET") || includedMethods[r.Method] {
+		return parseEncoding(r)
+	}
+	return ""
+}
+
+type q struct {
+	name  string
+	value float64
+}
+
+func parseEncoding(r *http.Request) string {
+	acceptEncoding := r.Header.Get("Accept-Encoding")
+	if acceptEncoding == "" {
+		return ""
+	}
+	var lastQ q
+	for _, v := range strings.Split(acceptEncoding, ",") {
+		v = strings.TrimSpace(v)
+		if v == "" {
+			continue
+		}
+		vs := strings.Split(v, ";")
+		var cf acceptEncoder
+		var ok bool
+		if cf, ok = encoderMap[vs[0]]; !ok {
+			continue
+		}
+		if len(vs) == 1 {
+			return cf.name
+		}
+		if len(vs) == 2 {
+			f, _ := strconv.ParseFloat(strings.Replace(vs[1], "q=", "", -1), 64)
+			if f == 0 {
+				continue
+			}
+			if f > lastQ.value {
+				lastQ = q{cf.name, f}
+			}
+		}
+	}
+	return lastQ.name
+}

+ 59 - 0
vendor/github.com/astaxie/beego/context/acceptencoder_test.go

@@ -0,0 +1,59 @@
+// Copyright 2015 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 context
+
+import (
+	"net/http"
+	"testing"
+)
+
+func Test_ExtractEncoding(t *testing.T) {
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip,deflate"}}}) != "gzip" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"deflate,gzip"}}}) != "deflate" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip;q=.5,deflate"}}}) != "deflate" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip;q=.5,deflate;q=0.3"}}}) != "gzip" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip;q=0,deflate"}}}) != "deflate" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"deflate;q=0.5,gzip;q=0.5,identity"}}}) != "" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"*"}}}) != "gzip" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"x,gzip,deflate"}}}) != "gzip" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip,x,deflate"}}}) != "gzip" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip;q=0.5,x,deflate"}}}) != "deflate" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"x"}}}) != "" {
+		t.Fail()
+	}
+	if parseEncoding(&http.Request{Header: map[string][]string{"Accept-Encoding": {"gzip;q=0.5,x;q=0.8"}}}) != "gzip" {
+		t.Fail()
+	}
+}

+ 246 - 0
vendor/github.com/astaxie/beego/context/context.go

@@ -0,0 +1,246 @@
+// 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 context provide the context utils
+// Usage:
+//
+//	import "github.com/astaxie/beego/context"
+//
+//	ctx := context.Context{Request:req,ResponseWriter:rw}
+//
+//  more docs http://beego.me/docs/module/context.md
+package context
+
+import (
+	"bufio"
+	"crypto/hmac"
+	"crypto/sha1"
+	"encoding/base64"
+	"errors"
+	"fmt"
+	"net"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/astaxie/beego/utils"
+)
+
+// NewContext return the Context with Input and Output
+func NewContext() *Context {
+	return &Context{
+		Input:  NewInput(),
+		Output: NewOutput(),
+	}
+}
+
+// Context Http request context struct including BeegoInput, BeegoOutput, http.Request and http.ResponseWriter.
+// BeegoInput and BeegoOutput provides some api to operate request and response more easily.
+type Context struct {
+	Input          *BeegoInput
+	Output         *BeegoOutput
+	Request        *http.Request
+	ResponseWriter *Response
+	_xsrfToken     string
+}
+
+// Reset init Context, BeegoInput and BeegoOutput
+func (ctx *Context) Reset(rw http.ResponseWriter, r *http.Request) {
+	ctx.Request = r
+	if ctx.ResponseWriter == nil {
+		ctx.ResponseWriter = &Response{}
+	}
+	ctx.ResponseWriter.reset(rw)
+	ctx.Input.Reset(ctx)
+	ctx.Output.Reset(ctx)
+	ctx._xsrfToken = ""
+}
+
+// Redirect does redirection to localurl with http header status code.
+func (ctx *Context) Redirect(status int, localurl string) {
+	http.Redirect(ctx.ResponseWriter, ctx.Request, localurl, status)
+}
+
+// Abort stops this request.
+// if beego.ErrorMaps exists, panic body.
+func (ctx *Context) Abort(status int, body string) {
+	ctx.Output.SetStatus(status)
+	panic(body)
+}
+
+// WriteString Write string to response body.
+// it sends response body.
+func (ctx *Context) WriteString(content string) {
+	ctx.ResponseWriter.Write([]byte(content))
+}
+
+// GetCookie Get cookie from request by a given key.
+// It's alias of BeegoInput.Cookie.
+func (ctx *Context) GetCookie(key string) string {
+	return ctx.Input.Cookie(key)
+}
+
+// SetCookie Set cookie for response.
+// It's alias of BeegoOutput.Cookie.
+func (ctx *Context) SetCookie(name string, value string, others ...interface{}) {
+	ctx.Output.Cookie(name, value, others...)
+}
+
+// GetSecureCookie Get secure cookie from request by a given key.
+func (ctx *Context) GetSecureCookie(Secret, key string) (string, bool) {
+	val := ctx.Input.Cookie(key)
+	if val == "" {
+		return "", false
+	}
+
+	parts := strings.SplitN(val, "|", 3)
+
+	if len(parts) != 3 {
+		return "", false
+	}
+
+	vs := parts[0]
+	timestamp := parts[1]
+	sig := parts[2]
+
+	h := hmac.New(sha1.New, []byte(Secret))
+	fmt.Fprintf(h, "%s%s", vs, timestamp)
+
+	if fmt.Sprintf("%02x", h.Sum(nil)) != sig {
+		return "", false
+	}
+	res, _ := base64.URLEncoding.DecodeString(vs)
+	return string(res), true
+}
+
+// SetSecureCookie Set Secure cookie for response.
+func (ctx *Context) SetSecureCookie(Secret, name, value string, others ...interface{}) {
+	vs := base64.URLEncoding.EncodeToString([]byte(value))
+	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+	h := hmac.New(sha1.New, []byte(Secret))
+	fmt.Fprintf(h, "%s%s", vs, timestamp)
+	sig := fmt.Sprintf("%02x", h.Sum(nil))
+	cookie := strings.Join([]string{vs, timestamp, sig}, "|")
+	ctx.Output.Cookie(name, cookie, others...)
+}
+
+// XSRFToken creates a xsrf token string and returns.
+func (ctx *Context) XSRFToken(key string, expire int64) string {
+	if ctx._xsrfToken == "" {
+		token, ok := ctx.GetSecureCookie(key, "_xsrf")
+		if !ok {
+			token = string(utils.RandomCreateBytes(32))
+			ctx.SetSecureCookie(key, "_xsrf", token, expire)
+		}
+		ctx._xsrfToken = token
+	}
+	return ctx._xsrfToken
+}
+
+// CheckXSRFCookie checks xsrf token in this request is valid or not.
+// the token can provided in request header "X-Xsrftoken" and "X-CsrfToken"
+// or in form field value named as "_xsrf".
+func (ctx *Context) CheckXSRFCookie() bool {
+	token := ctx.Input.Query("_xsrf")
+	if token == "" {
+		token = ctx.Request.Header.Get("X-Xsrftoken")
+	}
+	if token == "" {
+		token = ctx.Request.Header.Get("X-Csrftoken")
+	}
+	if token == "" {
+		ctx.Abort(403, "'_xsrf' argument missing from POST")
+		return false
+	}
+	if ctx._xsrfToken != token {
+		ctx.Abort(403, "XSRF cookie does not match POST argument")
+		return false
+	}
+	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 {
+	http.ResponseWriter
+	Started bool
+	Status  int
+}
+
+func (r *Response) reset(rw http.ResponseWriter) {
+	r.ResponseWriter = rw
+	r.Status = 0
+	r.Started = false
+}
+
+// Write writes the data to the connection as part of an HTTP reply,
+// and sets `started` to true.
+// started means the response has sent out.
+func (r *Response) Write(p []byte) (int, error) {
+	r.Started = true
+	return r.ResponseWriter.Write(p)
+}
+
+// WriteHeader sends an HTTP response header with status code,
+// and sets `started` to true.
+func (r *Response) WriteHeader(code int) {
+	if r.Status > 0 {
+		//prevent multiple response.WriteHeader calls
+		return
+	}
+	r.Status = code
+	r.Started = true
+	r.ResponseWriter.WriteHeader(code)
+}
+
+// Hijack hijacker for http
+func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+	hj, ok := r.ResponseWriter.(http.Hijacker)
+	if !ok {
+		return nil, nil, errors.New("webserver doesn't support hijacking")
+	}
+	return hj.Hijack()
+}
+
+// Flush http.Flusher
+func (r *Response) Flush() {
+	if f, ok := r.ResponseWriter.(http.Flusher); ok {
+		f.Flush()
+	}
+}
+
+// CloseNotify http.CloseNotifier
+func (r *Response) CloseNotify() <-chan bool {
+	if cn, ok := r.ResponseWriter.(http.CloseNotifier); ok {
+		return cn.CloseNotify()
+	}
+	return nil
+}

+ 47 - 0
vendor/github.com/astaxie/beego/context/context_test.go

@@ -0,0 +1,47 @@
+// Copyright 2016 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 context
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"testing"
+)
+
+func TestXsrfReset_01(t *testing.T) {
+	r := &http.Request{}
+	c := NewContext()
+	c.Request = r
+	c.ResponseWriter = &Response{}
+	c.ResponseWriter.reset(httptest.NewRecorder())
+	c.Output.Reset(c)
+	c.Input.Reset(c)
+	c.XSRFToken("key", 16)
+	if c._xsrfToken == "" {
+		t.FailNow()
+	}
+	token := c._xsrfToken
+	c.Reset(&Response{ResponseWriter: httptest.NewRecorder()}, r)
+	if c._xsrfToken != "" {
+		t.FailNow()
+	}
+	c.XSRFToken("key", 16)
+	if c._xsrfToken == "" {
+		t.FailNow()
+	}
+	if token == c._xsrfToken {
+		t.FailNow()
+	}
+}

+ 650 - 0
vendor/github.com/astaxie/beego/context/input.go

@@ -0,0 +1,650 @@
+// 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 context
+
+import (
+	"bytes"
+	"errors"
+	"io"
+	"io/ioutil"
+	"net/url"
+	"reflect"
+	"regexp"
+	"strconv"
+	"strings"
+
+	"github.com/astaxie/beego/session"
+)
+
+// Regexes for checking the accept headers
+// TODO make sure these are correct
+var (
+	acceptsHTMLRegex = regexp.MustCompile(`(text/html|application/xhtml\+xml)(?:,|$)`)
+	acceptsXMLRegex  = regexp.MustCompile(`(application/xml|text/xml)(?:,|$)`)
+	acceptsJSONRegex = regexp.MustCompile(`(application/json)(?:,|$)`)
+	maxParam         = 50
+)
+
+// BeegoInput operates the http request header, data, cookie and body.
+// it also contains router params and current session.
+type BeegoInput struct {
+	Context       *Context
+	CruSession    session.Store
+	pnames        []string
+	pvalues       []string
+	data          map[interface{}]interface{} // store some values in this context when calling context in filter or controller.
+	RequestBody   []byte
+	RunMethod     string
+	RunController reflect.Type
+}
+
+// NewInput return BeegoInput generated by Context.
+func NewInput() *BeegoInput {
+	return &BeegoInput{
+		pnames:  make([]string, 0, maxParam),
+		pvalues: make([]string, 0, maxParam),
+		data:    make(map[interface{}]interface{}),
+	}
+}
+
+// Reset init the BeegoInput
+func (input *BeegoInput) Reset(ctx *Context) {
+	input.Context = ctx
+	input.CruSession = nil
+	input.pnames = input.pnames[:0]
+	input.pvalues = input.pvalues[:0]
+	input.data = nil
+	input.RequestBody = []byte{}
+}
+
+// Protocol returns request protocol name, such as HTTP/1.1 .
+func (input *BeegoInput) Protocol() string {
+	return input.Context.Request.Proto
+}
+
+// URI returns full request url with query string, fragment.
+func (input *BeegoInput) URI() string {
+	return input.Context.Request.RequestURI
+}
+
+// URL returns request url path (without query string, fragment).
+func (input *BeegoInput) URL() string {
+	return input.Context.Request.URL.Path
+}
+
+// Site returns base site url as scheme://domain type.
+func (input *BeegoInput) Site() string {
+	return input.Scheme() + "://" + input.Domain()
+}
+
+// Scheme returns request scheme as "http" or "https".
+func (input *BeegoInput) Scheme() string {
+	if scheme := input.Header("X-Forwarded-Proto"); scheme != "" {
+		return scheme
+	}
+	if input.Context.Request.URL.Scheme != "" {
+		return input.Context.Request.URL.Scheme
+	}
+	if input.Context.Request.TLS == nil {
+		return "http"
+	}
+	return "https"
+}
+
+// Domain returns host name.
+// Alias of Host method.
+func (input *BeegoInput) Domain() string {
+	return input.Host()
+}
+
+// Host returns host name.
+// if no host info in request, return localhost.
+func (input *BeegoInput) Host() string {
+	if input.Context.Request.Host != "" {
+		hostParts := strings.Split(input.Context.Request.Host, ":")
+		if len(hostParts) > 0 {
+			return hostParts[0]
+		}
+		return input.Context.Request.Host
+	}
+	return "localhost"
+}
+
+// Method returns http request method.
+func (input *BeegoInput) Method() string {
+	return input.Context.Request.Method
+}
+
+// Is returns boolean of this request is on given method, such as Is("POST").
+func (input *BeegoInput) Is(method string) bool {
+	return input.Method() == method
+}
+
+// IsGet Is this a GET method request?
+func (input *BeegoInput) IsGet() bool {
+	return input.Is("GET")
+}
+
+// IsPost Is this a POST method request?
+func (input *BeegoInput) IsPost() bool {
+	return input.Is("POST")
+}
+
+// IsHead Is this a Head method request?
+func (input *BeegoInput) IsHead() bool {
+	return input.Is("HEAD")
+}
+
+// IsOptions Is this a OPTIONS method request?
+func (input *BeegoInput) IsOptions() bool {
+	return input.Is("OPTIONS")
+}
+
+// IsPut Is this a PUT method request?
+func (input *BeegoInput) IsPut() bool {
+	return input.Is("PUT")
+}
+
+// IsDelete Is this a DELETE method request?
+func (input *BeegoInput) IsDelete() bool {
+	return input.Is("DELETE")
+}
+
+// IsPatch Is this a PATCH method request?
+func (input *BeegoInput) IsPatch() bool {
+	return input.Is("PATCH")
+}
+
+// IsAjax returns boolean of this request is generated by ajax.
+func (input *BeegoInput) IsAjax() bool {
+	return input.Header("X-Requested-With") == "XMLHttpRequest"
+}
+
+// IsSecure returns boolean of this request is in https.
+func (input *BeegoInput) IsSecure() bool {
+	return input.Scheme() == "https"
+}
+
+// IsWebsocket returns boolean of this request is in webSocket.
+func (input *BeegoInput) IsWebsocket() bool {
+	return input.Header("Upgrade") == "websocket"
+}
+
+// IsUpload returns boolean of whether file uploads in this request or not..
+func (input *BeegoInput) IsUpload() bool {
+	return strings.Contains(input.Header("Content-Type"), "multipart/form-data")
+}
+
+// AcceptsHTML Checks if request accepts html response
+func (input *BeegoInput) AcceptsHTML() bool {
+	return acceptsHTMLRegex.MatchString(input.Header("Accept"))
+}
+
+// AcceptsXML Checks if request accepts xml response
+func (input *BeegoInput) AcceptsXML() bool {
+	return acceptsXMLRegex.MatchString(input.Header("Accept"))
+}
+
+// AcceptsJSON Checks if request accepts json response
+func (input *BeegoInput) AcceptsJSON() bool {
+	return acceptsJSONRegex.MatchString(input.Header("Accept"))
+}
+
+// IP returns request client ip.
+// if in proxy, return first proxy id.
+// if error, return 127.0.0.1.
+func (input *BeegoInput) IP() string {
+	ips := input.Proxy()
+	if len(ips) > 0 && ips[0] != "" {
+		rip := strings.Split(ips[0], ":")
+		return rip[0]
+	}
+	ip := strings.Split(input.Context.Request.RemoteAddr, ":")
+	if len(ip) > 0 {
+		if ip[0] != "[" {
+			return ip[0]
+		}
+	}
+	return "127.0.0.1"
+}
+
+// Proxy returns proxy client ips slice.
+func (input *BeegoInput) Proxy() []string {
+	if ips := input.Header("X-Forwarded-For"); ips != "" {
+		return strings.Split(ips, ",")
+	}
+	return []string{}
+}
+
+// Referer returns http referer header.
+func (input *BeegoInput) Referer() string {
+	return input.Header("Referer")
+}
+
+// Refer returns http referer header.
+func (input *BeegoInput) Refer() string {
+	return input.Referer()
+}
+
+// SubDomains returns sub domain string.
+// if aa.bb.domain.com, returns aa.bb .
+func (input *BeegoInput) SubDomains() string {
+	parts := strings.Split(input.Host(), ".")
+	if len(parts) >= 3 {
+		return strings.Join(parts[:len(parts)-2], ".")
+	}
+	return ""
+}
+
+// Port returns request client port.
+// when error or empty, return 80.
+func (input *BeegoInput) Port() int {
+	parts := strings.Split(input.Context.Request.Host, ":")
+	if len(parts) == 2 {
+		port, _ := strconv.Atoi(parts[1])
+		return port
+	}
+	return 80
+}
+
+// UserAgent returns request client user agent string.
+func (input *BeegoInput) UserAgent() string {
+	return input.Header("User-Agent")
+}
+
+// ParamsLen return the length of the params
+func (input *BeegoInput) ParamsLen() int {
+	return len(input.pnames)
+}
+
+// Param returns router param by a given key.
+func (input *BeegoInput) Param(key string) string {
+	for i, v := range input.pnames {
+		if v == key && i <= len(input.pvalues) {
+			return input.pvalues[i]
+		}
+	}
+	return ""
+}
+
+// Params returns the map[key]value.
+func (input *BeegoInput) Params() map[string]string {
+	m := make(map[string]string)
+	for i, v := range input.pnames {
+		if i <= len(input.pvalues) {
+			m[v] = input.pvalues[i]
+		}
+	}
+	return m
+}
+
+// SetParam will set the param with key and value
+func (input *BeegoInput) SetParam(key, val string) {
+	// check if already exists
+	for i, v := range input.pnames {
+		if v == key && i <= len(input.pvalues) {
+			input.pvalues[i] = val
+			return
+		}
+	}
+	input.pvalues = append(input.pvalues, val)
+	input.pnames = append(input.pnames, key)
+}
+
+// ResetParams clears any of the input's Params
+// This function is used to clear parameters so they may be reset between filter
+// passes.
+func (input *BeegoInput) ResetParams() {
+	input.pnames = input.pnames[:0]
+	input.pvalues = input.pvalues[:0]
+}
+
+// Query returns input data item string by a given string.
+func (input *BeegoInput) Query(key string) string {
+	if val := input.Param(key); val != "" {
+		return val
+	}
+	if input.Context.Request.Form == nil {
+		input.Context.Request.ParseForm()
+	}
+	return input.Context.Request.Form.Get(key)
+}
+
+// Header returns request header item string by a given string.
+// if non-existed, return empty string.
+func (input *BeegoInput) Header(key string) string {
+	return input.Context.Request.Header.Get(key)
+}
+
+// Cookie returns request cookie item string by a given key.
+// if non-existed, return empty string.
+func (input *BeegoInput) Cookie(key string) string {
+	ck, err := input.Context.Request.Cookie(key)
+	if err != nil {
+		return ""
+	}
+	return ck.Value
+}
+
+// Session returns current session item value by a given key.
+// if non-existed, return nil.
+func (input *BeegoInput) Session(key interface{}) interface{} {
+	return input.CruSession.Get(key)
+}
+
+// CopyBody returns the raw request body data as bytes.
+func (input *BeegoInput) CopyBody(MaxMemory int64) []byte {
+	if input.Context.Request.Body == nil {
+		return []byte{}
+	}
+	safe := &io.LimitedReader{R: input.Context.Request.Body, N: MaxMemory}
+	requestbody, _ := ioutil.ReadAll(safe)
+	input.Context.Request.Body.Close()
+	bf := bytes.NewBuffer(requestbody)
+	input.Context.Request.Body = ioutil.NopCloser(bf)
+	input.RequestBody = requestbody
+	return requestbody
+}
+
+// Data return the implicit data in the input
+func (input *BeegoInput) Data() map[interface{}]interface{} {
+	if input.data == nil {
+		input.data = make(map[interface{}]interface{})
+	}
+	return input.data
+}
+
+// GetData returns the stored data in this context.
+func (input *BeegoInput) GetData(key interface{}) interface{} {
+	if v, ok := input.data[key]; ok {
+		return v
+	}
+	return nil
+}
+
+// SetData stores data with given key in this context.
+// This data are only available in this context.
+func (input *BeegoInput) SetData(key, val interface{}) {
+	if input.data == nil {
+		input.data = make(map[interface{}]interface{})
+	}
+	input.data[key] = val
+}
+
+// ParseFormOrMulitForm parseForm or parseMultiForm based on Content-type
+func (input *BeegoInput) ParseFormOrMulitForm(maxMemory int64) error {
+	// Parse the body depending on the content type.
+	if strings.Contains(input.Header("Content-Type"), "multipart/form-data") {
+		if err := input.Context.Request.ParseMultipartForm(maxMemory); err != nil {
+			return errors.New("Error parsing request body:" + err.Error())
+		}
+	} else if err := input.Context.Request.ParseForm(); err != nil {
+		return errors.New("Error parsing request body:" + err.Error())
+	}
+	return nil
+}
+
+// Bind data from request.Form[key] to dest
+// like /?id=123&isok=true&ft=1.2&ol[0]=1&ol[1]=2&ul[]=str&ul[]=array&user.Name=astaxie
+// var id int  beegoInput.Bind(&id, "id")  id ==123
+// var isok bool  beegoInput.Bind(&isok, "isok")  isok ==true
+// var ft float64  beegoInput.Bind(&ft, "ft")  ft ==1.2
+// ol := make([]int, 0, 2)  beegoInput.Bind(&ol, "ol")  ol ==[1 2]
+// ul := make([]string, 0, 2)  beegoInput.Bind(&ul, "ul")  ul ==[str array]
+// user struct{Name}  beegoInput.Bind(&user, "user")  user == {Name:"astaxie"}
+func (input *BeegoInput) Bind(dest interface{}, key string) error {
+	value := reflect.ValueOf(dest)
+	if value.Kind() != reflect.Ptr {
+		return errors.New("beego: non-pointer passed to Bind: " + key)
+	}
+	value = value.Elem()
+	if !value.CanSet() {
+		return errors.New("beego: non-settable variable passed to Bind: " + key)
+	}
+	typ := value.Type()
+	// Get real type if dest define with interface{}.
+	// e.g  var dest interface{} dest=1.0
+	if value.Kind() == reflect.Interface {
+		typ = value.Elem().Type()
+	}
+	rv := input.bind(key, typ)
+	if !rv.IsValid() {
+		return errors.New("beego: reflect value is empty")
+	}
+	value.Set(rv)
+	return nil
+}
+
+func (input *BeegoInput) bind(key string, typ reflect.Type) reflect.Value {
+	if input.Context.Request.Form == nil {
+		input.Context.Request.ParseForm()
+	}
+	rv := reflect.Zero(typ)
+	switch typ.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		val := input.Query(key)
+		if len(val) == 0 {
+			return rv
+		}
+		rv = input.bindInt(val, typ)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		val := input.Query(key)
+		if len(val) == 0 {
+			return rv
+		}
+		rv = input.bindUint(val, typ)
+	case reflect.Float32, reflect.Float64:
+		val := input.Query(key)
+		if len(val) == 0 {
+			return rv
+		}
+		rv = input.bindFloat(val, typ)
+	case reflect.String:
+		val := input.Query(key)
+		if len(val) == 0 {
+			return rv
+		}
+		rv = input.bindString(val, typ)
+	case reflect.Bool:
+		val := input.Query(key)
+		if len(val) == 0 {
+			return rv
+		}
+		rv = input.bindBool(val, typ)
+	case reflect.Slice:
+		rv = input.bindSlice(&input.Context.Request.Form, key, typ)
+	case reflect.Struct:
+		rv = input.bindStruct(&input.Context.Request.Form, key, typ)
+	case reflect.Ptr:
+		rv = input.bindPoint(key, typ)
+	case reflect.Map:
+		rv = input.bindMap(&input.Context.Request.Form, key, typ)
+	}
+	return rv
+}
+
+func (input *BeegoInput) bindValue(val string, typ reflect.Type) reflect.Value {
+	rv := reflect.Zero(typ)
+	switch typ.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		rv = input.bindInt(val, typ)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		rv = input.bindUint(val, typ)
+	case reflect.Float32, reflect.Float64:
+		rv = input.bindFloat(val, typ)
+	case reflect.String:
+		rv = input.bindString(val, typ)
+	case reflect.Bool:
+		rv = input.bindBool(val, typ)
+	case reflect.Slice:
+		rv = input.bindSlice(&url.Values{"": {val}}, "", typ)
+	case reflect.Struct:
+		rv = input.bindStruct(&url.Values{"": {val}}, "", typ)
+	case reflect.Ptr:
+		rv = input.bindPoint(val, typ)
+	case reflect.Map:
+		rv = input.bindMap(&url.Values{"": {val}}, "", typ)
+	}
+	return rv
+}
+
+func (input *BeegoInput) bindInt(val string, typ reflect.Type) reflect.Value {
+	intValue, err := strconv.ParseInt(val, 10, 64)
+	if err != nil {
+		return reflect.Zero(typ)
+	}
+	pValue := reflect.New(typ)
+	pValue.Elem().SetInt(intValue)
+	return pValue.Elem()
+}
+
+func (input *BeegoInput) bindUint(val string, typ reflect.Type) reflect.Value {
+	uintValue, err := strconv.ParseUint(val, 10, 64)
+	if err != nil {
+		return reflect.Zero(typ)
+	}
+	pValue := reflect.New(typ)
+	pValue.Elem().SetUint(uintValue)
+	return pValue.Elem()
+}
+
+func (input *BeegoInput) bindFloat(val string, typ reflect.Type) reflect.Value {
+	floatValue, err := strconv.ParseFloat(val, 64)
+	if err != nil {
+		return reflect.Zero(typ)
+	}
+	pValue := reflect.New(typ)
+	pValue.Elem().SetFloat(floatValue)
+	return pValue.Elem()
+}
+
+func (input *BeegoInput) bindString(val string, typ reflect.Type) reflect.Value {
+	return reflect.ValueOf(val)
+}
+
+func (input *BeegoInput) bindBool(val string, typ reflect.Type) reflect.Value {
+	val = strings.TrimSpace(strings.ToLower(val))
+	switch val {
+	case "true", "on", "1":
+		return reflect.ValueOf(true)
+	}
+	return reflect.ValueOf(false)
+}
+
+type sliceValue struct {
+	index int           // Index extracted from brackets.  If -1, no index was provided.
+	value reflect.Value // the bound value for this slice element.
+}
+
+func (input *BeegoInput) bindSlice(params *url.Values, key string, typ reflect.Type) reflect.Value {
+	maxIndex := -1
+	numNoIndex := 0
+	sliceValues := []sliceValue{}
+	for reqKey, vals := range *params {
+		if !strings.HasPrefix(reqKey, key+"[") {
+			continue
+		}
+		// Extract the index, and the index where a sub-key starts. (e.g. field[0].subkey)
+		index := -1
+		leftBracket, rightBracket := len(key), strings.Index(reqKey[len(key):], "]")+len(key)
+		if rightBracket > leftBracket+1 {
+			index, _ = strconv.Atoi(reqKey[leftBracket+1 : rightBracket])
+		}
+		subKeyIndex := rightBracket + 1
+
+		// Handle the indexed case.
+		if index > -1 {
+			if index > maxIndex {
+				maxIndex = index
+			}
+			sliceValues = append(sliceValues, sliceValue{
+				index: index,
+				value: input.bind(reqKey[:subKeyIndex], typ.Elem()),
+			})
+			continue
+		}
+
+		// It's an un-indexed element.  (e.g. element[])
+		numNoIndex += len(vals)
+		for _, val := range vals {
+			// Unindexed values can only be direct-bound.
+			sliceValues = append(sliceValues, sliceValue{
+				index: -1,
+				value: input.bindValue(val, typ.Elem()),
+			})
+		}
+	}
+	resultArray := reflect.MakeSlice(typ, maxIndex+1, maxIndex+1+numNoIndex)
+	for _, sv := range sliceValues {
+		if sv.index != -1 {
+			resultArray.Index(sv.index).Set(sv.value)
+		} else {
+			resultArray = reflect.Append(resultArray, sv.value)
+		}
+	}
+	return resultArray
+}
+
+func (input *BeegoInput) bindStruct(params *url.Values, key string, typ reflect.Type) reflect.Value {
+	result := reflect.New(typ).Elem()
+	fieldValues := make(map[string]reflect.Value)
+	for reqKey, val := range *params {
+		var fieldName string
+		if strings.HasPrefix(reqKey, key+".") {
+			fieldName = reqKey[len(key)+1:]
+		} else if strings.HasPrefix(reqKey, key+"[") && reqKey[len(reqKey)-1] == ']' {
+			fieldName = reqKey[len(key)+1 : len(reqKey)-1]
+		} else {
+			continue
+		}
+
+		if _, ok := fieldValues[fieldName]; !ok {
+			// Time to bind this field.  Get it and make sure we can set it.
+			fieldValue := result.FieldByName(fieldName)
+			if !fieldValue.IsValid() {
+				continue
+			}
+			if !fieldValue.CanSet() {
+				continue
+			}
+			boundVal := input.bindValue(val[0], fieldValue.Type())
+			fieldValue.Set(boundVal)
+			fieldValues[fieldName] = boundVal
+		}
+	}
+
+	return result
+}
+
+func (input *BeegoInput) bindPoint(key string, typ reflect.Type) reflect.Value {
+	return input.bind(key, typ.Elem()).Addr()
+}
+
+func (input *BeegoInput) bindMap(params *url.Values, key string, typ reflect.Type) reflect.Value {
+	var (
+		result    = reflect.MakeMap(typ)
+		keyType   = typ.Key()
+		valueType = typ.Elem()
+	)
+	for paramName, values := range *params {
+		if !strings.HasPrefix(paramName, key+"[") || paramName[len(paramName)-1] != ']' {
+			continue
+		}
+
+		key := paramName[len(key)+1 : len(paramName)-1]
+		result.SetMapIndex(input.bindValue(key, keyType), input.bindValue(values[0], valueType))
+	}
+	return result
+}

+ 207 - 0
vendor/github.com/astaxie/beego/context/input_test.go

@@ -0,0 +1,207 @@
+// 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 context
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"reflect"
+	"testing"
+)
+
+func TestBind(t *testing.T) {
+	type testItem struct {
+		field string
+		empty interface{}
+		want  interface{}
+	}
+	type Human struct {
+		ID   int
+		Nick string
+		Pwd  string
+		Ms   bool
+	}
+
+	cases := []struct {
+		request string
+		valueGp []testItem
+	}{
+		{"/?p=str", []testItem{{"p", interface{}(""), interface{}("str")}}},
+
+		{"/?p=", []testItem{{"p", "", ""}}},
+		{"/?p=str", []testItem{{"p", "", "str"}}},
+
+		{"/?p=123", []testItem{{"p", 0, 123}}},
+		{"/?p=123", []testItem{{"p", uint(0), uint(123)}}},
+
+		{"/?p=1.0", []testItem{{"p", 0.0, 1.0}}},
+		{"/?p=1", []testItem{{"p", false, true}}},
+
+		{"/?p=true", []testItem{{"p", false, true}}},
+		{"/?p=ON", []testItem{{"p", false, true}}},
+		{"/?p=on", []testItem{{"p", false, true}}},
+		{"/?p=1", []testItem{{"p", false, true}}},
+		{"/?p=2", []testItem{{"p", false, false}}},
+		{"/?p=false", []testItem{{"p", false, false}}},
+
+		{"/?p[a]=1&p[b]=2&p[c]=3", []testItem{{"p", map[string]int{}, map[string]int{"a": 1, "b": 2, "c": 3}}}},
+		{"/?p[a]=v1&p[b]=v2&p[c]=v3", []testItem{{"p", map[string]string{}, map[string]string{"a": "v1", "b": "v2", "c": "v3"}}}},
+
+		{"/?p[]=8&p[]=9&p[]=10", []testItem{{"p", []int{}, []int{8, 9, 10}}}},
+		{"/?p[0]=8&p[1]=9&p[2]=10", []testItem{{"p", []int{}, []int{8, 9, 10}}}},
+		{"/?p[0]=8&p[1]=9&p[2]=10&p[5]=14", []testItem{{"p", []int{}, []int{8, 9, 10, 0, 0, 14}}}},
+		{"/?p[0]=8.0&p[1]=9.0&p[2]=10.0", []testItem{{"p", []float64{}, []float64{8.0, 9.0, 10.0}}}},
+
+		{"/?p[]=10&p[]=9&p[]=8", []testItem{{"p", []string{}, []string{"10", "9", "8"}}}},
+		{"/?p[0]=8&p[1]=9&p[2]=10", []testItem{{"p", []string{}, []string{"8", "9", "10"}}}},
+
+		{"/?p[0]=true&p[1]=false&p[2]=true&p[5]=1&p[6]=ON&p[7]=other", []testItem{{"p", []bool{}, []bool{true, false, true, false, false, true, true, false}}}},
+
+		{"/?human.Nick=astaxie", []testItem{{"human", Human{}, Human{Nick: "astaxie"}}}},
+		{"/?human.ID=888&human.Nick=astaxie&human.Ms=true&human[Pwd]=pass", []testItem{{"human", Human{}, Human{ID: 888, Nick: "astaxie", Ms: true, Pwd: "pass"}}}},
+		{"/?human[0].ID=888&human[0].Nick=astaxie&human[0].Ms=true&human[0][Pwd]=pass01&human[1].ID=999&human[1].Nick=ysqi&human[1].Ms=On&human[1].Pwd=pass02",
+			[]testItem{{"human", []Human{}, []Human{
+				{ID: 888, Nick: "astaxie", Ms: true, Pwd: "pass01"},
+				{ID: 999, Nick: "ysqi", Ms: true, Pwd: "pass02"},
+			}}}},
+
+		{
+			"/?id=123&isok=true&ft=1.2&ol[0]=1&ol[1]=2&ul[]=str&ul[]=array&human.Nick=astaxie",
+			[]testItem{
+				{"id", 0, 123},
+				{"isok", false, true},
+				{"ft", 0.0, 1.2},
+				{"ol", []int{}, []int{1, 2}},
+				{"ul", []string{}, []string{"str", "array"}},
+				{"human", Human{}, Human{Nick: "astaxie"}},
+			},
+		},
+	}
+	for _, c := range cases {
+		r, _ := http.NewRequest("GET", c.request, nil)
+		beegoInput := NewInput()
+		beegoInput.Context = NewContext()
+		beegoInput.Context.Reset(httptest.NewRecorder(), r)
+
+		for _, item := range c.valueGp {
+			got := item.empty
+			err := beegoInput.Bind(&got, item.field)
+			if err != nil {
+				t.Fatal(err)
+			}
+			if !reflect.DeepEqual(got, item.want) {
+				t.Fatalf("Bind %q error,should be:\n%#v \ngot:\n%#v", item.field, item.want, got)
+			}
+		}
+
+	}
+}
+
+func TestSubDomain(t *testing.T) {
+	r, _ := http.NewRequest("GET", "http://www.example.com/?id=123&isok=true&ft=1.2&ol[0]=1&ol[1]=2&ul[]=str&ul[]=array&user.Name=astaxie", nil)
+	beegoInput := NewInput()
+	beegoInput.Context = NewContext()
+	beegoInput.Context.Reset(httptest.NewRecorder(), r)
+
+	subdomain := beegoInput.SubDomains()
+	if subdomain != "www" {
+		t.Fatal("Subdomain parse error, got" + subdomain)
+	}
+
+	r, _ = http.NewRequest("GET", "http://localhost/", nil)
+	beegoInput.Context.Request = r
+	if beegoInput.SubDomains() != "" {
+		t.Fatal("Subdomain parse error, should be empty, got " + beegoInput.SubDomains())
+	}
+
+	r, _ = http.NewRequest("GET", "http://aa.bb.example.com/", nil)
+	beegoInput.Context.Request = r
+	if beegoInput.SubDomains() != "aa.bb" {
+		t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
+	}
+
+	/* TODO Fix this
+	r, _ = http.NewRequest("GET", "http://127.0.0.1/", nil)
+	beegoInput.Context.Request = r
+	if beegoInput.SubDomains() != "" {
+		t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
+	}
+	*/
+
+	r, _ = http.NewRequest("GET", "http://example.com/", nil)
+	beegoInput.Context.Request = r
+	if beegoInput.SubDomains() != "" {
+		t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
+	}
+
+	r, _ = http.NewRequest("GET", "http://aa.bb.cc.dd.example.com/", nil)
+	beegoInput.Context.Request = r
+	if beegoInput.SubDomains() != "aa.bb.cc.dd" {
+		t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
+	}
+}
+
+func TestParams(t *testing.T) {
+	inp := NewInput()
+
+	inp.SetParam("p1", "val1_ver1")
+	inp.SetParam("p2", "val2_ver1")
+	inp.SetParam("p3", "val3_ver1")
+	if l := inp.ParamsLen(); l != 3 {
+		t.Fatalf("Input.ParamsLen wrong value: %d, expected %d", l, 3)
+	}
+
+	if val := inp.Param("p1"); val != "val1_ver1" {
+		t.Fatalf("Input.Param wrong value: %s, expected %s", val, "val1_ver1")
+	}
+	if val := inp.Param("p3"); val != "val3_ver1" {
+		t.Fatalf("Input.Param wrong value: %s, expected %s", val, "val3_ver1")
+	}
+	vals := inp.Params()
+	expected := map[string]string{
+		"p1": "val1_ver1",
+		"p2": "val2_ver1",
+		"p3": "val3_ver1",
+	}
+	if !reflect.DeepEqual(vals, expected) {
+		t.Fatalf("Input.Params wrong value: %s, expected %s", vals, expected)
+	}
+
+	// overwriting existing params
+	inp.SetParam("p1", "val1_ver2")
+	inp.SetParam("p2", "val2_ver2")
+	expected = map[string]string{
+		"p1": "val1_ver2",
+		"p2": "val2_ver2",
+		"p3": "val3_ver1",
+	}
+	vals = inp.Params()
+	if !reflect.DeepEqual(vals, expected) {
+		t.Fatalf("Input.Params wrong value: %s, expected %s", vals, expected)
+	}
+
+	if l := inp.ParamsLen(); l != 3 {
+		t.Fatalf("Input.ParamsLen wrong value: %d, expected %d", l, 3)
+	}
+
+	if val := inp.Param("p1"); val != "val1_ver2" {
+		t.Fatalf("Input.Param wrong value: %s, expected %s", val, "val1_ver2")
+	}
+
+	if val := inp.Param("p2"); val != "val2_ver2" {
+		t.Fatalf("Input.Param wrong value: %s, expected %s", val, "val1_ver2")
+	}
+
+}

+ 362 - 0
vendor/github.com/astaxie/beego/context/output.go

@@ -0,0 +1,362 @@
+// 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 context
+
+import (
+	"bytes"
+	"encoding/json"
+	"encoding/xml"
+	"errors"
+	"fmt"
+	"html/template"
+	"io"
+	"mime"
+	"net/http"
+	"net/url"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// BeegoOutput does work for sending response header.
+type BeegoOutput struct {
+	Context    *Context
+	Status     int
+	EnableGzip bool
+}
+
+// NewOutput returns new BeegoOutput.
+// it contains nothing now.
+func NewOutput() *BeegoOutput {
+	return &BeegoOutput{}
+}
+
+// Reset init BeegoOutput
+func (output *BeegoOutput) Reset(ctx *Context) {
+	output.Context = ctx
+	output.Status = 0
+}
+
+// Header sets response header item string via given key.
+func (output *BeegoOutput) Header(key, val string) {
+	output.Context.ResponseWriter.Header().Set(key, val)
+}
+
+// Body sets response body content.
+// if EnableGzip, compress content string.
+// it sends out response body directly.
+func (output *BeegoOutput) Body(content []byte) error {
+	var encoding string
+	var buf = &bytes.Buffer{}
+	if output.EnableGzip {
+		encoding = ParseEncoding(output.Context.Request)
+	}
+	if b, n, _ := WriteBody(encoding, buf, content); b {
+		output.Header("Content-Encoding", n)
+		output.Header("Content-Length", strconv.Itoa(buf.Len()))
+	} else {
+		output.Header("Content-Length", strconv.Itoa(len(content)))
+	}
+	// Write status code if it has been set manually
+	// Set it to 0 afterwards to prevent "multiple response.WriteHeader calls"
+	if output.Status != 0 {
+		output.Context.ResponseWriter.WriteHeader(output.Status)
+		output.Status = 0
+	} else {
+		output.Context.ResponseWriter.Started = true
+	}
+	io.Copy(output.Context.ResponseWriter, buf)
+	return nil
+}
+
+// Cookie sets cookie value via given key.
+// others are ordered as cookie's max age time, path,domain, secure and httponly.
+func (output *BeegoOutput) Cookie(name string, value string, others ...interface{}) {
+	var b bytes.Buffer
+	fmt.Fprintf(&b, "%s=%s", sanitizeName(name), sanitizeValue(value))
+
+	//fix cookie not work in IE
+	if len(others) > 0 {
+		var maxAge int64
+
+		switch v := others[0].(type) {
+		case int:
+			maxAge = int64(v)
+		case int32:
+			maxAge = int64(v)
+		case int64:
+			maxAge = v
+		}
+
+		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:
+			fmt.Fprintf(&b, "; Max-Age=0")
+		}
+	}
+
+	// the settings below
+	// Path, Domain, Secure, HttpOnly
+	// can use nil skip set
+
+	// default "/"
+	if len(others) > 1 {
+		if v, ok := others[1].(string); ok && len(v) > 0 {
+			fmt.Fprintf(&b, "; Path=%s", sanitizeValue(v))
+		}
+	} else {
+		fmt.Fprintf(&b, "; Path=%s", "/")
+	}
+
+	// default empty
+	if len(others) > 2 {
+		if v, ok := others[2].(string); ok && len(v) > 0 {
+			fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(v))
+		}
+	}
+
+	// default empty
+	if len(others) > 3 {
+		var secure bool
+		switch v := others[3].(type) {
+		case bool:
+			secure = v
+		default:
+			if others[3] != nil {
+				secure = true
+			}
+		}
+		if secure {
+			fmt.Fprintf(&b, "; Secure")
+		}
+	}
+
+	// default false. for session cookie default true
+	if len(others) > 4 {
+		if v, ok := others[4].(bool); ok && v {
+			fmt.Fprintf(&b, "; HttpOnly")
+		}
+	}
+
+	output.Context.ResponseWriter.Header().Add("Set-Cookie", b.String())
+}
+
+var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-")
+
+func sanitizeName(n string) string {
+	return cookieNameSanitizer.Replace(n)
+}
+
+var cookieValueSanitizer = strings.NewReplacer("\n", " ", "\r", " ", ";", " ")
+
+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 {
+	output.Header("Content-Type", "application/json; charset=utf-8")
+	var content []byte
+	var err error
+	if hasIndent {
+		content, err = json.MarshalIndent(data, "", "  ")
+	} else {
+		content, err = json.Marshal(data)
+	}
+	if err != nil {
+		http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
+		return err
+	}
+	if coding {
+		content = []byte(stringsToJSON(string(content)))
+	}
+	return output.Body(content)
+}
+
+// JSONP writes jsonp to response body.
+func (output *BeegoOutput) JSONP(data interface{}, hasIndent bool) error {
+	output.Header("Content-Type", "application/javascript; charset=utf-8")
+	var content []byte
+	var err error
+	if hasIndent {
+		content, err = json.MarshalIndent(data, "", "  ")
+	} else {
+		content, err = json.Marshal(data)
+	}
+	if err != nil {
+		http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
+		return err
+	}
+	callback := output.Context.Input.Query("callback")
+	if callback == "" {
+		return errors.New(`"callback" parameter required`)
+	}
+	callback = template.JSEscapeString(callback)
+	callbackContent := bytes.NewBufferString(" if(window." + callback + ")" + callback)
+	callbackContent.WriteString("(")
+	callbackContent.Write(content)
+	callbackContent.WriteString(");\r\n")
+	return output.Body(callbackContent.Bytes())
+}
+
+// XML writes xml string to response body.
+func (output *BeegoOutput) XML(data interface{}, hasIndent bool) error {
+	output.Header("Content-Type", "application/xml; charset=utf-8")
+	var content []byte
+	var err error
+	if hasIndent {
+		content, err = xml.MarshalIndent(data, "", "  ")
+	} else {
+		content, err = xml.Marshal(data)
+	}
+	if err != nil {
+		http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
+		return err
+	}
+	return output.Body(content)
+}
+
+// Download forces response for download file.
+// it prepares the download response header automatically.
+func (output *BeegoOutput) Download(file string, filename ...string) {
+	// check get file error, file not found or other error.
+	if _, err := os.Stat(file); err != nil {
+		http.ServeFile(output.Context.ResponseWriter, output.Context.Request, file)
+		return
+	}
+
+	var fName string
+	if len(filename) > 0 && filename[0] != "" {
+		fName = filename[0]
+	} else {
+		fName = filepath.Base(file)
+	}
+	output.Header("Content-Disposition", "attachment; filename="+url.QueryEscape(fName))
+	output.Header("Content-Description", "File Transfer")
+	output.Header("Content-Type", "application/octet-stream")
+	output.Header("Content-Transfer-Encoding", "binary")
+	output.Header("Expires", "0")
+	output.Header("Cache-Control", "must-revalidate")
+	output.Header("Pragma", "public")
+	http.ServeFile(output.Context.ResponseWriter, output.Context.Request, file)
+}
+
+// ContentType sets the content type from ext string.
+// MIME type is given in mime package.
+func (output *BeegoOutput) ContentType(ext string) {
+	if !strings.HasPrefix(ext, ".") {
+		ext = "." + ext
+	}
+	ctype := mime.TypeByExtension(ext)
+	if ctype != "" {
+		output.Header("Content-Type", ctype)
+	}
+}
+
+// SetStatus sets response status code.
+// It writes response header directly.
+func (output *BeegoOutput) SetStatus(status int) {
+	output.Status = status
+}
+
+// IsCachable returns boolean of this request is cached.
+// HTTP 304 means cached.
+func (output *BeegoOutput) IsCachable() bool {
+	return output.Status >= 200 && output.Status < 300 || output.Status == 304
+}
+
+// IsEmpty returns boolean of this request is empty.
+// HTTP 201,204 and 304 means empty.
+func (output *BeegoOutput) IsEmpty() bool {
+	return output.Status == 201 || output.Status == 204 || output.Status == 304
+}
+
+// IsOk returns boolean of this request runs well.
+// HTTP 200 means ok.
+func (output *BeegoOutput) IsOk() bool {
+	return output.Status == 200
+}
+
+// IsSuccessful returns boolean of this request runs successfully.
+// HTTP 2xx means ok.
+func (output *BeegoOutput) IsSuccessful() bool {
+	return output.Status >= 200 && output.Status < 300
+}
+
+// IsRedirect returns boolean of this request is redirection header.
+// HTTP 301,302,307 means redirection.
+func (output *BeegoOutput) IsRedirect() bool {
+	return output.Status == 301 || output.Status == 302 || output.Status == 303 || output.Status == 307
+}
+
+// IsForbidden returns boolean of this request is forbidden.
+// HTTP 403 means forbidden.
+func (output *BeegoOutput) IsForbidden() bool {
+	return output.Status == 403
+}
+
+// IsNotFound returns boolean of this request is not found.
+// HTTP 404 means forbidden.
+func (output *BeegoOutput) IsNotFound() bool {
+	return output.Status == 404
+}
+
+// IsClientError returns boolean of this request client sends error data.
+// HTTP 4xx means forbidden.
+func (output *BeegoOutput) IsClientError() bool {
+	return output.Status >= 400 && output.Status < 500
+}
+
+// IsServerError returns boolean of this server handler errors.
+// HTTP 5xx means server internal error.
+func (output *BeegoOutput) IsServerError() bool {
+	return output.Status >= 500 && output.Status < 600
+}
+
+func stringsToJSON(str string) string {
+	var jsons bytes.Buffer
+	for _, r := range str {
+		rint := int(r)
+		if rint < 128 {
+			jsons.WriteRune(r)
+		} else {
+			jsons.WriteString("\\u")
+			jsons.WriteString(strconv.FormatInt(int64(rint), 16))
+		}
+	}
+	return jsons.String()
+}
+
+// Session sets session item value with given key.
+func (output *BeegoOutput) Session(name interface{}, value interface{}) {
+	output.Context.Input.CruSession.Set(name, value)
+}

+ 84 - 0
vendor/github.com/astaxie/beego/context/param/parsers_test.go

@@ -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)
+	}
+}

+ 654 - 0
vendor/github.com/astaxie/beego/controller.go

@@ -0,0 +1,654 @@
+// 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 beego
+
+import (
+	"bytes"
+	"errors"
+	"html/template"
+	"io"
+	"mime/multipart"
+	"net/http"
+	"net/url"
+	"os"
+	"reflect"
+	"strconv"
+	"strings"
+
+	"github.com/astaxie/beego/context"
+	"github.com/astaxie/beego/context/param"
+	"github.com/astaxie/beego/session"
+)
+
+//commonly used mime-types
+const (
+	applicationJSON = "application/json"
+	applicationXML  = "application/xml"
+	textXML         = "text/xml"
+)
+
+var (
+	// ErrAbort custom error when user stop request handler manually.
+	ErrAbort = errors.New("User stop run")
+	// GlobalControllerRouter store comments with controller. pkgpath+controller:comments
+	GlobalControllerRouter = make(map[string][]ControllerComments)
+)
+
+// ControllerComments store the comment for the controller method
+type ControllerComments struct {
+	Method           string
+	Router           string
+	AllowHTTPMethods []string
+	Params           []map[string]string
+	MethodParams     []*param.MethodParam
+}
+
+// Controller defines some basic http request handler operations, such as
+// http context, template and view, session and xsrf.
+type Controller struct {
+	// context data
+	Ctx  *context.Context
+	Data map[interface{}]interface{}
+
+	// route controller info
+	controllerName string
+	actionName     string
+	methodMapping  map[string]func() //method:routertree
+	gotofunc       string
+	AppController  interface{}
+
+	// template data
+	TplName        string
+	ViewPath       string
+	Layout         string
+	LayoutSections map[string]string // the key is the section name and the value is the template name
+	TplPrefix      string
+	TplExt         string
+	EnableRender   bool
+
+	// xsrf data
+	_xsrfToken string
+	XSRFExpire int
+	EnableXSRF bool
+
+	// session
+	CruSession session.Store
+}
+
+// ControllerInterface is an interface to uniform all controller handler.
+type ControllerInterface interface {
+	Init(ct *context.Context, controllerName, actionName string, app interface{})
+	Prepare()
+	Get()
+	Post()
+	Delete()
+	Put()
+	Head()
+	Patch()
+	Options()
+	Finish()
+	Render() error
+	XSRFToken() string
+	CheckXSRFCookie() bool
+	HandlerFunc(fn string) bool
+	URLMapping()
+}
+
+// Init generates default values of controller operations.
+func (c *Controller) Init(ctx *context.Context, controllerName, actionName string, app interface{}) {
+	c.Layout = ""
+	c.TplName = ""
+	c.controllerName = controllerName
+	c.actionName = actionName
+	c.Ctx = ctx
+	c.TplExt = "tpl"
+	c.AppController = app
+	c.EnableRender = true
+	c.EnableXSRF = true
+	c.Data = ctx.Input.Data()
+	c.methodMapping = make(map[string]func())
+}
+
+// Prepare runs after Init before request function execution.
+func (c *Controller) Prepare() {}
+
+// Finish runs after request function execution.
+func (c *Controller) Finish() {}
+
+// Get adds a request function to handle GET request.
+func (c *Controller) Get() {
+	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
+}
+
+// Post adds a request function to handle POST request.
+func (c *Controller) Post() {
+	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
+}
+
+// Delete adds a request function to handle DELETE request.
+func (c *Controller) Delete() {
+	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
+}
+
+// Put adds a request function to handle PUT request.
+func (c *Controller) Put() {
+	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
+}
+
+// Head adds a request function to handle HEAD request.
+func (c *Controller) Head() {
+	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
+}
+
+// Patch adds a request function to handle PATCH request.
+func (c *Controller) Patch() {
+	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
+}
+
+// Options adds a request function to handle OPTIONS request.
+func (c *Controller) Options() {
+	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
+}
+
+// HandlerFunc call function with the name
+func (c *Controller) HandlerFunc(fnname string) bool {
+	if v, ok := c.methodMapping[fnname]; ok {
+		v()
+		return true
+	}
+	return false
+}
+
+// URLMapping register the internal Controller router.
+func (c *Controller) URLMapping() {}
+
+// Mapping the method to function
+func (c *Controller) Mapping(method string, fn func()) {
+	c.methodMapping[method] = fn
+}
+
+// Render sends the response with rendered template bytes as text/html type.
+func (c *Controller) Render() error {
+	if !c.EnableRender {
+		return nil
+	}
+	rb, err := c.RenderBytes()
+	if err != nil {
+		return err
+	}
+
+	if c.Ctx.ResponseWriter.Header().Get("Content-Type") == "" {
+		c.Ctx.Output.Header("Content-Type", "text/html; charset=utf-8")
+	}
+
+	return c.Ctx.Output.Body(rb)
+}
+
+// RenderString returns the rendered template string. Do not send out response.
+func (c *Controller) RenderString() (string, error) {
+	b, e := c.RenderBytes()
+	return string(b), e
+}
+
+// RenderBytes returns the bytes of rendered template string. Do not send out response.
+func (c *Controller) RenderBytes() ([]byte, error) {
+	buf, err := c.renderTemplate()
+	//if the controller has set layout, then first get the tplName's content set the content to the layout
+	if err == nil && c.Layout != "" {
+		c.Data["LayoutContent"] = template.HTML(buf.String())
+
+		if c.LayoutSections != nil {
+			for sectionName, sectionTpl := range c.LayoutSections {
+				if sectionTpl == "" {
+					c.Data[sectionName] = ""
+					continue
+				}
+				buf.Reset()
+				err = ExecuteViewPathTemplate(&buf, sectionTpl, c.viewPath(), c.Data)
+				if err != nil {
+					return nil, err
+				}
+				c.Data[sectionName] = template.HTML(buf.String())
+			}
+		}
+
+		buf.Reset()
+		ExecuteViewPathTemplate(&buf, c.Layout, c.viewPath(), c.Data)
+	}
+	return buf.Bytes(), err
+}
+
+func (c *Controller) renderTemplate() (bytes.Buffer, error) {
+	var buf bytes.Buffer
+	if c.TplName == "" {
+		c.TplName = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt
+	}
+	if c.TplPrefix != "" {
+		c.TplName = c.TplPrefix + c.TplName
+	}
+	if BConfig.RunMode == DEV {
+		buildFiles := []string{c.TplName}
+		if c.Layout != "" {
+			buildFiles = append(buildFiles, c.Layout)
+			if c.LayoutSections != nil {
+				for _, sectionTpl := range c.LayoutSections {
+					if sectionTpl == "" {
+						continue
+					}
+					buildFiles = append(buildFiles, sectionTpl)
+				}
+			}
+		}
+		BuildTemplate(c.viewPath(), buildFiles...)
+	}
+	return buf, ExecuteViewPathTemplate(&buf, c.TplName, c.viewPath(), c.Data)
+}
+
+func (c *Controller) viewPath() string {
+	if c.ViewPath == "" {
+		return BConfig.WebConfig.ViewsPath
+	}
+	return c.ViewPath
+}
+
+// Redirect sends the redirection response to url with status code.
+func (c *Controller) Redirect(url string, code int) {
+	c.Ctx.Redirect(code, url)
+}
+
+// Abort stops controller handler and show the error data if code is defined in ErrorMap or code string.
+func (c *Controller) Abort(code string) {
+	status, err := strconv.Atoi(code)
+	if err != nil {
+		status = 200
+	}
+	c.CustomAbort(status, code)
+}
+
+// CustomAbort stops controller handler and show the error data, it's similar Aborts, but support status code and body.
+func (c *Controller) CustomAbort(status int, body string) {
+	// first panic from ErrorMaps, it is user defined error functions.
+	if _, ok := ErrorMaps[body]; ok {
+		c.Ctx.Output.Status = status
+		panic(body)
+	}
+	// last panic user string
+	c.Ctx.ResponseWriter.WriteHeader(status)
+	c.Ctx.ResponseWriter.Write([]byte(body))
+	panic(ErrAbort)
+}
+
+// StopRun makes panic of USERSTOPRUN error and go to recover function if defined.
+func (c *Controller) StopRun() {
+	panic(ErrAbort)
+}
+
+// URLFor does another controller handler in this request function.
+// it goes to this controller method if endpoint is not clear.
+func (c *Controller) URLFor(endpoint string, values ...interface{}) string {
+	if len(endpoint) == 0 {
+		return ""
+	}
+	if endpoint[0] == '.' {
+		return URLFor(reflect.Indirect(reflect.ValueOf(c.AppController)).Type().Name()+endpoint, values...)
+	}
+	return URLFor(endpoint, values...)
+}
+
+// ServeJSON sends a json response with encoding charset.
+func (c *Controller) ServeJSON(encoding ...bool) {
+	var (
+		hasIndent   = true
+		hasEncoding = false
+	)
+	if BConfig.RunMode == PROD {
+		hasIndent = false
+	}
+	if len(encoding) > 0 && encoding[0] {
+		hasEncoding = true
+	}
+	c.Ctx.Output.JSON(c.Data["json"], hasIndent, hasEncoding)
+}
+
+// ServeJSONP sends a jsonp response.
+func (c *Controller) ServeJSONP() {
+	hasIndent := true
+	if BConfig.RunMode == PROD {
+		hasIndent = false
+	}
+	c.Ctx.Output.JSONP(c.Data["jsonp"], hasIndent)
+}
+
+// ServeXML sends xml response.
+func (c *Controller) ServeXML() {
+	hasIndent := true
+	if BConfig.RunMode == PROD {
+		hasIndent = false
+	}
+	c.Ctx.Output.XML(c.Data["xml"], hasIndent)
+}
+
+// ServeFormatted serve Xml OR Json, depending on the value of the Accept header
+func (c *Controller) ServeFormatted() {
+	accept := c.Ctx.Input.Header("Accept")
+	switch accept {
+	case applicationJSON:
+		c.ServeJSON()
+	case applicationXML, textXML:
+		c.ServeXML()
+	default:
+		c.ServeJSON()
+	}
+}
+
+// Input returns the input data map from POST or PUT request body and query string.
+func (c *Controller) Input() url.Values {
+	if c.Ctx.Request.Form == nil {
+		c.Ctx.Request.ParseForm()
+	}
+	return c.Ctx.Request.Form
+}
+
+// ParseForm maps input data map to obj struct.
+func (c *Controller) ParseForm(obj interface{}) error {
+	return ParseForm(c.Input(), obj)
+}
+
+// GetString returns the input value by key string or the default value while it's present and input is blank
+func (c *Controller) GetString(key string, def ...string) string {
+	if v := c.Ctx.Input.Query(key); v != "" {
+		return v
+	}
+	if len(def) > 0 {
+		return def[0]
+	}
+	return ""
+}
+
+// GetStrings returns the input string slice by key string or the default value while it's present and input is blank
+// it's designed for multi-value input field such as checkbox(input[type=checkbox]), multi-selection.
+func (c *Controller) GetStrings(key string, def ...[]string) []string {
+	var defv []string
+	if len(def) > 0 {
+		defv = def[0]
+	}
+
+	if f := c.Input(); f == nil {
+		return defv
+	} else if vs := f[key]; len(vs) > 0 {
+		return vs
+	}
+
+	return defv
+}
+
+// GetInt returns input as an int or the default value while it's present and input is blank
+func (c *Controller) GetInt(key string, def ...int) (int, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	return strconv.Atoi(strv)
+}
+
+// GetInt8 return input as an int8 or the default value while it's present and input is blank
+func (c *Controller) GetInt8(key string, def ...int8) (int8, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	i64, err := strconv.ParseInt(strv, 10, 8)
+	return int8(i64), err
+}
+
+// GetUint8 return input as an uint8 or the default value while it's present and input is blank
+func (c *Controller) GetUint8(key string, def ...uint8) (uint8, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	u64, err := strconv.ParseUint(strv, 10, 8)
+	return uint8(u64), err
+}
+
+// GetInt16 returns input as an int16 or the default value while it's present and input is blank
+func (c *Controller) GetInt16(key string, def ...int16) (int16, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	i64, err := strconv.ParseInt(strv, 10, 16)
+	return int16(i64), err
+}
+
+// GetUint16 returns input as an uint16 or the default value while it's present and input is blank
+func (c *Controller) GetUint16(key string, def ...uint16) (uint16, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	u64, err := strconv.ParseUint(strv, 10, 16)
+	return uint16(u64), err
+}
+
+// GetInt32 returns input as an int32 or the default value while it's present and input is blank
+func (c *Controller) GetInt32(key string, def ...int32) (int32, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	i64, err := strconv.ParseInt(strv, 10, 32)
+	return int32(i64), err
+}
+
+// GetUint32 returns input as an uint32 or the default value while it's present and input is blank
+func (c *Controller) GetUint32(key string, def ...uint32) (uint32, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	u64, err := strconv.ParseUint(strv, 10, 32)
+	return uint32(u64), err
+}
+
+// GetInt64 returns input value as int64 or the default value while it's present and input is blank.
+func (c *Controller) GetInt64(key string, def ...int64) (int64, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	return strconv.ParseInt(strv, 10, 64)
+}
+
+// GetUint64 returns input value as uint64 or the default value while it's present and input is blank.
+func (c *Controller) GetUint64(key string, def ...uint64) (uint64, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	return strconv.ParseUint(strv, 10, 64)
+}
+
+// GetBool returns input value as bool or the default value while it's present and input is blank.
+func (c *Controller) GetBool(key string, def ...bool) (bool, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	return strconv.ParseBool(strv)
+}
+
+// GetFloat returns input value as float64 or the default value while it's present and input is blank.
+func (c *Controller) GetFloat(key string, def ...float64) (float64, error) {
+	strv := c.Ctx.Input.Query(key)
+	if len(strv) == 0 && len(def) > 0 {
+		return def[0], nil
+	}
+	return strconv.ParseFloat(strv, 64)
+}
+
+// GetFile returns the file data in file upload field named as key.
+// it returns the first one of multi-uploaded files.
+func (c *Controller) GetFile(key string) (multipart.File, *multipart.FileHeader, error) {
+	return c.Ctx.Request.FormFile(key)
+}
+
+// GetFiles return multi-upload files
+// files, err:=c.GetFiles("myfiles")
+//	if err != nil {
+//		http.Error(w, err.Error(), http.StatusNoContent)
+//		return
+//	}
+// for i, _ := range files {
+//	//for each fileheader, get a handle to the actual file
+//	file, err := files[i].Open()
+//	defer file.Close()
+//	if err != nil {
+//		http.Error(w, err.Error(), http.StatusInternalServerError)
+//		return
+//	}
+//	//create destination file making sure the path is writeable.
+//	dst, err := os.Create("upload/" + files[i].Filename)
+//	defer dst.Close()
+//	if err != nil {
+//		http.Error(w, err.Error(), http.StatusInternalServerError)
+//		return
+//	}
+//	//copy the uploaded file to the destination file
+//	if _, err := io.Copy(dst, file); err != nil {
+//		http.Error(w, err.Error(), http.StatusInternalServerError)
+//		return
+//	}
+// }
+func (c *Controller) GetFiles(key string) ([]*multipart.FileHeader, error) {
+	if files, ok := c.Ctx.Request.MultipartForm.File[key]; ok {
+		return files, nil
+	}
+	return nil, http.ErrMissingFile
+}
+
+// SaveToFile saves uploaded file to new path.
+// it only operates the first one of mutil-upload form file field.
+func (c *Controller) SaveToFile(fromfile, tofile string) error {
+	file, _, err := c.Ctx.Request.FormFile(fromfile)
+	if err != nil {
+		return err
+	}
+	defer file.Close()
+	f, err := os.OpenFile(tofile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	io.Copy(f, file)
+	return nil
+}
+
+// StartSession starts session and load old session data info this controller.
+func (c *Controller) StartSession() session.Store {
+	if c.CruSession == nil {
+		c.CruSession = c.Ctx.Input.CruSession
+	}
+	return c.CruSession
+}
+
+// SetSession puts value into session.
+func (c *Controller) SetSession(name interface{}, value interface{}) {
+	if c.CruSession == nil {
+		c.StartSession()
+	}
+	c.CruSession.Set(name, value)
+}
+
+// GetSession gets value from session.
+func (c *Controller) GetSession(name interface{}) interface{} {
+	if c.CruSession == nil {
+		c.StartSession()
+	}
+	return c.CruSession.Get(name)
+}
+
+// DelSession removes value from session.
+func (c *Controller) DelSession(name interface{}) {
+	if c.CruSession == nil {
+		c.StartSession()
+	}
+	c.CruSession.Delete(name)
+}
+
+// SessionRegenerateID regenerates session id for this session.
+// the session data have no changes.
+func (c *Controller) SessionRegenerateID() {
+	if c.CruSession != nil {
+		c.CruSession.SessionRelease(c.Ctx.ResponseWriter)
+	}
+	c.CruSession = GlobalSessions.SessionRegenerateID(c.Ctx.ResponseWriter, c.Ctx.Request)
+	c.Ctx.Input.CruSession = c.CruSession
+}
+
+// DestroySession cleans session data and session cookie.
+func (c *Controller) DestroySession() {
+	c.Ctx.Input.CruSession.Flush()
+	c.Ctx.Input.CruSession = nil
+	GlobalSessions.SessionDestroy(c.Ctx.ResponseWriter, c.Ctx.Request)
+}
+
+// IsAjax returns this request is ajax or not.
+func (c *Controller) IsAjax() bool {
+	return c.Ctx.Input.IsAjax()
+}
+
+// GetSecureCookie returns decoded cookie value from encoded browser cookie values.
+func (c *Controller) GetSecureCookie(Secret, key string) (string, bool) {
+	return c.Ctx.GetSecureCookie(Secret, key)
+}
+
+// SetSecureCookie puts value into cookie after encoded the value.
+func (c *Controller) SetSecureCookie(Secret, name, value string, others ...interface{}) {
+	c.Ctx.SetSecureCookie(Secret, name, value, others...)
+}
+
+// XSRFToken creates a CSRF token string and returns.
+func (c *Controller) XSRFToken() string {
+	if c._xsrfToken == "" {
+		expire := int64(BConfig.WebConfig.XSRFExpire)
+		if c.XSRFExpire > 0 {
+			expire = int64(c.XSRFExpire)
+		}
+		c._xsrfToken = c.Ctx.XSRFToken(BConfig.WebConfig.XSRFKey, expire)
+	}
+	return c._xsrfToken
+}
+
+// CheckXSRFCookie checks xsrf token in this request is valid or not.
+// the token can provided in request header "X-Xsrftoken" and "X-CsrfToken"
+// or in form field value named as "_xsrf".
+func (c *Controller) CheckXSRFCookie() bool {
+	if !c.EnableXSRF {
+		return true
+	}
+	return c.Ctx.CheckXSRFCookie()
+}
+
+// XSRFFormHTML writes an input field contains xsrf token value.
+func (c *Controller) XSRFFormHTML() string {
+	return `<input type="hidden" name="_xsrf" value="` +
+		c.XSRFToken() + `" />`
+}
+
+// GetControllerAndAction gets the executing controller name and action name.
+func (c *Controller) GetControllerAndAction() (string, string) {
+	return c.controllerName, c.actionName
+}

+ 181 - 0
vendor/github.com/astaxie/beego/controller_test.go

@@ -0,0 +1,181 @@
+// 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 beego
+
+import (
+	"math"
+	"strconv"
+	"testing"
+
+	"github.com/astaxie/beego/context"
+	"os"
+	"path/filepath"
+)
+
+func TestGetInt(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", "40")
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetInt("age")
+	if val != 40 {
+		t.Errorf("TestGetInt expect 40,get %T,%v", val, val)
+	}
+}
+
+func TestGetInt8(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", "40")
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetInt8("age")
+	if val != 40 {
+		t.Errorf("TestGetInt8 expect 40,get %T,%v", val, val)
+	}
+	//Output: int8
+}
+
+func TestGetInt16(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", "40")
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetInt16("age")
+	if val != 40 {
+		t.Errorf("TestGetInt16 expect 40,get %T,%v", val, val)
+	}
+}
+
+func TestGetInt32(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", "40")
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetInt32("age")
+	if val != 40 {
+		t.Errorf("TestGetInt32 expect 40,get %T,%v", val, val)
+	}
+}
+
+func TestGetInt64(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", "40")
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetInt64("age")
+	if val != 40 {
+		t.Errorf("TestGeetInt64 expect 40,get %T,%v", val, val)
+	}
+}
+
+func TestGetUint8(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", strconv.FormatUint(math.MaxUint8, 10))
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetUint8("age")
+	if val != math.MaxUint8 {
+		t.Errorf("TestGetUint8 expect %v,get %T,%v", math.MaxUint8, val, val)
+	}
+}
+
+func TestGetUint16(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", strconv.FormatUint(math.MaxUint16, 10))
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetUint16("age")
+	if val != math.MaxUint16 {
+		t.Errorf("TestGetUint16 expect %v,get %T,%v", math.MaxUint16, val, val)
+	}
+}
+
+func TestGetUint32(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", strconv.FormatUint(math.MaxUint32, 10))
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetUint32("age")
+	if val != math.MaxUint32 {
+		t.Errorf("TestGetUint32 expect %v,get %T,%v", math.MaxUint32, val, val)
+	}
+}
+
+func TestGetUint64(t *testing.T) {
+	i := context.NewInput()
+	i.SetParam("age", strconv.FormatUint(math.MaxUint64, 10))
+	ctx := &context.Context{Input: i}
+	ctrlr := Controller{Ctx: ctx}
+	val, _ := ctrlr.GetUint64("age")
+	if val != math.MaxUint64 {
+		t.Errorf("TestGetUint64 expect %v,get %T,%v", uint64(math.MaxUint64), val, val)
+	}
+}
+
+func TestAdditionalViewPaths(t *testing.T) {
+	dir1 := "_beeTmp"
+	dir2 := "_beeTmp2"
+	defer os.RemoveAll(dir1)
+	defer os.RemoveAll(dir2)
+
+	dir1file := "file1.tpl"
+	dir2file := "file2.tpl"
+
+	genFile := func(dir string, name string, content string) {
+		os.MkdirAll(filepath.Dir(filepath.Join(dir, name)), 0777)
+		if f, err := os.Create(filepath.Join(dir, name)); err != nil {
+			t.Fatal(err)
+		} else {
+			defer f.Close()
+			f.WriteString(content)
+			f.Close()
+		}
+
+	}
+	genFile(dir1, dir1file, `<div>{{.Content}}</div>`)
+	genFile(dir2, dir2file, `<html>{{.Content}}</html>`)
+
+	AddViewPath(dir1)
+	AddViewPath(dir2)
+
+	ctrl := Controller{
+		TplName:  "file1.tpl",
+		ViewPath: dir1,
+	}
+	ctrl.Data = map[interface{}]interface{}{
+		"Content": "value2",
+	}
+	if result, err := ctrl.RenderString(); err != nil {
+		t.Fatal(err)
+	} else {
+		if result != "<div>value2</div>" {
+			t.Fatalf("TestAdditionalViewPaths expect %s got %s", "<div>value2</div>", result)
+		}
+	}
+
+	func() {
+		ctrl.TplName = "file2.tpl"
+		defer func() {
+			if r := recover(); r == nil {
+				t.Fatal("TestAdditionalViewPaths expected error")
+			}
+		}()
+		ctrl.RenderString()
+	}()
+
+	ctrl.TplName = "file2.tpl"
+	ctrl.ViewPath = dir2
+	ctrl.RenderString()
+}

+ 17 - 0
vendor/github.com/astaxie/beego/doc.go

@@ -0,0 +1,17 @@
+/*
+Package beego provide a MVC framework
+beego: an open-source, high-performance, modular, full-stack web framework
+
+It is used for rapid development of RESTful APIs, web apps and backend services in Go.
+beego is inspired by Tornado, Sinatra and Flask with the added benefit of some Go-specific features such as interfaces and struct embedding.
+
+	package main
+	import "github.com/astaxie/beego"
+
+	func main() {
+	 beego.Run()
+	}
+
+more information: http://beego.me
+*/
+package beego

+ 476 - 0
vendor/github.com/astaxie/beego/error.go

@@ -0,0 +1,476 @@
+// 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 beego
+
+import (
+	"fmt"
+	"html/template"
+	"net/http"
+	"reflect"
+	"runtime"
+	"strconv"
+	"strings"
+
+	"github.com/astaxie/beego/context"
+	"github.com/astaxie/beego/utils"
+)
+
+const (
+	errorTypeHandler = iota
+	errorTypeController
+)
+
+var tpl = `
+<!DOCTYPE html>
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <title>beego application error</title>
+    <style>
+        html, body, body * {padding: 0; margin: 0;}
+        #header {background:#ffd; border-bottom:solid 2px #A31515; padding: 20px 10px;}
+        #header h2{ }
+        #footer {border-top:solid 1px #aaa; padding: 5px 10px; font-size: 12px; color:green;}
+        #content {padding: 5px;}
+        #content .stack b{ font-size: 13px; color: red;}
+        #content .stack pre{padding-left: 10px;}
+        table {}
+        td.t {text-align: right; padding-right: 5px; color: #888;}
+    </style>
+    <script type="text/javascript">
+    </script>
+</head>
+<body>
+    <div id="header">
+        <h2>{{.AppError}}</h2>
+    </div>
+    <div id="content">
+        <table>
+            <tr>
+                <td class="t">Request Method: </td><td>{{.RequestMethod}}</td>
+            </tr>
+            <tr>
+                <td class="t">Request URL: </td><td>{{.RequestURL}}</td>
+            </tr>
+            <tr>
+                <td class="t">RemoteAddr: </td><td>{{.RemoteAddr }}</td>
+            </tr>
+        </table>
+        <div class="stack">
+            <b>Stack</b>
+            <pre>{{.Stack}}</pre>
+        </div>
+    </div>
+    <div id="footer">
+        <p>beego {{ .BeegoVersion }} (beego framework)</p>
+        <p>golang version: {{.GoVersion}}</p>
+    </div>
+</body>
+</html>
+`
+
+// render default application error page with error and stack string.
+func showErr(err interface{}, ctx *context.Context, stack string) {
+	t, _ := template.New("beegoerrortemp").Parse(tpl)
+	data := map[string]string{
+		"AppError":      fmt.Sprintf("%s:%v", BConfig.AppName, err),
+		"RequestMethod": ctx.Input.Method(),
+		"RequestURL":    ctx.Input.URI(),
+		"RemoteAddr":    ctx.Input.IP(),
+		"Stack":         stack,
+		"BeegoVersion":  VERSION,
+		"GoVersion":     runtime.Version(),
+	}
+	if ctx.Output.Status != 0 {
+		ctx.ResponseWriter.WriteHeader(ctx.Output.Status)
+	} else {
+		ctx.ResponseWriter.WriteHeader(500)
+	}
+	t.Execute(ctx.ResponseWriter, data)
+}
+
+var errtpl = `
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+		<title>{{.Title}}</title>
+		<style type="text/css">
+			* {
+				margin:0;
+				padding:0;
+			}
+
+			body {
+				background-color:#EFEFEF;
+				font: .9em "Lucida Sans Unicode", "Lucida Grande", sans-serif;
+			}
+
+			#wrapper{
+				width:600px;
+				margin:40px auto 0;
+				text-align:center;
+				-moz-box-shadow: 5px 5px 10px rgba(0,0,0,0.3);
+				-webkit-box-shadow: 5px 5px 10px rgba(0,0,0,0.3);
+				box-shadow: 5px 5px 10px rgba(0,0,0,0.3);
+			}
+
+			#wrapper h1{
+				color:#FFF;
+				text-align:center;
+				margin-bottom:20px;
+			}
+
+			#wrapper a{
+				display:block;
+				font-size:.9em;
+				padding-top:20px;
+				color:#FFF;
+				text-decoration:none;
+				text-align:center;
+			}
+
+			#container {
+				width:600px;
+				padding-bottom:15px;
+				background-color:#FFFFFF;
+			}
+
+			.navtop{
+				height:40px;
+				background-color:#24B2EB;
+				padding:13px;
+			}
+
+			.content {
+				padding:10px 10px 25px;
+				background: #FFFFFF;
+				margin:;
+				color:#333;
+			}
+
+			a.button{
+				color:white;
+				padding:15px 20px;
+				text-shadow:1px 1px 0 #00A5FF;
+				font-weight:bold;
+				text-align:center;
+				border:1px solid #24B2EB;
+				margin:0px 200px;
+				clear:both;
+				background-color: #24B2EB;
+				border-radius:100px;
+				-moz-border-radius:100px;
+				-webkit-border-radius:100px;
+			}
+
+			a.button:hover{
+				text-decoration:none;
+				background-color: #24B2EB;
+			}
+
+		</style>
+	</head>
+	<body>
+		<div id="wrapper">
+			<div id="container">
+				<div class="navtop">
+					<h1>{{.Title}}</h1>
+				</div>
+				<div id="content">
+					{{.Content}}
+					<a href="/" title="Home" class="button">Go Home</a><br />
+
+					<br>Powered by beego {{.BeegoVersion}}
+				</div>
+			</div>
+		</div>
+	</body>
+</html>
+`
+
+type errorInfo struct {
+	controllerType reflect.Type
+	handler        http.HandlerFunc
+	method         string
+	errorType      int
+}
+
+// ErrorMaps holds map of http handlers for each error string.
+// there is 10 kinds default error(40x and 50x)
+var ErrorMaps = make(map[string]*errorInfo, 10)
+
+// show 401 unauthorized error.
+func unauthorized(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		401,
+		"<br>The page you have requested can't be authorized."+
+			"<br>Perhaps you are here because:"+
+			"<br><br><ul>"+
+			"<br>The credentials you supplied are incorrect"+
+			"<br>There are errors in the website address"+
+			"</ul>",
+	)
+}
+
+// show 402 Payment Required
+func paymentRequired(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		402,
+		"<br>The page you have requested Payment Required."+
+			"<br>Perhaps you are here because:"+
+			"<br><br><ul>"+
+			"<br>The credentials you supplied are incorrect"+
+			"<br>There are errors in the website address"+
+			"</ul>",
+	)
+}
+
+// show 403 forbidden error.
+func forbidden(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		403,
+		"<br>The page you have requested is forbidden."+
+			"<br>Perhaps you are here because:"+
+			"<br><br><ul>"+
+			"<br>Your address may be blocked"+
+			"<br>The site may be disabled"+
+			"<br>You need to log in"+
+			"</ul>",
+	)
+}
+
+// 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,
+		404,
+		"<br>The page you have requested has flown the coop."+
+			"<br>Perhaps you are here because:"+
+			"<br><br><ul>"+
+			"<br>The page has moved"+
+			"<br>The page no longer exists"+
+			"<br>You were looking for your puppy and got lost"+
+			"<br>You like 404 pages"+
+			"</ul>",
+	)
+}
+
+// show 405 Method Not Allowed
+func methodNotAllowed(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		405,
+		"<br>The method you have requested Not Allowed."+
+			"<br>Perhaps you are here because:"+
+			"<br><br><ul>"+
+			"<br>The method specified in the Request-Line is not allowed for the resource identified by the Request-URI"+
+			"<br>The response MUST include an Allow header containing a list of valid methods for the requested resource."+
+			"</ul>",
+	)
+}
+
+// show 500 internal server error.
+func internalServerError(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		500,
+		"<br>The page you have requested is down right now."+
+			"<br><br><ul>"+
+			"<br>Please try again later and report the error to the website administrator"+
+			"<br></ul>",
+	)
+}
+
+// show 501 Not Implemented.
+func notImplemented(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		501,
+		"<br>The page you have requested is Not Implemented."+
+			"<br><br><ul>"+
+			"<br>Please try again later and report the error to the website administrator"+
+			"<br></ul>",
+	)
+}
+
+// show 502 Bad Gateway.
+func badGateway(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		502,
+		"<br>The page you have requested is down right now."+
+			"<br><br><ul>"+
+			"<br>The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request."+
+			"<br>Please try again later and report the error to the website administrator"+
+			"<br></ul>",
+	)
+}
+
+// show 503 service unavailable error.
+func serviceUnavailable(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		503,
+		"<br>The page you have requested is unavailable."+
+			"<br>Perhaps you are here because:"+
+			"<br><br><ul>"+
+			"<br><br>The page is overloaded"+
+			"<br>Please try again later."+
+			"</ul>",
+	)
+}
+
+// show 504 Gateway Timeout.
+func gatewayTimeout(rw http.ResponseWriter, r *http.Request) {
+	responseError(rw, r,
+		504,
+		"<br>The page you have requested is unavailable"+
+			"<br>Perhaps you are here because:"+
+			"<br><br><ul>"+
+			"<br><br>The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI."+
+			"<br>Please try again later."+
+			"</ul>",
+	)
+}
+
+func responseError(rw http.ResponseWriter, r *http.Request, errCode int, errContent string) {
+	t, _ := template.New("beegoerrortemp").Parse(errtpl)
+	data := map[string]interface{}{
+		"Title":        http.StatusText(errCode),
+		"BeegoVersion": VERSION,
+		"Content":      template.HTML(errContent),
+	}
+	t.Execute(rw, data)
+}
+
+// ErrorHandler registers http.HandlerFunc to each http err code string.
+// usage:
+// 	beego.ErrorHandler("404",NotFound)
+//	beego.ErrorHandler("500",InternalServerError)
+func ErrorHandler(code string, h http.HandlerFunc) *App {
+	ErrorMaps[code] = &errorInfo{
+		errorType: errorTypeHandler,
+		handler:   h,
+		method:    code,
+	}
+	return BeeApp
+}
+
+// ErrorController registers ControllerInterface to each http err code string.
+// usage:
+// 	beego.ErrorController(&controllers.ErrorController{})
+func ErrorController(c ControllerInterface) *App {
+	reflectVal := reflect.ValueOf(c)
+	rt := reflectVal.Type()
+	ct := reflect.Indirect(reflectVal).Type()
+	for i := 0; i < rt.NumMethod(); i++ {
+		methodName := rt.Method(i).Name
+		if !utils.InSlice(methodName, exceptMethod) && strings.HasPrefix(methodName, "Error") {
+			errName := strings.TrimPrefix(methodName, "Error")
+			ErrorMaps[errName] = &errorInfo{
+				errorType:      errorTypeController,
+				controllerType: ct,
+				method:         methodName,
+			}
+		}
+	}
+	return BeeApp
+}
+
+// Exception Write HttpStatus with errCode and Exec error handler if exist.
+func Exception(errCode uint64, ctx *context.Context) {
+	exception(strconv.FormatUint(errCode, 10), ctx)
+}
+
+// show error string as simple text message.
+// if error string is empty, show 503 or 500 error as default.
+func exception(errCode string, ctx *context.Context) {
+	atoi := func(code string) int {
+		v, err := strconv.Atoi(code)
+		if err == nil {
+			return v
+		}
+		if ctx.Output.Status == 0 {
+			return 503
+		}
+		return ctx.Output.Status
+	}
+
+	for _, ec := range []string{errCode, "503", "500"} {
+		if h, ok := ErrorMaps[ec]; ok {
+			executeError(h, ctx, atoi(ec))
+			return
+		}
+	}
+	//if 50x error has been removed from errorMap
+	ctx.ResponseWriter.WriteHeader(atoi(errCode))
+	ctx.WriteString(errCode)
+}
+
+func executeError(err *errorInfo, ctx *context.Context, code int) {
+	if err.errorType == errorTypeHandler {
+		ctx.ResponseWriter.WriteHeader(code)
+		err.handler(ctx.ResponseWriter, ctx.Request)
+		return
+	}
+	if err.errorType == errorTypeController {
+		ctx.Output.SetStatus(code)
+		//Invoke the request handler
+		vc := reflect.New(err.controllerType)
+		execController, ok := vc.Interface().(ControllerInterface)
+		if !ok {
+			panic("controller is not ControllerInterface")
+		}
+		//call the controller init function
+		execController.Init(ctx, err.controllerType.Name(), err.method, vc.Interface())
+
+		//call prepare function
+		execController.Prepare()
+
+		execController.URLMapping()
+
+		method := vc.MethodByName(err.method)
+		method.Call([]reflect.Value{})
+
+		//render template
+		if BConfig.WebConfig.AutoRender {
+			if err := execController.Render(); err != nil {
+				panic(err)
+			}
+		}
+
+		// finish all runrouter. release resource
+		execController.Finish()
+	}
+}

+ 88 - 0
vendor/github.com/astaxie/beego/error_test.go

@@ -0,0 +1,88 @@
+// Copyright 2016 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 beego
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+type errorTestController struct {
+	Controller
+}
+
+const parseCodeError = "parse code error"
+
+func (ec *errorTestController) Get() {
+	errorCode, err := ec.GetInt("code")
+	if err != nil {
+		ec.Abort(parseCodeError)
+	}
+	if errorCode != 0 {
+		ec.CustomAbort(errorCode, ec.GetString("code"))
+	}
+	ec.Abort("404")
+}
+
+func TestErrorCode_01(t *testing.T) {
+	registerDefaultErrorHandler()
+	for k := range ErrorMaps {
+		r, _ := http.NewRequest("GET", "/error?code="+k, nil)
+		w := httptest.NewRecorder()
+
+		handler := NewControllerRegister()
+		handler.Add("/error", &errorTestController{})
+		handler.ServeHTTP(w, r)
+		code, _ := strconv.Atoi(k)
+		if w.Code != code {
+			t.Fail()
+		}
+		if !strings.Contains(string(w.Body.Bytes()), http.StatusText(code)) {
+			t.Fail()
+		}
+	}
+}
+
+func TestErrorCode_02(t *testing.T) {
+	registerDefaultErrorHandler()
+	r, _ := http.NewRequest("GET", "/error?code=0", nil)
+	w := httptest.NewRecorder()
+
+	handler := NewControllerRegister()
+	handler.Add("/error", &errorTestController{})
+	handler.ServeHTTP(w, r)
+	if w.Code != 404 {
+		t.Fail()
+	}
+}
+
+func TestErrorCode_03(t *testing.T) {
+	registerDefaultErrorHandler()
+	r, _ := http.NewRequest("GET", "/error?code=panic", nil)
+	w := httptest.NewRecorder()
+
+	handler := NewControllerRegister()
+	handler.Add("/error", &errorTestController{})
+	handler.ServeHTTP(w, r)
+	if w.Code != 200 {
+		t.Fail()
+	}
+	if string(w.Body.Bytes()) != parseCodeError {
+		t.Fail()
+	}
+}

+ 44 - 0
vendor/github.com/astaxie/beego/filter.go

@@ -0,0 +1,44 @@
+// 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 beego
+
+import "github.com/astaxie/beego/context"
+
+// FilterFunc defines a filter function which is invoked before the controller handler is executed.
+type FilterFunc func(*context.Context)
+
+// FilterRouter defines a filter operation which is invoked before the controller handler is executed.
+// It can match the URL against a pattern, and execute a filter function
+// when a request with a matching URL arrives.
+type FilterRouter struct {
+	filterFunc     FilterFunc
+	tree           *Tree
+	pattern        string
+	returnOnOutput bool
+	resetParams    bool
+}
+
+// ValidRouter checks if the current request is matched by this filter.
+// If the request is matched, the values of the URL parameters defined
+// by the filter pattern are also returned.
+func (f *FilterRouter) ValidRouter(url string, ctx *context.Context) bool {
+	isOk := f.tree.Match(url, ctx)
+	if isOk != nil {
+		if b, ok := isOk.(bool); ok {
+			return b
+		}
+	}
+	return false
+}

+ 68 - 0
vendor/github.com/astaxie/beego/filter_test.go

@@ -0,0 +1,68 @@
+// 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 beego
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/astaxie/beego/context"
+)
+
+var FilterUser = func(ctx *context.Context) {
+	ctx.Output.Body([]byte("i am " + ctx.Input.Param(":last") + ctx.Input.Param(":first")))
+}
+
+func TestFilter(t *testing.T) {
+	r, _ := http.NewRequest("GET", "/person/asta/Xie", nil)
+	w := httptest.NewRecorder()
+	handler := NewControllerRegister()
+	handler.InsertFilter("/person/:last/:first", BeforeRouter, FilterUser)
+	handler.Add("/person/:last/:first", &TestController{})
+	handler.ServeHTTP(w, r)
+	if w.Body.String() != "i am astaXie" {
+		t.Errorf("user define func can't run")
+	}
+}
+
+var FilterAdminUser = func(ctx *context.Context) {
+	ctx.Output.Body([]byte("i am admin"))
+}
+
+// Filter pattern /admin/:all
+// all url like    /admin/    /admin/xie    will all get filter
+
+func TestPatternTwo(t *testing.T) {
+	r, _ := http.NewRequest("GET", "/admin/", nil)
+	w := httptest.NewRecorder()
+	handler := NewControllerRegister()
+	handler.InsertFilter("/admin/?:all", BeforeRouter, FilterAdminUser)
+	handler.ServeHTTP(w, r)
+	if w.Body.String() != "i am admin" {
+		t.Errorf("filter /admin/ can't run")
+	}
+}
+
+func TestPatternThree(t *testing.T) {
+	r, _ := http.NewRequest("GET", "/admin/astaxie", nil)
+	w := httptest.NewRecorder()
+	handler := NewControllerRegister()
+	handler.InsertFilter("/admin/:all", BeforeRouter, FilterAdminUser)
+	handler.ServeHTTP(w, r)
+	if w.Body.String() != "i am admin" {
+		t.Errorf("filter /admin/astaxie can't run")
+	}
+}

+ 110 - 0
vendor/github.com/astaxie/beego/flash.go

@@ -0,0 +1,110 @@
+// 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 beego
+
+import (
+	"fmt"
+	"net/url"
+	"strings"
+)
+
+// FlashData is a tools to maintain data when using across request.
+type FlashData struct {
+	Data map[string]string
+}
+
+// NewFlash return a new empty FlashData struct.
+func NewFlash() *FlashData {
+	return &FlashData{
+		Data: make(map[string]string),
+	}
+}
+
+// Set message to flash
+func (fd *FlashData) Set(key string, msg string, args ...interface{}) {
+	if len(args) == 0 {
+		fd.Data[key] = msg
+	} else {
+		fd.Data[key] = fmt.Sprintf(msg, args...)
+	}
+}
+
+// Success writes success message to flash.
+func (fd *FlashData) Success(msg string, args ...interface{}) {
+	if len(args) == 0 {
+		fd.Data["success"] = msg
+	} else {
+		fd.Data["success"] = fmt.Sprintf(msg, args...)
+	}
+}
+
+// Notice writes notice message to flash.
+func (fd *FlashData) Notice(msg string, args ...interface{}) {
+	if len(args) == 0 {
+		fd.Data["notice"] = msg
+	} else {
+		fd.Data["notice"] = fmt.Sprintf(msg, args...)
+	}
+}
+
+// Warning writes warning message to flash.
+func (fd *FlashData) Warning(msg string, args ...interface{}) {
+	if len(args) == 0 {
+		fd.Data["warning"] = msg
+	} else {
+		fd.Data["warning"] = fmt.Sprintf(msg, args...)
+	}
+}
+
+// Error writes error message to flash.
+func (fd *FlashData) Error(msg string, args ...interface{}) {
+	if len(args) == 0 {
+		fd.Data["error"] = msg
+	} else {
+		fd.Data["error"] = fmt.Sprintf(msg, args...)
+	}
+}
+
+// Store does the saving operation of flash data.
+// the data are encoded and saved in cookie.
+func (fd *FlashData) Store(c *Controller) {
+	c.Data["flash"] = fd.Data
+	var flashValue string
+	for key, value := range fd.Data {
+		flashValue += "\x00" + key + "\x23" + BConfig.WebConfig.FlashSeparator + "\x23" + value + "\x00"
+	}
+	c.Ctx.SetCookie(BConfig.WebConfig.FlashName, url.QueryEscape(flashValue), 0, "/")
+}
+
+// ReadFromRequest parsed flash data from encoded values in cookie.
+func ReadFromRequest(c *Controller) *FlashData {
+	flash := NewFlash()
+	if cookie, err := c.Ctx.Request.Cookie(BConfig.WebConfig.FlashName); err == nil {
+		v, _ := url.QueryUnescape(cookie.Value)
+		vals := strings.Split(v, "\x00")
+		for _, v := range vals {
+			if len(v) > 0 {
+				kv := strings.Split(v, "\x23"+BConfig.WebConfig.FlashSeparator+"\x23")
+				if len(kv) == 2 {
+					flash.Data[kv[0]] = kv[1]
+				}
+			}
+		}
+		//read one time then delete it
+		c.Ctx.SetCookie(BConfig.WebConfig.FlashName, "", -1, "/")
+	}
+	c.Data["flash"] = flash.Data
+	return flash
+}

+ 54 - 0
vendor/github.com/astaxie/beego/flash_test.go

@@ -0,0 +1,54 @@
+// 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 beego
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"strings"
+	"testing"
+)
+
+type TestFlashController struct {
+	Controller
+}
+
+func (t *TestFlashController) TestWriteFlash() {
+	flash := NewFlash()
+	flash.Notice("TestFlashString")
+	flash.Store(&t.Controller)
+	// we choose to serve json because we don't want to load a template html file
+	t.ServeJSON(true)
+}
+
+func TestFlashHeader(t *testing.T) {
+	// create fake GET request
+	r, _ := http.NewRequest("GET", "/", nil)
+	w := httptest.NewRecorder()
+
+	// setup the handler
+	handler := NewControllerRegister()
+	handler.Add("/", &TestFlashController{}, "get:TestWriteFlash")
+	handler.ServeHTTP(w, r)
+
+	// get the Set-Cookie value
+	sc := w.Header().Get("Set-Cookie")
+	// match for the expected header
+	res := strings.Contains(sc, "BEEGO_FLASH=%00notice%23BEEGOFLASH%23TestFlashString%00")
+	// validate the assertion
+	if !res {
+		t.Errorf("TestFlashHeader() unable to validate flash message")
+	}
+}

+ 28 - 0
vendor/github.com/astaxie/beego/grace/conn.go

@@ -0,0 +1,28 @@
+package grace
+
+import (
+	"errors"
+	"net"
+)
+
+type graceConn struct {
+	net.Conn
+	server *Server
+}
+
+func (c graceConn) Close() (err error) {
+	defer func() {
+		if r := recover(); r != nil {
+			switch x := r.(type) {
+			case string:
+				err = errors.New(x)
+			case error:
+				err = x
+			default:
+				err = errors.New("Unknown panic")
+			}
+		}
+	}()
+	c.server.wg.Done()
+	return c.Conn.Close()
+}

+ 166 - 0
vendor/github.com/astaxie/beego/grace/grace.go

@@ -0,0 +1,166 @@
+// 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 grace use to hot reload
+// Description: http://grisha.org/blog/2014/06/03/graceful-restart-in-golang/
+//
+// Usage:
+//
+// import(
+//   "log"
+//	 "net/http"
+//	 "os"
+//
+//   "github.com/astaxie/beego/grace"
+// )
+//
+//  func handler(w http.ResponseWriter, r *http.Request) {
+//	  w.Write([]byte("WORLD!"))
+//  }
+//
+//  func main() {
+//      mux := http.NewServeMux()
+//      mux.HandleFunc("/hello", handler)
+//
+//	    err := grace.ListenAndServe("localhost:8080", mux)
+//      if err != nil {
+//		   log.Println(err)
+//	    }
+//      log.Println("Server on 8080 stopped")
+//	     os.Exit(0)
+//    }
+package grace
+
+import (
+	"flag"
+	"net/http"
+	"os"
+	"strings"
+	"sync"
+	"syscall"
+	"time"
+)
+
+const (
+	// PreSignal is the position to add filter before signal
+	PreSignal = iota
+	// PostSignal is the position to add filter after signal
+	PostSignal
+	// StateInit represent the application inited
+	StateInit
+	// StateRunning represent the application is running
+	StateRunning
+	// StateShuttingDown represent the application is shutting down
+	StateShuttingDown
+	// StateTerminate represent the application is killed
+	StateTerminate
+)
+
+var (
+	regLock              *sync.Mutex
+	runningServers       map[string]*Server
+	runningServersOrder  []string
+	socketPtrOffsetMap   map[string]uint
+	runningServersForked bool
+
+	// DefaultReadTimeOut is the HTTP read timeout
+	DefaultReadTimeOut time.Duration
+	// DefaultWriteTimeOut is the HTTP Write timeout
+	DefaultWriteTimeOut time.Duration
+	// DefaultMaxHeaderBytes is the Max HTTP Herder size, default is 0, no limit
+	DefaultMaxHeaderBytes int
+	// DefaultTimeout is the shutdown server's timeout. default is 60s
+	DefaultTimeout = 60 * time.Second
+
+	isChild     bool
+	socketOrder string
+
+	hookableSignals []os.Signal
+)
+
+func init() {
+	flag.BoolVar(&isChild, "graceful", false, "listen on open fd (after forking)")
+	flag.StringVar(&socketOrder, "socketorder", "", "previous initialization order - used when more than one listener was started")
+
+	regLock = &sync.Mutex{}
+	runningServers = make(map[string]*Server)
+	runningServersOrder = []string{}
+	socketPtrOffsetMap = make(map[string]uint)
+
+	hookableSignals = []os.Signal{
+		syscall.SIGHUP,
+		syscall.SIGINT,
+		syscall.SIGTERM,
+	}
+}
+
+// NewServer returns a new graceServer.
+func NewServer(addr string, handler http.Handler) (srv *Server) {
+	regLock.Lock()
+	defer regLock.Unlock()
+
+	if !flag.Parsed() {
+		flag.Parse()
+	}
+	if len(socketOrder) > 0 {
+		for i, addr := range strings.Split(socketOrder, ",") {
+			socketPtrOffsetMap[addr] = uint(i)
+		}
+	} else {
+		socketPtrOffsetMap[addr] = uint(len(runningServersOrder))
+	}
+
+	srv = &Server{
+		wg:      sync.WaitGroup{},
+		sigChan: make(chan os.Signal),
+		isChild: isChild,
+		SignalHooks: map[int]map[os.Signal][]func(){
+			PreSignal: {
+				syscall.SIGHUP:  {},
+				syscall.SIGINT:  {},
+				syscall.SIGTERM: {},
+			},
+			PostSignal: {
+				syscall.SIGHUP:  {},
+				syscall.SIGINT:  {},
+				syscall.SIGTERM: {},
+			},
+		},
+		state:   StateInit,
+		Network: "tcp",
+	}
+	srv.Server = &http.Server{}
+	srv.Server.Addr = addr
+	srv.Server.ReadTimeout = DefaultReadTimeOut
+	srv.Server.WriteTimeout = DefaultWriteTimeOut
+	srv.Server.MaxHeaderBytes = DefaultMaxHeaderBytes
+	srv.Server.Handler = handler
+
+	runningServersOrder = append(runningServersOrder, addr)
+	runningServers[addr] = srv
+
+	return
+}
+
+// ListenAndServe refer http.ListenAndServe
+func ListenAndServe(addr string, handler http.Handler) error {
+	server := NewServer(addr, handler)
+	return server.ListenAndServe()
+}
+
+// ListenAndServeTLS refer http.ListenAndServeTLS
+func ListenAndServeTLS(addr string, certFile string, keyFile string, handler http.Handler) error {
+	server := NewServer(addr, handler)
+	return server.ListenAndServeTLS(certFile, keyFile)
+}

+ 62 - 0
vendor/github.com/astaxie/beego/grace/listener.go

@@ -0,0 +1,62 @@
+package grace
+
+import (
+	"net"
+	"os"
+	"syscall"
+	"time"
+)
+
+type graceListener struct {
+	net.Listener
+	stop    chan error
+	stopped bool
+	server  *Server
+}
+
+func newGraceListener(l net.Listener, srv *Server) (el *graceListener) {
+	el = &graceListener{
+		Listener: l,
+		stop:     make(chan error),
+		server:   srv,
+	}
+	go func() {
+		<-el.stop
+		el.stopped = true
+		el.stop <- el.Listener.Close()
+	}()
+	return
+}
+
+func (gl *graceListener) Accept() (c net.Conn, err error) {
+	tc, err := gl.Listener.(*net.TCPListener).AcceptTCP()
+	if err != nil {
+		return
+	}
+
+	tc.SetKeepAlive(true)
+	tc.SetKeepAlivePeriod(3 * time.Minute)
+
+	c = graceConn{
+		Conn:   tc,
+		server: gl.server,
+	}
+
+	gl.server.wg.Add(1)
+	return
+}
+
+func (gl *graceListener) Close() error {
+	if gl.stopped {
+		return syscall.EINVAL
+	}
+	gl.stop <- nil
+	return <-gl.stop
+}
+
+func (gl *graceListener) File() *os.File {
+	// returns a dup(2) - FD_CLOEXEC flag *not* set
+	tl := gl.Listener.(*net.TCPListener)
+	fl, _ := tl.File()
+	return fl
+}

+ 305 - 0
vendor/github.com/astaxie/beego/grace/server.go

@@ -0,0 +1,305 @@
+package grace
+
+import (
+	"crypto/tls"
+	"fmt"
+	"log"
+	"net"
+	"net/http"
+	"os"
+	"os/exec"
+	"os/signal"
+	"strings"
+	"sync"
+	"syscall"
+	"time"
+)
+
+// Server embedded http.Server
+type Server struct {
+	*http.Server
+	GraceListener    net.Listener
+	SignalHooks      map[int]map[os.Signal][]func()
+	tlsInnerListener *graceListener
+	wg               sync.WaitGroup
+	sigChan          chan os.Signal
+	isChild          bool
+	state            uint8
+	Network          string
+}
+
+// Serve accepts incoming connections on the Listener l,
+// creating a new service goroutine for each.
+// The service goroutines read requests and then call srv.Handler to reply to them.
+func (srv *Server) Serve() (err error) {
+	srv.state = StateRunning
+	err = srv.Server.Serve(srv.GraceListener)
+	log.Println(syscall.Getpid(), "Waiting for connections to finish...")
+	srv.wg.Wait()
+	srv.state = StateTerminate
+	return
+}
+
+// ListenAndServe listens on the TCP network address srv.Addr and then calls Serve
+// to handle requests on incoming connections. If srv.Addr is blank, ":http" is
+// used.
+func (srv *Server) ListenAndServe() (err error) {
+	addr := srv.Addr
+	if addr == "" {
+		addr = ":http"
+	}
+
+	go srv.handleSignals()
+
+	l, err := srv.getListener(addr)
+	if err != nil {
+		log.Println(err)
+		return err
+	}
+
+	srv.GraceListener = newGraceListener(l, srv)
+
+	if srv.isChild {
+		process, err := os.FindProcess(os.Getppid())
+		if err != nil {
+			log.Println(err)
+			return err
+		}
+		err = process.Kill()
+		if err != nil {
+			return err
+		}
+	}
+
+	log.Println(os.Getpid(), srv.Addr)
+	return srv.Serve()
+}
+
+// ListenAndServeTLS listens on the TCP network address srv.Addr and then calls
+// Serve to handle requests on incoming TLS connections.
+//
+// Filenames containing a certificate and matching private key for the server must
+// be provided. If the certificate is signed by a certificate authority, the
+// certFile should be the concatenation of the server's certificate followed by the
+// CA's certificate.
+//
+// If srv.Addr is blank, ":https" is used.
+func (srv *Server) ListenAndServeTLS(certFile, keyFile string) (err error) {
+	addr := srv.Addr
+	if addr == "" {
+		addr = ":https"
+	}
+
+	if srv.TLSConfig == nil {
+		srv.TLSConfig = &tls.Config{}
+	}
+	if srv.TLSConfig.NextProtos == nil {
+		srv.TLSConfig.NextProtos = []string{"http/1.1"}
+	}
+
+	srv.TLSConfig.Certificates = make([]tls.Certificate, 1)
+	srv.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
+	if err != nil {
+		return
+	}
+
+	go srv.handleSignals()
+
+	l, err := srv.getListener(addr)
+	if err != nil {
+		log.Println(err)
+		return err
+	}
+
+	srv.tlsInnerListener = newGraceListener(l, srv)
+	srv.GraceListener = tls.NewListener(srv.tlsInnerListener, srv.TLSConfig)
+
+	if srv.isChild {
+		process, err := os.FindProcess(os.Getppid())
+		if err != nil {
+			log.Println(err)
+			return err
+		}
+		err = process.Kill()
+		if err != nil {
+			return err
+		}
+	}
+	log.Println(os.Getpid(), srv.Addr)
+	return srv.Serve()
+}
+
+// getListener either opens a new socket to listen on, or takes the acceptor socket
+// it got passed when restarted.
+func (srv *Server) getListener(laddr string) (l net.Listener, err error) {
+	if srv.isChild {
+		var ptrOffset uint
+		if len(socketPtrOffsetMap) > 0 {
+			ptrOffset = socketPtrOffsetMap[laddr]
+			log.Println("laddr", laddr, "ptr offset", socketPtrOffsetMap[laddr])
+		}
+
+		f := os.NewFile(uintptr(3+ptrOffset), "")
+		l, err = net.FileListener(f)
+		if err != nil {
+			err = fmt.Errorf("net.FileListener error: %v", err)
+			return
+		}
+	} else {
+		l, err = net.Listen(srv.Network, laddr)
+		if err != nil {
+			err = fmt.Errorf("net.Listen error: %v", err)
+			return
+		}
+	}
+	return
+}
+
+// handleSignals listens for os Signals and calls any hooked in function that the
+// user had registered with the signal.
+func (srv *Server) handleSignals() {
+	var sig os.Signal
+
+	signal.Notify(
+		srv.sigChan,
+		hookableSignals...,
+	)
+
+	pid := syscall.Getpid()
+	for {
+		sig = <-srv.sigChan
+		srv.signalHooks(PreSignal, sig)
+		switch sig {
+		case syscall.SIGHUP:
+			log.Println(pid, "Received SIGHUP. forking.")
+			err := srv.fork()
+			if err != nil {
+				log.Println("Fork err:", err)
+			}
+		case syscall.SIGINT:
+			log.Println(pid, "Received SIGINT.")
+			srv.shutdown()
+		case syscall.SIGTERM:
+			log.Println(pid, "Received SIGTERM.")
+			srv.shutdown()
+		default:
+			log.Printf("Received %v: nothing i care about...\n", sig)
+		}
+		srv.signalHooks(PostSignal, sig)
+	}
+}
+
+func (srv *Server) signalHooks(ppFlag int, sig os.Signal) {
+	if _, notSet := srv.SignalHooks[ppFlag][sig]; !notSet {
+		return
+	}
+	for _, f := range srv.SignalHooks[ppFlag][sig] {
+		f()
+	}
+}
+
+// shutdown closes the listener so that no new connections are accepted. it also
+// starts a goroutine that will serverTimeout (stop all running requests) the server
+// after DefaultTimeout.
+func (srv *Server) shutdown() {
+	if srv.state != StateRunning {
+		return
+	}
+
+	srv.state = StateShuttingDown
+	if DefaultTimeout >= 0 {
+		go srv.serverTimeout(DefaultTimeout)
+	}
+	err := srv.GraceListener.Close()
+	if err != nil {
+		log.Println(syscall.Getpid(), "Listener.Close() error:", err)
+	} else {
+		log.Println(syscall.Getpid(), srv.GraceListener.Addr(), "Listener closed.")
+	}
+}
+
+// serverTimeout forces the server to shutdown in a given timeout - whether it
+// finished outstanding requests or not. if Read/WriteTimeout are not set or the
+// max header size is very big a connection could hang
+func (srv *Server) serverTimeout(d time.Duration) {
+	defer func() {
+		if r := recover(); r != nil {
+			log.Println("WaitGroup at 0", r)
+		}
+	}()
+	if srv.state != StateShuttingDown {
+		return
+	}
+	time.Sleep(d)
+	log.Println("[STOP - Hammer Time] Forcefully shutting down parent")
+	for {
+		if srv.state == StateTerminate {
+			break
+		}
+		srv.wg.Done()
+	}
+}
+
+func (srv *Server) fork() (err error) {
+	regLock.Lock()
+	defer regLock.Unlock()
+	if runningServersForked {
+		return
+	}
+	runningServersForked = true
+
+	var files = make([]*os.File, len(runningServers))
+	var orderArgs = make([]string, len(runningServers))
+	for _, srvPtr := range runningServers {
+		switch srvPtr.GraceListener.(type) {
+		case *graceListener:
+			files[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.GraceListener.(*graceListener).File()
+		default:
+			files[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.tlsInnerListener.File()
+		}
+		orderArgs[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.Server.Addr
+	}
+
+	log.Println(files)
+	path := os.Args[0]
+	var args []string
+	if len(os.Args) > 1 {
+		for _, arg := range os.Args[1:] {
+			if arg == "-graceful" {
+				break
+			}
+			args = append(args, arg)
+		}
+	}
+	args = append(args, "-graceful")
+	if len(runningServers) > 1 {
+		args = append(args, fmt.Sprintf(`-socketorder=%s`, strings.Join(orderArgs, ",")))
+		log.Println(args)
+	}
+	cmd := exec.Command(path, args...)
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	cmd.ExtraFiles = files
+	err = cmd.Start()
+	if err != nil {
+		log.Fatalf("Restart: Failed to launch, error: %v", err)
+	}
+
+	return
+}
+
+// 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")
+		return
+	}
+	for _, s := range hookableSignals {
+		if s == sig {
+			srv.SignalHooks[ppFlag][sig] = append(srv.SignalHooks[ppFlag][sig], f)
+			return
+		}
+	}
+	err = fmt.Errorf("Signal '%v' is not supported", sig)
+	return
+}

+ 103 - 0
vendor/github.com/astaxie/beego/hooks.go

@@ -0,0 +1,103 @@
+package beego
+
+import (
+	"encoding/json"
+	"mime"
+	"net/http"
+	"path/filepath"
+
+	"github.com/astaxie/beego/context"
+	"github.com/astaxie/beego/logs"
+	"github.com/astaxie/beego/session"
+)
+
+//
+func registerMime() error {
+	for k, v := range mimemaps {
+		mime.AddExtensionType(k, v)
+	}
+	return nil
+}
+
+// register default error http handlers, 404,401,403,500 and 503.
+func registerDefaultErrorHandler() error {
+	m := map[string]func(http.ResponseWriter, *http.Request){
+		"401": unauthorized,
+		"402": paymentRequired,
+		"403": forbidden,
+		"404": notFound,
+		"405": methodNotAllowed,
+		"500": internalServerError,
+		"501": notImplemented,
+		"502": badGateway,
+		"503": serviceUnavailable,
+		"504": gatewayTimeout,
+		"417": invalidxsrf,
+		"422": missingxsrf,
+	}
+	for e, h := range m {
+		if _, ok := ErrorMaps[e]; !ok {
+			ErrorHandler(e, h)
+		}
+	}
+	return nil
+}
+
+func registerSession() error {
+	if BConfig.WebConfig.Session.SessionOn {
+		var err error
+		sessionConfig := AppConfig.String("sessionConfig")
+		conf := new(session.ManagerConfig)
+		if sessionConfig == "" {
+			conf.CookieName = BConfig.WebConfig.Session.SessionName
+			conf.EnableSetCookie = BConfig.WebConfig.Session.SessionAutoSetCookie
+			conf.Gclifetime = BConfig.WebConfig.Session.SessionGCMaxLifetime
+			conf.Secure = BConfig.Listen.EnableHTTPS
+			conf.CookieLifeTime = BConfig.WebConfig.Session.SessionCookieLifeTime
+			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
+		} else {
+			if err = json.Unmarshal([]byte(sessionConfig), conf); err != nil {
+				return err
+			}
+		}
+		if GlobalSessions, err = session.NewManager(BConfig.WebConfig.Session.SessionProvider, conf); err != nil {
+			return err
+		}
+		go GlobalSessions.GC()
+	}
+	return nil
+}
+
+func registerTemplate() error {
+	defer lockViewPaths()
+	if err := AddViewPath(BConfig.WebConfig.ViewsPath); err != nil {
+		if BConfig.RunMode == DEV {
+			logs.Warn(err)
+		}
+		return err
+	}
+	return nil
+}
+
+func registerAdmin() error {
+	if BConfig.Listen.EnableAdmin {
+		go beeAdminApp.Run()
+	}
+	return nil
+}
+
+func registerGzip() error {
+	if BConfig.EnableGzip {
+		context.InitGzip(
+			AppConfig.DefaultInt("gzipMinLength", -1),
+			AppConfig.DefaultInt("gzipCompressLevel", -1),
+			AppConfig.DefaultStrings("includedMethods", []string{"GET"}),
+		)
+	}
+	return nil
+}

+ 97 - 0
vendor/github.com/astaxie/beego/httplib/README.md

@@ -0,0 +1,97 @@
+# httplib
+httplib is an libs help you to curl remote url.
+
+# How to use?
+
+## GET
+you can use Get to crawl data.
+
+	import "github.com/astaxie/beego/httplib"
+	
+	str, err := httplib.Get("http://beego.me/").String()
+	if err != nil {
+        	// error
+	}
+	fmt.Println(str)
+	
+## POST
+POST data to remote url
+
+	req := httplib.Post("http://beego.me/")
+	req.Param("username","astaxie")
+	req.Param("password","123456")
+	str, err := req.String()
+	if err != nil {
+        	// error
+	}
+	fmt.Println(str)
+
+## Set timeout
+
+The default timeout is `60` seconds, function prototype:
+
+	SetTimeout(connectTimeout, readWriteTimeout time.Duration)
+
+Example:
+
+	// GET
+	httplib.Get("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second)
+	
+	// POST
+	httplib.Post("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second)
+
+
+## Debug
+
+If you want to debug the request info, set the debug on
+
+	httplib.Get("http://beego.me/").Debug(true)
+	
+## Set HTTP Basic Auth
+
+	str, err := Get("http://beego.me/").SetBasicAuth("user", "passwd").String()
+	if err != nil {
+        	// error
+	}
+	fmt.Println(str)
+	
+## Set HTTPS
+
+If request url is https, You can set the client support TSL:
+
+	httplib.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
+	
+More info about the `tls.Config` please visit http://golang.org/pkg/crypto/tls/#Config	
+
+## Set HTTP Version
+
+some servers need to specify the protocol version of HTTP
+
+	httplib.Get("http://beego.me/").SetProtocolVersion("HTTP/1.1")
+	
+## Set Cookie
+
+some http request need setcookie. So set it like this:
+
+	cookie := &http.Cookie{}
+	cookie.Name = "username"
+	cookie.Value  = "astaxie"
+	httplib.Get("http://beego.me/").SetCookie(cookie)
+
+## Upload file
+
+httplib support mutil file upload, use `req.PostFile()`
+
+	req := httplib.Post("http://beego.me/")
+	req.Param("username","astaxie")
+	req.PostFile("uploadfile1", "httplib.pdf")
+	str, err := req.String()
+	if err != nil {
+        	// error
+	}
+	fmt.Println(str)
+
+
+See godoc for further documentation and examples.
+
+* [godoc.org/github.com/astaxie/beego/httplib](https://godoc.org/github.com/astaxie/beego/httplib)

+ 585 - 0
vendor/github.com/astaxie/beego/httplib/httplib.go

@@ -0,0 +1,585 @@
+// 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 httplib is used as http.Client
+// Usage:
+//
+// import "github.com/astaxie/beego/httplib"
+//
+//	b := httplib.Post("http://beego.me/")
+//	b.Param("username","astaxie")
+//	b.Param("password","123456")
+//	b.PostFile("uploadfile1", "httplib.pdf")
+//	b.PostFile("uploadfile2", "httplib.txt")
+//	str, err := b.String()
+//	if err != nil {
+//		t.Fatal(err)
+//	}
+//	fmt.Println(str)
+//
+//  more docs http://beego.me/docs/module/httplib.md
+package httplib
+
+import (
+	"bytes"
+	"compress/gzip"
+	"crypto/tls"
+	"encoding/json"
+	"encoding/xml"
+	"io"
+	"io/ioutil"
+	"log"
+	"mime/multipart"
+	"net"
+	"net/http"
+	"net/http/cookiejar"
+	"net/http/httputil"
+	"net/url"
+	"os"
+	"strings"
+	"sync"
+	"time"
+)
+
+var defaultSetting = BeegoHTTPSettings{
+	UserAgent:        "beegoServer",
+	ConnectTimeout:   60 * time.Second,
+	ReadWriteTimeout: 60 * time.Second,
+	Gzip:             true,
+	DumpBody:         true,
+}
+
+var defaultCookieJar http.CookieJar
+var settingMutex sync.Mutex
+
+// createDefaultCookie creates a global cookiejar to store cookies.
+func createDefaultCookie() {
+	settingMutex.Lock()
+	defer settingMutex.Unlock()
+	defaultCookieJar, _ = cookiejar.New(nil)
+}
+
+// SetDefaultSetting Overwrite default settings
+func SetDefaultSetting(setting BeegoHTTPSettings) {
+	settingMutex.Lock()
+	defer settingMutex.Unlock()
+	defaultSetting = setting
+}
+
+// NewBeegoRequest return *BeegoHttpRequest with specific method
+func NewBeegoRequest(rawurl, method string) *BeegoHTTPRequest {
+	var resp http.Response
+	u, err := url.Parse(rawurl)
+	if err != nil {
+		log.Println("Httplib:", err)
+	}
+	req := http.Request{
+		URL:        u,
+		Method:     method,
+		Header:     make(http.Header),
+		Proto:      "HTTP/1.1",
+		ProtoMajor: 1,
+		ProtoMinor: 1,
+	}
+	return &BeegoHTTPRequest{
+		url:     rawurl,
+		req:     &req,
+		params:  map[string][]string{},
+		files:   map[string]string{},
+		setting: defaultSetting,
+		resp:    &resp,
+	}
+}
+
+// Get returns *BeegoHttpRequest with GET method.
+func Get(url string) *BeegoHTTPRequest {
+	return NewBeegoRequest(url, "GET")
+}
+
+// Post returns *BeegoHttpRequest with POST method.
+func Post(url string) *BeegoHTTPRequest {
+	return NewBeegoRequest(url, "POST")
+}
+
+// Put returns *BeegoHttpRequest with PUT method.
+func Put(url string) *BeegoHTTPRequest {
+	return NewBeegoRequest(url, "PUT")
+}
+
+// Delete returns *BeegoHttpRequest DELETE method.
+func Delete(url string) *BeegoHTTPRequest {
+	return NewBeegoRequest(url, "DELETE")
+}
+
+// Head returns *BeegoHttpRequest with HEAD method.
+func Head(url string) *BeegoHTTPRequest {
+	return NewBeegoRequest(url, "HEAD")
+}
+
+// BeegoHTTPSettings is the http.Client setting
+type BeegoHTTPSettings struct {
+	ShowDebug        bool
+	UserAgent        string
+	ConnectTimeout   time.Duration
+	ReadWriteTimeout time.Duration
+	TLSClientConfig  *tls.Config
+	Proxy            func(*http.Request) (*url.URL, error)
+	Transport        http.RoundTripper
+	CheckRedirect    func(req *http.Request, via []*http.Request) error
+	EnableCookie     bool
+	Gzip             bool
+	DumpBody         bool
+	Retries          int // if set to -1 means will retry forever
+}
+
+// BeegoHTTPRequest provides more useful methods for requesting one url than http.Request.
+type BeegoHTTPRequest struct {
+	url     string
+	req     *http.Request
+	params  map[string][]string
+	files   map[string]string
+	setting BeegoHTTPSettings
+	resp    *http.Response
+	body    []byte
+	dump    []byte
+}
+
+// GetRequest return the request object
+func (b *BeegoHTTPRequest) GetRequest() *http.Request {
+	return b.req
+}
+
+// Setting Change request settings
+func (b *BeegoHTTPRequest) Setting(setting BeegoHTTPSettings) *BeegoHTTPRequest {
+	b.setting = setting
+	return b
+}
+
+// SetBasicAuth sets the request's Authorization header to use HTTP Basic Authentication with the provided username and password.
+func (b *BeegoHTTPRequest) SetBasicAuth(username, password string) *BeegoHTTPRequest {
+	b.req.SetBasicAuth(username, password)
+	return b
+}
+
+// SetEnableCookie sets enable/disable cookiejar
+func (b *BeegoHTTPRequest) SetEnableCookie(enable bool) *BeegoHTTPRequest {
+	b.setting.EnableCookie = enable
+	return b
+}
+
+// SetUserAgent sets User-Agent header field
+func (b *BeegoHTTPRequest) SetUserAgent(useragent string) *BeegoHTTPRequest {
+	b.setting.UserAgent = useragent
+	return b
+}
+
+// Debug sets show debug or not when executing request.
+func (b *BeegoHTTPRequest) Debug(isdebug bool) *BeegoHTTPRequest {
+	b.setting.ShowDebug = isdebug
+	return b
+}
+
+// Retries sets Retries times.
+// default is 0 means no retried.
+// -1 means retried forever.
+// others means retried times.
+func (b *BeegoHTTPRequest) Retries(times int) *BeegoHTTPRequest {
+	b.setting.Retries = times
+	return b
+}
+
+// DumpBody setting whether need to Dump the Body.
+func (b *BeegoHTTPRequest) DumpBody(isdump bool) *BeegoHTTPRequest {
+	b.setting.DumpBody = isdump
+	return b
+}
+
+// DumpRequest return the DumpRequest
+func (b *BeegoHTTPRequest) DumpRequest() []byte {
+	return b.dump
+}
+
+// SetTimeout sets connect time out and read-write time out for BeegoRequest.
+func (b *BeegoHTTPRequest) SetTimeout(connectTimeout, readWriteTimeout time.Duration) *BeegoHTTPRequest {
+	b.setting.ConnectTimeout = connectTimeout
+	b.setting.ReadWriteTimeout = readWriteTimeout
+	return b
+}
+
+// SetTLSClientConfig sets tls connection configurations if visiting https url.
+func (b *BeegoHTTPRequest) SetTLSClientConfig(config *tls.Config) *BeegoHTTPRequest {
+	b.setting.TLSClientConfig = config
+	return b
+}
+
+// Header add header item string in request.
+func (b *BeegoHTTPRequest) Header(key, value string) *BeegoHTTPRequest {
+	b.req.Header.Set(key, value)
+	return b
+}
+
+// SetHost set the request host
+func (b *BeegoHTTPRequest) SetHost(host string) *BeegoHTTPRequest {
+	b.req.Host = host
+	return b
+}
+
+// SetProtocolVersion Set the protocol version for incoming requests.
+// Client requests always use HTTP/1.1.
+func (b *BeegoHTTPRequest) SetProtocolVersion(vers string) *BeegoHTTPRequest {
+	if len(vers) == 0 {
+		vers = "HTTP/1.1"
+	}
+
+	major, minor, ok := http.ParseHTTPVersion(vers)
+	if ok {
+		b.req.Proto = vers
+		b.req.ProtoMajor = major
+		b.req.ProtoMinor = minor
+	}
+
+	return b
+}
+
+// SetCookie add cookie into request.
+func (b *BeegoHTTPRequest) SetCookie(cookie *http.Cookie) *BeegoHTTPRequest {
+	b.req.Header.Add("Cookie", cookie.String())
+	return b
+}
+
+// SetTransport set the setting transport
+func (b *BeegoHTTPRequest) SetTransport(transport http.RoundTripper) *BeegoHTTPRequest {
+	b.setting.Transport = transport
+	return b
+}
+
+// SetProxy set the http proxy
+// example:
+//
+//	func(req *http.Request) (*url.URL, error) {
+// 		u, _ := url.ParseRequestURI("http://127.0.0.1:8118")
+// 		return u, nil
+// 	}
+func (b *BeegoHTTPRequest) SetProxy(proxy func(*http.Request) (*url.URL, error)) *BeegoHTTPRequest {
+	b.setting.Proxy = proxy
+	return b
+}
+
+// SetCheckRedirect specifies the policy for handling redirects.
+//
+// If CheckRedirect is nil, the Client uses its default policy,
+// which is to stop after 10 consecutive requests.
+func (b *BeegoHTTPRequest) SetCheckRedirect(redirect func(req *http.Request, via []*http.Request) error) *BeegoHTTPRequest {
+	b.setting.CheckRedirect = redirect
+	return b
+}
+
+// Param adds query param in to request.
+// params build query string as ?key1=value1&key2=value2...
+func (b *BeegoHTTPRequest) Param(key, value string) *BeegoHTTPRequest {
+	if param, ok := b.params[key]; ok {
+		b.params[key] = append(param, value)
+	} else {
+		b.params[key] = []string{value}
+	}
+	return b
+}
+
+// PostFile add a post file to the request
+func (b *BeegoHTTPRequest) PostFile(formname, filename string) *BeegoHTTPRequest {
+	b.files[formname] = filename
+	return b
+}
+
+// Body adds request raw body.
+// it supports string and []byte.
+func (b *BeegoHTTPRequest) Body(data interface{}) *BeegoHTTPRequest {
+	switch t := data.(type) {
+	case string:
+		bf := bytes.NewBufferString(t)
+		b.req.Body = ioutil.NopCloser(bf)
+		b.req.ContentLength = int64(len(t))
+	case []byte:
+		bf := bytes.NewBuffer(t)
+		b.req.Body = ioutil.NopCloser(bf)
+		b.req.ContentLength = int64(len(t))
+	}
+	return b
+}
+
+// JSONBody adds request raw body encoding by JSON.
+func (b *BeegoHTTPRequest) JSONBody(obj interface{}) (*BeegoHTTPRequest, error) {
+	if b.req.Body == nil && obj != nil {
+		byts, err := json.Marshal(obj)
+		if err != nil {
+			return b, err
+		}
+		b.req.Body = ioutil.NopCloser(bytes.NewReader(byts))
+		b.req.ContentLength = int64(len(byts))
+		b.req.Header.Set("Content-Type", "application/json")
+	}
+	return b, nil
+}
+
+func (b *BeegoHTTPRequest) buildURL(paramBody string) {
+	// build GET url with query string
+	if b.req.Method == "GET" && len(paramBody) > 0 {
+		if strings.Contains(b.url, "?") {
+			b.url += "&" + paramBody
+		} else {
+			b.url = b.url + "?" + paramBody
+		}
+		return
+	}
+
+	// build POST/PUT/PATCH url and body
+	if (b.req.Method == "POST" || b.req.Method == "PUT" || b.req.Method == "PATCH" || b.req.Method == "DELETE") && b.req.Body == nil {
+		// with files
+		if len(b.files) > 0 {
+			pr, pw := io.Pipe()
+			bodyWriter := multipart.NewWriter(pw)
+			go func() {
+				for formname, filename := range b.files {
+					fileWriter, err := bodyWriter.CreateFormFile(formname, filename)
+					if err != nil {
+						log.Println("Httplib:", err)
+					}
+					fh, err := os.Open(filename)
+					if err != nil {
+						log.Println("Httplib:", err)
+					}
+					//iocopy
+					_, err = io.Copy(fileWriter, fh)
+					fh.Close()
+					if err != nil {
+						log.Println("Httplib:", err)
+					}
+				}
+				for k, v := range b.params {
+					for _, vv := range v {
+						bodyWriter.WriteField(k, vv)
+					}
+				}
+				bodyWriter.Close()
+				pw.Close()
+			}()
+			b.Header("Content-Type", bodyWriter.FormDataContentType())
+			b.req.Body = ioutil.NopCloser(pr)
+			return
+		}
+
+		// with params
+		if len(paramBody) > 0 {
+			b.Header("Content-Type", "application/x-www-form-urlencoded")
+			b.Body(paramBody)
+		}
+	}
+}
+
+func (b *BeegoHTTPRequest) getResponse() (*http.Response, error) {
+	if b.resp.StatusCode != 0 {
+		return b.resp, nil
+	}
+	resp, err := b.DoRequest()
+	if err != nil {
+		return nil, err
+	}
+	b.resp = resp
+	return resp, nil
+}
+
+// DoRequest will do the client.Do
+func (b *BeegoHTTPRequest) DoRequest() (resp *http.Response, err error) {
+	var paramBody string
+	if len(b.params) > 0 {
+		var buf bytes.Buffer
+		for k, v := range b.params {
+			for _, vv := range v {
+				buf.WriteString(url.QueryEscape(k))
+				buf.WriteByte('=')
+				buf.WriteString(url.QueryEscape(vv))
+				buf.WriteByte('&')
+			}
+		}
+		paramBody = buf.String()
+		paramBody = paramBody[0 : len(paramBody)-1]
+	}
+
+	b.buildURL(paramBody)
+	url, err := url.Parse(b.url)
+	if err != nil {
+		return nil, err
+	}
+
+	b.req.URL = url
+
+	trans := b.setting.Transport
+
+	if trans == nil {
+		// create default transport
+		trans = &http.Transport{
+			TLSClientConfig:     b.setting.TLSClientConfig,
+			Proxy:               b.setting.Proxy,
+			Dial:                TimeoutDialer(b.setting.ConnectTimeout, b.setting.ReadWriteTimeout),
+			MaxIdleConnsPerHost: -1,
+		}
+	} else {
+		// if b.transport is *http.Transport then set the settings.
+		if t, ok := trans.(*http.Transport); ok {
+			if t.TLSClientConfig == nil {
+				t.TLSClientConfig = b.setting.TLSClientConfig
+			}
+			if t.Proxy == nil {
+				t.Proxy = b.setting.Proxy
+			}
+			if t.Dial == nil {
+				t.Dial = TimeoutDialer(b.setting.ConnectTimeout, b.setting.ReadWriteTimeout)
+			}
+		}
+	}
+
+	var jar http.CookieJar
+	if b.setting.EnableCookie {
+		if defaultCookieJar == nil {
+			createDefaultCookie()
+		}
+		jar = defaultCookieJar
+	}
+
+	client := &http.Client{
+		Transport: trans,
+		Jar:       jar,
+	}
+
+	if b.setting.UserAgent != "" && b.req.Header.Get("User-Agent") == "" {
+		b.req.Header.Set("User-Agent", b.setting.UserAgent)
+	}
+
+	if b.setting.CheckRedirect != nil {
+		client.CheckRedirect = b.setting.CheckRedirect
+	}
+
+	if b.setting.ShowDebug {
+		dump, err := httputil.DumpRequest(b.req, b.setting.DumpBody)
+		if err != nil {
+			log.Println(err.Error())
+		}
+		b.dump = dump
+	}
+	// retries default value is 0, it will run once.
+	// retries equal to -1, it will run forever until success
+	// retries is setted, it will retries fixed times.
+	for i := 0; b.setting.Retries == -1 || i <= b.setting.Retries; i++ {
+		resp, err = client.Do(b.req)
+		if err == nil {
+			break
+		}
+	}
+	return resp, err
+}
+
+// String returns the body string in response.
+// it calls Response inner.
+func (b *BeegoHTTPRequest) String() (string, error) {
+	data, err := b.Bytes()
+	if err != nil {
+		return "", err
+	}
+
+	return string(data), nil
+}
+
+// Bytes returns the body []byte in response.
+// it calls Response inner.
+func (b *BeegoHTTPRequest) Bytes() ([]byte, error) {
+	if b.body != nil {
+		return b.body, nil
+	}
+	resp, err := b.getResponse()
+	if err != nil {
+		return nil, err
+	}
+	if resp.Body == nil {
+		return nil, nil
+	}
+	defer resp.Body.Close()
+	if b.setting.Gzip && resp.Header.Get("Content-Encoding") == "gzip" {
+		reader, err := gzip.NewReader(resp.Body)
+		if err != nil {
+			return nil, err
+		}
+		b.body, err = ioutil.ReadAll(reader)
+		return b.body, err
+	}
+	b.body, err = ioutil.ReadAll(resp.Body)
+	return b.body, err
+}
+
+// ToFile saves the body data in response to one file.
+// it calls Response inner.
+func (b *BeegoHTTPRequest) ToFile(filename string) error {
+	f, err := os.Create(filename)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	resp, err := b.getResponse()
+	if err != nil {
+		return err
+	}
+	if resp.Body == nil {
+		return nil
+	}
+	defer resp.Body.Close()
+	_, err = io.Copy(f, resp.Body)
+	return err
+}
+
+// ToJSON returns the map that marshals from the body bytes as json in response .
+// it calls Response inner.
+func (b *BeegoHTTPRequest) ToJSON(v interface{}) error {
+	data, err := b.Bytes()
+	if err != nil {
+		return err
+	}
+	return json.Unmarshal(data, v)
+}
+
+// ToXML returns the map that marshals from the body bytes as xml in response .
+// it calls Response inner.
+func (b *BeegoHTTPRequest) ToXML(v interface{}) error {
+	data, err := b.Bytes()
+	if err != nil {
+		return err
+	}
+	return xml.Unmarshal(data, v)
+}
+
+// Response executes request client gets response mannually.
+func (b *BeegoHTTPRequest) Response() (*http.Response, error) {
+	return b.getResponse()
+}
+
+// TimeoutDialer returns functions of connection dialer with timeout settings for http.Transport Dial field.
+func TimeoutDialer(cTimeout time.Duration, rwTimeout time.Duration) func(net, addr string) (c net.Conn, err error) {
+	return func(netw, addr string) (net.Conn, error) {
+		conn, err := net.DialTimeout(netw, addr, cTimeout)
+		if err != nil {
+			return nil, err
+		}
+		err = conn.SetDeadline(time.Now().Add(rwTimeout))
+		return conn, err
+	}
+}

+ 226 - 0
vendor/github.com/astaxie/beego/httplib/httplib_test.go

@@ -0,0 +1,226 @@
+// 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 httplib
+
+import (
+	"io/ioutil"
+	"os"
+	"strings"
+	"testing"
+	"time"
+)
+
+func TestResponse(t *testing.T) {
+	req := Get("http://httpbin.org/get")
+	resp, err := req.Response()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log(resp)
+}
+
+func TestGet(t *testing.T) {
+	req := Get("http://httpbin.org/get")
+	b, err := req.Bytes()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log(b)
+
+	s, err := req.String()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log(s)
+
+	if string(b) != s {
+		t.Fatal("request data not match")
+	}
+}
+
+func TestSimplePost(t *testing.T) {
+	v := "smallfish"
+	req := Post("http://httpbin.org/post")
+	req.Param("username", v)
+
+	str, err := req.String()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log(str)
+
+	n := strings.Index(str, v)
+	if n == -1 {
+		t.Fatal(v + " not found in post")
+	}
+}
+
+//func TestPostFile(t *testing.T) {
+//	v := "smallfish"
+//	req := Post("http://httpbin.org/post")
+//	req.Debug(true)
+//	req.Param("username", v)
+//	req.PostFile("uploadfile", "httplib_test.go")
+
+//	str, err := req.String()
+//	if err != nil {
+//		t.Fatal(err)
+//	}
+//	t.Log(str)
+
+//	n := strings.Index(str, v)
+//	if n == -1 {
+//		t.Fatal(v + " not found in post")
+//	}
+//}
+
+func TestSimplePut(t *testing.T) {
+	str, err := Put("http://httpbin.org/put").String()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log(str)
+}
+
+func TestSimpleDelete(t *testing.T) {
+	str, err := Delete("http://httpbin.org/delete").String()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log(str)
+}
+
+func TestSimpleDeleteParam(t *testing.T) {
+	str, err := Delete("http://httpbin.org/delete").Param("key", "val").String()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log(str)
+}
+
+func TestWithCookie(t *testing.T) {
+	v := "smallfish"
+	str, err := Get("http://httpbin.org/cookies/set?k1=" + v).SetEnableCookie(true).String()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log(str)
+
+	str, err = Get("http://httpbin.org/cookies").SetEnableCookie(true).String()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log(str)
+
+	n := strings.Index(str, v)
+	if n == -1 {
+		t.Fatal(v + " not found in cookie")
+	}
+}
+
+func TestWithBasicAuth(t *testing.T) {
+	str, err := Get("http://httpbin.org/basic-auth/user/passwd").SetBasicAuth("user", "passwd").String()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log(str)
+	n := strings.Index(str, "authenticated")
+	if n == -1 {
+		t.Fatal("authenticated not found in response")
+	}
+}
+
+func TestWithUserAgent(t *testing.T) {
+	v := "beego"
+	str, err := Get("http://httpbin.org/headers").SetUserAgent(v).String()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log(str)
+
+	n := strings.Index(str, v)
+	if n == -1 {
+		t.Fatal(v + " not found in user-agent")
+	}
+}
+
+func TestWithSetting(t *testing.T) {
+	v := "beego"
+	var setting BeegoHTTPSettings
+	setting.EnableCookie = true
+	setting.UserAgent = v
+	setting.Transport = nil
+	setting.ReadWriteTimeout = 5 * time.Second
+	SetDefaultSetting(setting)
+
+	str, err := Get("http://httpbin.org/get").String()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log(str)
+
+	n := strings.Index(str, v)
+	if n == -1 {
+		t.Fatal(v + " not found in user-agent")
+	}
+}
+
+func TestToJson(t *testing.T) {
+	req := Get("http://httpbin.org/ip")
+	resp, err := req.Response()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log(resp)
+
+	// httpbin will return http remote addr
+	type IP struct {
+		Origin string `json:"origin"`
+	}
+	var ip IP
+	err = req.ToJSON(&ip)
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log(ip.Origin)
+
+	if n := strings.Count(ip.Origin, "."); n != 3 {
+		t.Fatal("response is not valid ip")
+	}
+}
+
+func TestToFile(t *testing.T) {
+	f := "beego_testfile"
+	req := Get("http://httpbin.org/ip")
+	err := req.ToFile(f)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.Remove(f)
+	b, err := ioutil.ReadFile(f)
+	if n := strings.Index(string(b), "origin"); n == -1 {
+		t.Fatal(err)
+	}
+}
+
+func TestHeader(t *testing.T) {
+	req := Get("http://httpbin.org/headers")
+	req.Header("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36")
+	str, err := req.String()
+	if err != nil {
+		t.Fatal(err)
+	}
+	t.Log(str)
+}

+ 111 - 0
vendor/github.com/astaxie/beego/log.go

@@ -0,0 +1,111 @@
+// 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 beego
+
+import (
+	"strings"
+
+	"github.com/astaxie/beego/logs"
+)
+
+// Log levels to control the logging output.
+const (
+	LevelEmergency = iota
+	LevelAlert
+	LevelCritical
+	LevelError
+	LevelWarning
+	LevelNotice
+	LevelInformational
+	LevelDebug
+)
+
+// BeeLogger references the used application logger.
+var BeeLogger = logs.GetBeeLogger()
+
+// SetLevel sets the global log level used by the simple logger.
+func SetLevel(l int) {
+	logs.SetLevel(l)
+}
+
+// SetLogFuncCall set the CallDepth, default is 3
+func SetLogFuncCall(b bool) {
+	logs.SetLogFuncCall(b)
+}
+
+// SetLogger sets a new logger.
+func SetLogger(adaptername string, config string) error {
+	return logs.SetLogger(adaptername, config)
+}
+
+// Emergency logs a message at emergency level.
+func Emergency(v ...interface{}) {
+	logs.Emergency(generateFmtStr(len(v)), v...)
+}
+
+// Alert logs a message at alert level.
+func Alert(v ...interface{}) {
+	logs.Alert(generateFmtStr(len(v)), v...)
+}
+
+// Critical logs a message at critical level.
+func Critical(v ...interface{}) {
+	logs.Critical(generateFmtStr(len(v)), v...)
+}
+
+// Error logs a message at error level.
+func Error(v ...interface{}) {
+	logs.Error(generateFmtStr(len(v)), v...)
+}
+
+// Warning logs a message at warning level.
+func Warning(v ...interface{}) {
+	logs.Warning(generateFmtStr(len(v)), v...)
+}
+
+// Warn compatibility alias for Warning()
+func Warn(v ...interface{}) {
+	logs.Warn(generateFmtStr(len(v)), v...)
+}
+
+// Notice logs a message at notice level.
+func Notice(v ...interface{}) {
+	logs.Notice(generateFmtStr(len(v)), v...)
+}
+
+// Informational logs a message at info level.
+func Informational(v ...interface{}) {
+	logs.Informational(generateFmtStr(len(v)), v...)
+}
+
+// Info compatibility alias for Warning()
+func Info(v ...interface{}) {
+	logs.Info(generateFmtStr(len(v)), v...)
+}
+
+// Debug logs a message at debug level.
+func Debug(v ...interface{}) {
+	logs.Debug(generateFmtStr(len(v)), v...)
+}
+
+// Trace logs a message at trace level.
+// compatibility alias for Warning()
+func Trace(v ...interface{}) {
+	logs.Trace(generateFmtStr(len(v)), v...)
+}
+
+func generateFmtStr(n int) string {
+	return strings.Repeat("%v ", n)
+}

+ 63 - 0
vendor/github.com/astaxie/beego/logs/README.md

@@ -0,0 +1,63 @@
+## logs
+logs is a Go logs manager. It can use many logs adapters. The repo is inspired by `database/sql` .
+
+
+## How to install?
+
+	go get github.com/astaxie/beego/logs
+
+
+## What adapters are supported?
+
+As of now this logs support console, file,smtp and conn.
+
+
+## How to use it?
+
+First you must import it
+
+	import (
+		"github.com/astaxie/beego/logs"
+	)
+
+Then init a Log (example with console adapter)
+
+	log := NewLogger(10000)
+	log.SetLogger("console", "")	
+
+> the first params stand for how many channel
+
+Use it like this:	
+	
+	log.Trace("trace")
+	log.Info("info")
+	log.Warn("warning")
+	log.Debug("debug")
+	log.Critical("critical")
+
+
+## File adapter
+
+Configure file adapter like this:
+
+	log := NewLogger(10000)
+	log.SetLogger("file", `{"filename":"test.log"}`)
+
+
+## Conn adapter
+
+Configure like this:
+
+	log := NewLogger(1000)
+	log.SetLogger("conn", `{"net":"tcp","addr":":7020"}`)
+	log.Info("info")
+
+
+## Smtp adapter
+
+Configure like this:
+
+	log := NewLogger(10000)
+	log.SetLogger("smtp", `{"username":"[email protected]","password":"xxxxxxxx","host":"smtp.gmail.com:587","sendTos":["[email protected]"]}`)
+	log.Critical("sendmail critical")
+	time.Sleep(time.Second * 30)

+ 186 - 0
vendor/github.com/astaxie/beego/logs/alils/alils.go

@@ -0,0 +1,186 @@
+package alils
+
+import (
+	"encoding/json"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/astaxie/beego/logs"
+	"github.com/gogo/protobuf/proto"
+)
+
+const (
+	// CacheSize set the flush size
+	CacheSize int = 64
+	// Delimiter define the topic delimiter
+	Delimiter string = "##"
+)
+
+// Config is the Config for Ali Log
+type Config struct {
+	Project   string   `json:"project"`
+	Endpoint  string   `json:"endpoint"`
+	KeyID     string   `json:"key_id"`
+	KeySecret string   `json:"key_secret"`
+	LogStore  string   `json:"log_store"`
+	Topics    []string `json:"topics"`
+	Source    string   `json:"source"`
+	Level     int      `json:"level"`
+	FlushWhen int      `json:"flush_when"`
+}
+
+// aliLSWriter implements LoggerInterface.
+// it writes messages in keep-live tcp connection.
+type aliLSWriter struct {
+	store    *LogStore
+	group    []*LogGroup
+	withMap  bool
+	groupMap map[string]*LogGroup
+	lock     *sync.Mutex
+	Config
+}
+
+// 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)
+
+	if c.FlushWhen > CacheSize {
+		c.FlushWhen = CacheSize
+	}
+
+	prj := &LogProject{
+		Name:            c.Project,
+		Endpoint:        c.Endpoint,
+		AccessKeyID:     c.KeyID,
+		AccessKeySecret: c.KeySecret,
+	}
+
+	c.store, err = prj.GetLogStore(c.LogStore)
+	if err != nil {
+		return err
+	}
+
+	// Create default Log Group
+	c.group = append(c.group, &LogGroup{
+		Topic:  proto.String(""),
+		Source: proto.String(c.Source),
+		Logs:   make([]*Log, 0, c.FlushWhen),
+	})
+
+	// Create other Log Group
+	c.groupMap = make(map[string]*LogGroup)
+	for _, topic := range c.Topics {
+
+		lg := &LogGroup{
+			Topic:  proto.String(topic),
+			Source: proto.String(c.Source),
+			Logs:   make([]*Log, 0, c.FlushWhen),
+		}
+
+		c.group = append(c.group, lg)
+		c.groupMap[topic] = lg
+	}
+
+	if len(c.group) == 1 {
+		c.withMap = false
+	} else {
+		c.withMap = true
+	}
+
+	c.lock = &sync.Mutex{}
+
+	return nil
+}
+
+// WriteMsg write message in connection.
+// if connection is down, try to re-connect.
+func (c *aliLSWriter) WriteMsg(when time.Time, msg string, level int) (err error) {
+
+	if level > c.Level {
+		return nil
+	}
+
+	var topic string
+	var content string
+	var lg *LogGroup
+	if c.withMap {
+
+		// Topic,LogGroup
+		strs := strings.SplitN(msg, Delimiter, 2)
+		if len(strs) == 2 {
+			pos := strings.LastIndex(strs[0], " ")
+			topic = strs[0][pos+1 : len(strs[0])]
+			content = strs[0][0:pos] + strs[1]
+			lg = c.groupMap[topic]
+		}
+
+		// send to empty Topic
+		if lg == nil {
+			content = msg
+			lg = c.group[0]
+		}
+	} else {
+		content = msg
+		lg = c.group[0]
+	}
+
+	c1 := &LogContent{
+		Key:   proto.String("msg"),
+		Value: proto.String(content),
+	}
+
+	l := &Log{
+		Time: proto.Uint32(uint32(when.Unix())),
+		Contents: []*LogContent{
+			c1,
+		},
+	}
+
+	c.lock.Lock()
+	lg.Logs = append(lg.Logs, l)
+	c.lock.Unlock()
+
+	if len(lg.Logs) >= c.FlushWhen {
+		c.flush(lg)
+	}
+
+	return nil
+}
+
+// Flush implementing method. empty.
+func (c *aliLSWriter) Flush() {
+
+	// flush all group
+	for _, lg := range c.group {
+		c.flush(lg)
+	}
+}
+
+// Destroy destroy connection writer and close tcp listener.
+func (c *aliLSWriter) Destroy() {
+}
+
+func (c *aliLSWriter) flush(lg *LogGroup) {
+
+	c.lock.Lock()
+	defer c.lock.Unlock()
+	err := c.store.PutLogs(lg)
+	if err != nil {
+		return
+	}
+
+	lg.Logs = make([]*Log, 0, c.FlushWhen)
+}
+
+func init() {
+	logs.Register(logs.AdapterAliLS, NewAliLS)
+}

+ 13 - 0
vendor/github.com/astaxie/beego/logs/alils/config.go

@@ -0,0 +1,13 @@
+package alils
+
+const (
+	version         = "0.5.0"     // SDK version
+	signatureMethod = "hmac-sha1" // Signature method
+
+	// OffsetNewest stands for the log head offset, i.e. the offset that will be
+	// assigned to the next message that will be produced to the shard.
+	OffsetNewest = "end"
+	// OffsetOldest stands for the oldest offset available on the logstore for a
+	// shard.
+	OffsetOldest = "begin"
+)

+ 1038 - 0
vendor/github.com/astaxie/beego/logs/alils/log.pb.go

@@ -0,0 +1,1038 @@
+package alils
+
+import (
+	"fmt"
+	"io"
+	"math"
+
+	"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        []*LogContent `protobuf:"bytes,2,rep,name=Contents" json:"Contents,omitempty"`
+	XXXUnrecognized []byte        `json:"-"`
+}
+
+// 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
+	}
+	return 0
+}
+
+// GetContents return the Log's Contents
+func (m *Log) GetContents() []*LogContent {
+	if m != nil {
+		return m.Contents
+	}
+	return nil
+}
+
+// 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:"-"`
+}
+
+// Reset LogContent
+func (m *LogContent) Reset() { *m = LogContent{} }
+
+// 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 ""
+}
+
+// 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"`
+	XXXUnrecognized []byte  `json:"-"`
+}
+
+// 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
+	}
+	return nil
+}
+
+// GetReserved return Reserved
+func (m *LogGroup) GetReserved() string {
+	if m != nil && m.Reserved != nil {
+		return *m.Reserved
+	}
+	return ""
+}
+
+// GetTopic return Topic
+func (m *LogGroup) GetTopic() string {
+	if m != nil && m.Topic != nil {
+		return *m.Topic
+	}
+	return ""
+}
+
+// GetSource return Source
+func (m *LogGroup) GetSource() string {
+	if m != nil && m.Source != nil {
+		return *m.Source
+	}
+	return ""
+}
+
+// LogGroupList define the LogGroups
+type LogGroupList struct {
+	LogGroups       []*LogGroup `protobuf:"bytes,1,rep,name=logGroups" json:"logGroups,omitempty"`
+	XXXUnrecognized []byte      `json:"-"`
+}
+
+// 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
+	}
+	return nil
+}
+
+// Marshal the logs to byte slice
+func (m *Log) Marshal() (data []byte, err error) {
+	size := m.Size()
+	data = make([]byte, size)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+// MarshalTo data
+func (m *Log) MarshalTo(data []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if m.Time == nil {
+		return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("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
+			i++
+			i = encodeVarintLog(data, i, uint64(msg.Size()))
+			n, err := msg.MarshalTo(data[i:])
+			if err != nil {
+				return 0, err
+			}
+			i += n
+		}
+	}
+	if m.XXXUnrecognized != nil {
+		i += copy(data[i:], m.XXXUnrecognized)
+	}
+	return i, nil
+}
+
+// Marshal LogContent
+func (m *LogContent) Marshal() (data []byte, err error) {
+	size := m.Size()
+	data = make([]byte, size)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+// 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")
+	}
+	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")
+	}
+	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)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+// MarshalTo LogGroup to data
+func (m *LogGroup) MarshalTo(data []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if len(m.Logs) > 0 {
+		for _, msg := range m.Logs {
+			data[i] = 0xa
+			i++
+			i = encodeVarintLog(data, i, uint64(msg.Size()))
+			n, err := msg.MarshalTo(data[i:])
+			if err != nil {
+				return 0, err
+			}
+			i += n
+		}
+	}
+	if m.Reserved != nil {
+		data[i] = 0x12
+		i++
+		i = encodeVarintLog(data, i, uint64(len(*m.Reserved)))
+		i += copy(data[i:], *m.Reserved)
+	}
+	if m.Topic != nil {
+		data[i] = 0x1a
+		i++
+		i = encodeVarintLog(data, i, uint64(len(*m.Topic)))
+		i += copy(data[i:], *m.Topic)
+	}
+	if m.Source != nil {
+		data[i] = 0x22
+		i++
+		i = encodeVarintLog(data, i, uint64(len(*m.Source)))
+		i += copy(data[i:], *m.Source)
+	}
+	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)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+// MarshalTo LogGroupList to data
+func (m *LogGroupList) MarshalTo(data []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if len(m.LogGroups) > 0 {
+		for _, msg := range m.LogGroups {
+			data[i] = 0xa
+			i++
+			i = encodeVarintLog(data, i, uint64(msg.Size()))
+			n, err := msg.MarshalTo(data[i:])
+			if err != nil {
+				return 0, err
+			}
+			i += n
+		}
+	}
+	if m.XXXUnrecognized != nil {
+		i += copy(data[i:], m.XXXUnrecognized)
+	}
+	return i, nil
+}
+
+func encodeFixed64Log(data []byte, offset int, v uint64) int {
+	data[offset] = uint8(v)
+	data[offset+1] = uint8(v >> 8)
+	data[offset+2] = uint8(v >> 16)
+	data[offset+3] = uint8(v >> 24)
+	data[offset+4] = uint8(v >> 32)
+	data[offset+5] = uint8(v >> 40)
+	data[offset+6] = uint8(v >> 48)
+	data[offset+7] = uint8(v >> 56)
+	return offset + 8
+}
+func encodeFixed32Log(data []byte, offset int, v uint32) int {
+	data[offset] = uint8(v)
+	data[offset+1] = uint8(v >> 8)
+	data[offset+2] = uint8(v >> 16)
+	data[offset+3] = uint8(v >> 24)
+	return offset + 4
+}
+func encodeVarintLog(data []byte, offset int, v uint64) int {
+	for v >= 1<<7 {
+		data[offset] = uint8(v&0x7f | 0x80)
+		v >>= 7
+		offset++
+	}
+	data[offset] = uint8(v)
+	return offset + 1
+}
+
+// Size return the log's size
+func (m *Log) Size() (n int) {
+	var l int
+	_ = l
+	if m.Time != nil {
+		n += 1 + sovLog(uint64(*m.Time))
+	}
+	if len(m.Contents) > 0 {
+		for _, e := range m.Contents {
+			l = e.Size()
+			n += 1 + l + sovLog(uint64(l))
+		}
+	}
+	if m.XXXUnrecognized != nil {
+		n += len(m.XXXUnrecognized)
+	}
+	return n
+}
+
+// Size return LogContent size based on Key and Value
+func (m *LogContent) Size() (n int) {
+	var l int
+	_ = l
+	if m.Key != nil {
+		l = len(*m.Key)
+		n += 1 + l + sovLog(uint64(l))
+	}
+	if m.Value != nil {
+		l = len(*m.Value)
+		n += 1 + l + sovLog(uint64(l))
+	}
+	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
+	if len(m.Logs) > 0 {
+		for _, e := range m.Logs {
+			l = e.Size()
+			n += 1 + l + sovLog(uint64(l))
+		}
+	}
+	if m.Reserved != nil {
+		l = len(*m.Reserved)
+		n += 1 + l + sovLog(uint64(l))
+	}
+	if m.Topic != nil {
+		l = len(*m.Topic)
+		n += 1 + l + sovLog(uint64(l))
+	}
+	if m.Source != nil {
+		l = len(*m.Source)
+		n += 1 + l + sovLog(uint64(l))
+	}
+	if m.XXXUnrecognized != nil {
+		n += len(m.XXXUnrecognized)
+	}
+	return n
+}
+
+// Size return LogGroupList size
+func (m *LogGroupList) Size() (n int) {
+	var l int
+	_ = l
+	if len(m.LogGroups) > 0 {
+		for _, e := range m.LogGroups {
+			l = e.Size()
+			n += 1 + l + sovLog(uint64(l))
+		}
+	}
+	if m.XXXUnrecognized != nil {
+		n += len(m.XXXUnrecognized)
+	}
+	return n
+}
+
+func sovLog(x uint64) (n int) {
+	for {
+		n++
+		x >>= 7
+		if x == 0 {
+			break
+		}
+	}
+	return n
+}
+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)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowLog
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: Log: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: Log: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Time", wireType)
+			}
+			var v uint32
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLog
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				v |= (uint32(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			m.Time = &v
+			hasFields[0] |= uint64(0x00000001)
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Contents", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLog
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthLog
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Contents = append(m.Contents, &LogContent{})
+			if err := m.Contents[len(m.Contents)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipLog(data[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthLog
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.XXXUnrecognized = append(m.XXXUnrecognized, data[iNdEx:iNdEx+skippy]...)
+			iNdEx += skippy
+		}
+	}
+	if hasFields[0]&uint64(0x00000001) == 0 {
+		return github_com_gogo_protobuf_proto.NewRequiredNotSetError("Time")
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+
+// Unmarshal data to LogContent
+func (m *LogContent) Unmarshal(data []byte) error {
+	var hasFields [1]uint64
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowLog
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: Content: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: Content: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLog
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthLog
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			s := string(data[iNdEx:postIndex])
+			m.Key = &s
+			iNdEx = postIndex
+			hasFields[0] |= uint64(0x00000001)
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLog
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthLog
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			s := string(data[iNdEx:postIndex])
+			m.Value = &s
+			iNdEx = postIndex
+			hasFields[0] |= uint64(0x00000002)
+		default:
+			iNdEx = preIndex
+			skippy, err := skipLog(data[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthLog
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.XXXUnrecognized = append(m.XXXUnrecognized, data[iNdEx:iNdEx+skippy]...)
+			iNdEx += skippy
+		}
+	}
+	if hasFields[0]&uint64(0x00000001) == 0 {
+		return github_com_gogo_protobuf_proto.NewRequiredNotSetError("Key")
+	}
+	if hasFields[0]&uint64(0x00000002) == 0 {
+		return github_com_gogo_protobuf_proto.NewRequiredNotSetError("Value")
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+
+// Unmarshal data to LogGroup
+func (m *LogGroup) Unmarshal(data []byte) error {
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowLog
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: LogGroup: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: LogGroup: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Logs", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLog
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthLog
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Logs = append(m.Logs, &Log{})
+			if err := m.Logs[len(m.Logs)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Reserved", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLog
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthLog
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			s := string(data[iNdEx:postIndex])
+			m.Reserved = &s
+			iNdEx = postIndex
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Topic", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLog
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthLog
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			s := string(data[iNdEx:postIndex])
+			m.Topic = &s
+			iNdEx = postIndex
+		case 4:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Source", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLog
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthLog
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			s := string(data[iNdEx:postIndex])
+			m.Source = &s
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipLog(data[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthLog
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.XXXUnrecognized = append(m.XXXUnrecognized, data[iNdEx:iNdEx+skippy]...)
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+
+// Unmarshal data to LogGroupList
+func (m *LogGroupList) Unmarshal(data []byte) error {
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowLog
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: LogGroupList: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: LogGroupList: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field LogGroups", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowLog
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthLog
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.LogGroups = append(m.LogGroups, &LogGroup{})
+			if err := m.LogGroups[len(m.LogGroups)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipLog(data[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthLog
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.XXXUnrecognized = append(m.XXXUnrecognized, data[iNdEx:iNdEx+skippy]...)
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+
+func skipLog(data []byte) (n int, err error) {
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return 0, ErrIntOverflowLog
+			}
+			if iNdEx >= l {
+				return 0, io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		wireType := int(wire & 0x7)
+		switch wireType {
+		case 0:
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return 0, ErrIntOverflowLog
+				}
+				if iNdEx >= l {
+					return 0, io.ErrUnexpectedEOF
+				}
+				iNdEx++
+				if data[iNdEx-1] < 0x80 {
+					break
+				}
+			}
+			return iNdEx, nil
+		case 1:
+			iNdEx += 8
+			return iNdEx, nil
+		case 2:
+			var length int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return 0, ErrIntOverflowLog
+				}
+				if iNdEx >= l {
+					return 0, io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				length |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			iNdEx += length
+			if length < 0 {
+				return 0, ErrInvalidLengthLog
+			}
+			return iNdEx, nil
+		case 3:
+			for {
+				var innerWire uint64
+				var start = iNdEx
+				for shift := uint(0); ; shift += 7 {
+					if shift >= 64 {
+						return 0, ErrIntOverflowLog
+					}
+					if iNdEx >= l {
+						return 0, io.ErrUnexpectedEOF
+					}
+					b := data[iNdEx]
+					iNdEx++
+					innerWire |= (uint64(b) & 0x7F) << shift
+					if b < 0x80 {
+						break
+					}
+				}
+				innerWireType := int(innerWire & 0x7)
+				if innerWireType == 4 {
+					break
+				}
+				next, err := skipLog(data[start:])
+				if err != nil {
+					return 0, err
+				}
+				iNdEx = start + next
+			}
+			return iNdEx, nil
+		case 4:
+			return iNdEx, nil
+		case 5:
+			iNdEx += 4
+			return iNdEx, nil
+		default:
+			return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
+		}
+	}
+	panic("unreachable")
+}

+ 42 - 0
vendor/github.com/astaxie/beego/logs/alils/log_config.go

@@ -0,0 +1,42 @@
+package alils
+
+// InputDetail define log detail
+type InputDetail struct {
+	LogType       string   `json:"logType"`
+	LogPath       string   `json:"logPath"`
+	FilePattern   string   `json:"filePattern"`
+	LocalStorage  bool     `json:"localStorage"`
+	TimeFormat    string   `json:"timeFormat"`
+	LogBeginRegex string   `json:"logBeginRegex"`
+	Regex         string   `json:"regex"`
+	Keys          []string `json:"key"`
+	FilterKeys    []string `json:"filterKey"`
+	FilterRegex   []string `json:"filterRegex"`
+	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"`
+	InputDetail  InputDetail  `json:"inputDetail"`
+	OutputType   string       `json:"outputType"`
+	OutputDetail OutputDetail `json:"outputDetail"`
+
+	CreateTime     uint32
+	LastModifyTime uint32
+
+	project *LogProject
+}
+
+// GetAppliedMachineGroup returns applied machine group of this config.
+func (c *LogConfig) GetAppliedMachineGroup(confName string) (groupNames []string, err error) {
+	groupNames, err = c.project.GetAppliedMachineGroups(c.Name)
+	return
+}

+ 819 - 0
vendor/github.com/astaxie/beego/logs/alils/log_project.go

@@ -0,0 +1,819 @@
+/*
+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.
+*/
+package alils
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"net/http/httputil"
+)
+
+// Error message in SLS HTTP response.
+type errorMessage struct {
+	Code    string `json:"errorCode"`
+	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
+	AccessKeySecret string
+}
+
+// NewLogProject creates a new SLS project.
+func NewLogProject(name, endpoint, AccessKeyID, accessKeySecret string) (p *LogProject, err error) {
+	p = &LogProject{
+		Name:            name,
+		Endpoint:        endpoint,
+		AccessKeyID:     AccessKeyID,
+		AccessKeySecret: accessKeySecret,
+	}
+	return p, nil
+}
+
+// ListLogStore returns all logstore names of project p.
+func (p *LogProject) ListLogStore() (storeNames []string, err error) {
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+	}
+
+	uri := fmt.Sprintf("/logstores")
+	r, err := request(p, "GET", uri, h, nil)
+	if err != nil {
+		return
+	}
+
+	buf, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(buf, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to list logstore")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	type Body struct {
+		Count     int
+		LogStores []string
+	}
+	body := &Body{}
+
+	err = json.Unmarshal(buf, body)
+	if err != nil {
+		return
+	}
+
+	storeNames = body.LogStores
+
+	return
+}
+
+// GetLogStore returns logstore according by logstore name.
+func (p *LogProject) GetLogStore(name string) (s *LogStore, err error) {
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+	}
+
+	r, err := request(p, "GET", "/logstores/"+name, h, nil)
+	if err != nil {
+		return
+	}
+
+	buf, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(buf, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to get logstore")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	s = &LogStore{}
+	err = json.Unmarshal(buf, s)
+	if err != nil {
+		return
+	}
+	s.project = p
+	return
+}
+
+// CreateLogStore creates a new logstore in SLS,
+// where name is logstore name,
+// and ttl is time-to-live(in day) of logs,
+// and shardCnt is the number of shards.
+func (p *LogProject) CreateLogStore(name string, ttl, shardCnt int) (err error) {
+
+	type Body struct {
+		Name       string `json:"logstoreName"`
+		TTL        int    `json:"ttl"`
+		ShardCount int    `json:"shardCount"`
+	}
+
+	store := &Body{
+		Name:       name,
+		TTL:        ttl,
+		ShardCount: shardCnt,
+	}
+
+	body, err := json.Marshal(store)
+	if err != nil {
+		return
+	}
+
+	h := map[string]string{
+		"x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)),
+		"Content-Type":      "application/json",
+		"Accept-Encoding":   "deflate", // TODO: support lz4
+	}
+
+	r, err := request(p, "POST", "/logstores", h, body)
+	if err != nil {
+		return
+	}
+
+	body, err = ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(body, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to create logstore")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	return
+}
+
+// DeleteLogStore deletes a logstore according by logstore name.
+func (p *LogProject) DeleteLogStore(name string) (err error) {
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+	}
+
+	r, err := request(p, "DELETE", "/logstores/"+name, h, nil)
+	if err != nil {
+		return
+	}
+
+	body, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(body, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to delete logstore")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+	return
+}
+
+// UpdateLogStore updates a logstore according by logstore name,
+// obviously we can't modify the logstore name itself.
+func (p *LogProject) UpdateLogStore(name string, ttl, shardCnt int) (err error) {
+
+	type Body struct {
+		Name       string `json:"logstoreName"`
+		TTL        int    `json:"ttl"`
+		ShardCount int    `json:"shardCount"`
+	}
+
+	store := &Body{
+		Name:       name,
+		TTL:        ttl,
+		ShardCount: shardCnt,
+	}
+
+	body, err := json.Marshal(store)
+	if err != nil {
+		return
+	}
+
+	h := map[string]string{
+		"x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)),
+		"Content-Type":      "application/json",
+		"Accept-Encoding":   "deflate", // TODO: support lz4
+	}
+
+	r, err := request(p, "PUT", "/logstores", h, body)
+	if err != nil {
+		return
+	}
+
+	body, err = ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(body, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to update logstore")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	return
+}
+
+// ListMachineGroup returns machine group name list and the total number of machine groups.
+// The offset starts from 0 and the size is the max number of machine groups could be returned.
+func (p *LogProject) ListMachineGroup(offset, size int) (m []string, total int, err error) {
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+	}
+
+	if size <= 0 {
+		size = 500
+	}
+
+	uri := fmt.Sprintf("/machinegroups?offset=%v&size=%v", offset, size)
+	r, err := request(p, "GET", uri, h, nil)
+	if err != nil {
+		return
+	}
+
+	buf, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(buf, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to list machine group")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	type Body struct {
+		MachineGroups []string
+		Count         int
+		Total         int
+	}
+	body := &Body{}
+
+	err = json.Unmarshal(buf, body)
+	if err != nil {
+		return
+	}
+
+	m = body.MachineGroups
+	total = body.Total
+
+	return
+}
+
+// GetMachineGroup retruns machine group according by machine group name.
+func (p *LogProject) GetMachineGroup(name string) (m *MachineGroup, err error) {
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+	}
+
+	r, err := request(p, "GET", "/machinegroups/"+name, h, nil)
+	if err != nil {
+		return
+	}
+
+	buf, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(buf, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to get machine group:%v", name)
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	m = &MachineGroup{}
+	err = json.Unmarshal(buf, m)
+	if err != nil {
+		return
+	}
+	m.project = p
+	return
+}
+
+// CreateMachineGroup creates a new machine group in SLS.
+func (p *LogProject) CreateMachineGroup(m *MachineGroup) (err error) {
+
+	body, err := json.Marshal(m)
+	if err != nil {
+		return
+	}
+
+	h := map[string]string{
+		"x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)),
+		"Content-Type":      "application/json",
+		"Accept-Encoding":   "deflate", // TODO: support lz4
+	}
+
+	r, err := request(p, "POST", "/machinegroups", h, body)
+	if err != nil {
+		return
+	}
+
+	body, err = ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(body, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to create machine group")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	return
+}
+
+// UpdateMachineGroup updates a machine group.
+func (p *LogProject) UpdateMachineGroup(m *MachineGroup) (err error) {
+
+	body, err := json.Marshal(m)
+	if err != nil {
+		return
+	}
+
+	h := map[string]string{
+		"x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)),
+		"Content-Type":      "application/json",
+		"Accept-Encoding":   "deflate", // TODO: support lz4
+	}
+
+	r, err := request(p, "PUT", "/machinegroups/"+m.Name, h, body)
+	if err != nil {
+		return
+	}
+
+	body, err = ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(body, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to update machine group")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	return
+}
+
+// DeleteMachineGroup deletes machine group according machine group name.
+func (p *LogProject) DeleteMachineGroup(name string) (err error) {
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+	}
+
+	r, err := request(p, "DELETE", "/machinegroups/"+name, h, nil)
+	if err != nil {
+		return
+	}
+
+	body, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(body, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to delete machine group")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+	return
+}
+
+// ListConfig returns config names list and the total number of configs.
+// The offset starts from 0 and the size is the max number of configs could be returned.
+func (p *LogProject) ListConfig(offset, size int) (cfgNames []string, total int, err error) {
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+	}
+
+	if size <= 0 {
+		size = 100
+	}
+
+	uri := fmt.Sprintf("/configs?offset=%v&size=%v", offset, size)
+	r, err := request(p, "GET", uri, h, nil)
+	if err != nil {
+		return
+	}
+
+	buf, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(buf, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to delete machine group")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	type Body struct {
+		Total   int
+		Configs []string
+	}
+	body := &Body{}
+
+	err = json.Unmarshal(buf, body)
+	if err != nil {
+		return
+	}
+
+	cfgNames = body.Configs
+	total = body.Total
+	return
+}
+
+// GetConfig returns config according by config name.
+func (p *LogProject) GetConfig(name string) (c *LogConfig, err error) {
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+	}
+
+	r, err := request(p, "GET", "/configs/"+name, h, nil)
+	if err != nil {
+		return
+	}
+
+	buf, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(buf, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to delete config")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	c = &LogConfig{}
+	err = json.Unmarshal(buf, c)
+	if err != nil {
+		return
+	}
+	c.project = p
+	return
+}
+
+// UpdateConfig updates a config.
+func (p *LogProject) UpdateConfig(c *LogConfig) (err error) {
+
+	body, err := json.Marshal(c)
+	if err != nil {
+		return
+	}
+
+	h := map[string]string{
+		"x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)),
+		"Content-Type":      "application/json",
+		"Accept-Encoding":   "deflate", // TODO: support lz4
+	}
+
+	r, err := request(p, "PUT", "/configs/"+c.Name, h, body)
+	if err != nil {
+		return
+	}
+
+	body, err = ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(body, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to update config")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	return
+}
+
+// CreateConfig creates a new config in SLS.
+func (p *LogProject) CreateConfig(c *LogConfig) (err error) {
+
+	body, err := json.Marshal(c)
+	if err != nil {
+		return
+	}
+
+	h := map[string]string{
+		"x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)),
+		"Content-Type":      "application/json",
+		"Accept-Encoding":   "deflate", // TODO: support lz4
+	}
+
+	r, err := request(p, "POST", "/configs", h, body)
+	if err != nil {
+		return
+	}
+
+	body, err = ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(body, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to update config")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	return
+}
+
+// DeleteConfig deletes a config according by config name.
+func (p *LogProject) DeleteConfig(name string) (err error) {
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+	}
+
+	r, err := request(p, "DELETE", "/configs/"+name, h, nil)
+	if err != nil {
+		return
+	}
+
+	body, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(body, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to delete config")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+	return
+}
+
+// GetAppliedMachineGroups returns applied machine group names list according config name.
+func (p *LogProject) GetAppliedMachineGroups(confName string) (groupNames []string, err error) {
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+	}
+
+	uri := fmt.Sprintf("/configs/%v/machinegroups", confName)
+	r, err := request(p, "GET", uri, h, nil)
+	if err != nil {
+		return
+	}
+
+	buf, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(buf, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to get applied machine groups")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	type Body struct {
+		Count         int
+		Machinegroups []string
+	}
+
+	body := &Body{}
+	err = json.Unmarshal(buf, body)
+	if err != nil {
+		return
+	}
+
+	groupNames = body.Machinegroups
+	return
+}
+
+// GetAppliedConfigs returns applied config names list according machine group name groupName.
+func (p *LogProject) GetAppliedConfigs(groupName string) (confNames []string, err error) {
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+	}
+
+	uri := fmt.Sprintf("/machinegroups/%v/configs", groupName)
+	r, err := request(p, "GET", uri, h, nil)
+	if err != nil {
+		return
+	}
+
+	buf, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(buf, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to applied configs")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	type Cfg struct {
+		Count   int      `json:"count"`
+		Configs []string `json:"configs"`
+	}
+
+	body := &Cfg{}
+	err = json.Unmarshal(buf, body)
+	if err != nil {
+		return
+	}
+
+	confNames = body.Configs
+	return
+}
+
+// ApplyConfigToMachineGroup applies config to machine group.
+func (p *LogProject) ApplyConfigToMachineGroup(confName, groupName string) (err error) {
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+	}
+
+	uri := fmt.Sprintf("/machinegroups/%v/configs/%v", groupName, confName)
+	r, err := request(p, "PUT", uri, h, nil)
+	if err != nil {
+		return
+	}
+
+	buf, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(buf, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to apply config to machine group")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+	return
+}
+
+// RemoveConfigFromMachineGroup removes config from machine group.
+func (p *LogProject) RemoveConfigFromMachineGroup(confName, groupName string) (err error) {
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+	}
+
+	uri := fmt.Sprintf("/machinegroups/%v/configs/%v", groupName, confName)
+	r, err := request(p, "DELETE", uri, h, nil)
+	if err != nil {
+		return
+	}
+
+	buf, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(buf, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to remove config from machine group")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Printf("%s\n", dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+	return
+}

+ 271 - 0
vendor/github.com/astaxie/beego/logs/alils/log_store.go

@@ -0,0 +1,271 @@
+package alils
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"net/http/httputil"
+	"strconv"
+
+	lz4 "github.com/cloudflare/golz4"
+	"github.com/gogo/protobuf/proto"
+)
+
+// LogStore Store the logs
+type LogStore struct {
+	Name       string `json:"logstoreName"`
+	TTL        int
+	ShardCount int
+
+	CreateTime     uint32
+	LastModifyTime uint32
+
+	project *LogProject
+}
+
+// Shard define the Log Shard
+type Shard struct {
+	ShardID int `json:"shardID"`
+}
+
+// ListShards returns shard id list of this logstore.
+func (s *LogStore) ListShards() (shardIDs []int, err error) {
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+	}
+
+	uri := fmt.Sprintf("/logstores/%v/shards", s.Name)
+	r, err := request(s.project, "GET", uri, h, nil)
+	if err != nil {
+		return
+	}
+
+	buf, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(buf, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to list logstore")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Println(dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	var shards []*Shard
+	err = json.Unmarshal(buf, &shards)
+	if err != nil {
+		return
+	}
+
+	for _, v := range shards {
+		shardIDs = append(shardIDs, v.ShardID)
+	}
+	return
+}
+
+// PutLogs put logs into logstore.
+// The callers should transform user logs into LogGroup.
+func (s *LogStore) PutLogs(lg *LogGroup) (err error) {
+	body, err := proto.Marshal(lg)
+	if err != nil {
+		return
+	}
+
+	// Compresse body with lz4
+	out := make([]byte, lz4.CompressBound(body))
+	n, err := lz4.Compress(body, out)
+	if err != nil {
+		return
+	}
+
+	h := map[string]string{
+		"x-sls-compresstype": "lz4",
+		"x-sls-bodyrawsize":  fmt.Sprintf("%v", len(body)),
+		"Content-Type":       "application/x-protobuf",
+	}
+
+	uri := fmt.Sprintf("/logstores/%v", s.Name)
+	r, err := request(s.project, "POST", uri, h, out[:n])
+	if err != nil {
+		return
+	}
+
+	buf, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(buf, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to put logs")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Println(dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+	return
+}
+
+// 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) {
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+	}
+
+	uri := fmt.Sprintf("/logstores/%v/shards/%v?type=cursor&from=%v",
+		s.Name, shardID, from)
+
+	r, err := request(s.project, "GET", uri, h, nil)
+	if err != nil {
+		return
+	}
+
+	buf, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(buf, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to get cursor")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Println(dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	type Body struct {
+		Cursor string
+	}
+	body := &Body{}
+
+	err = json.Unmarshal(buf, body)
+	if err != nil {
+		return
+	}
+	cursor = body.Cursor
+	return
+}
+
+// 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,
+	logGroupMaxCount int) (out []byte, nextCursor string, err error) {
+
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+		"Accept":            "application/x-protobuf",
+		"Accept-Encoding":   "lz4",
+	}
+
+	uri := fmt.Sprintf("/logstores/%v/shards/%v?type=logs&cursor=%v&count=%v",
+		s.Name, shardID, cursor, logGroupMaxCount)
+
+	r, err := request(s.project, "GET", uri, h, nil)
+	if err != nil {
+		return
+	}
+
+	buf, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(buf, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to get cursor")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Println(dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	v, ok := r.Header["X-Sls-Compresstype"]
+	if !ok || len(v) == 0 {
+		err = fmt.Errorf("can't find 'x-sls-compresstype' header")
+		return
+	}
+	if v[0] != "lz4" {
+		err = fmt.Errorf("unexpected compress type:%v", v[0])
+		return
+	}
+
+	v, ok = r.Header["X-Sls-Cursor"]
+	if !ok || len(v) == 0 {
+		err = fmt.Errorf("can't find 'x-sls-cursor' header")
+		return
+	}
+	nextCursor = v[0]
+
+	v, ok = r.Header["X-Sls-Bodyrawsize"]
+	if !ok || len(v) == 0 {
+		err = fmt.Errorf("can't find 'x-sls-bodyrawsize' header")
+		return
+	}
+	bodyRawSize, err := strconv.Atoi(v[0])
+	if err != nil {
+		return
+	}
+
+	out = make([]byte, bodyRawSize)
+	err = lz4.Uncompress(buf, out)
+	if err != nil {
+		return
+	}
+
+	return
+}
+
+// LogsBytesDecode decodes logs binary data retruned by GetLogsBytes API
+func LogsBytesDecode(data []byte) (gl *LogGroupList, err error) {
+
+	gl = &LogGroupList{}
+	err = proto.Unmarshal(data, gl)
+	if err != nil {
+		return
+	}
+
+	return
+}
+
+// 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,
+	logGroupMaxCount int) (gl *LogGroupList, nextCursor string, err error) {
+
+	out, nextCursor, err := s.GetLogsBytes(shardID, cursor, logGroupMaxCount)
+	if err != nil {
+		return
+	}
+
+	gl, err = LogsBytesDecode(out)
+	if err != nil {
+		return
+	}
+
+	return
+}

+ 91 - 0
vendor/github.com/astaxie/beego/logs/alils/machine_group.go

@@ -0,0 +1,91 @@
+package alils
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"net/http/httputil"
+)
+
+// 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"`
+
+	Attribute MachineGroupAttribute `json:"groupAttribute"`
+
+	CreateTime     uint32
+	LastModifyTime uint32
+
+	project *LogProject
+}
+
+// Machine define the Machine
+type Machine struct {
+	IP            string
+	UniqueID      string `json:"machine-uniqueid"`
+	UserdefinedID string `json:"userdefined-id"`
+}
+
+// MachineList define the Machine List
+type MachineList struct {
+	Total    int
+	Machines []*Machine
+}
+
+// ListMachines returns machine list of this machine group.
+func (m *MachineGroup) ListMachines() (ms []*Machine, total int, err error) {
+	h := map[string]string{
+		"x-sls-bodyrawsize": "0",
+	}
+
+	uri := fmt.Sprintf("/machinegroups/%v/machines", m.Name)
+	r, err := request(m.project, "GET", uri, h, nil)
+	if err != nil {
+		return
+	}
+
+	buf, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return
+	}
+
+	if r.StatusCode != http.StatusOK {
+		errMsg := &errorMessage{}
+		err = json.Unmarshal(buf, errMsg)
+		if err != nil {
+			err = fmt.Errorf("failed to remove config from machine group")
+			dump, _ := httputil.DumpResponse(r, true)
+			fmt.Println(dump)
+			return
+		}
+		err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message)
+		return
+	}
+
+	body := &MachineList{}
+	err = json.Unmarshal(buf, body)
+	if err != nil {
+		return
+	}
+
+	ms = body.Machines
+	total = body.Total
+
+	return
+}
+
+// GetAppliedConfigs returns applied configs of this machine group.
+func (m *MachineGroup) GetAppliedConfigs() (confNames []string, err error) {
+	confNames, err = m.project.GetAppliedConfigs(m.Name)
+	return
+}

+ 62 - 0
vendor/github.com/astaxie/beego/logs/alils/request.go

@@ -0,0 +1,62 @@
+package alils
+
+import (
+	"bytes"
+	"crypto/md5"
+	"fmt"
+	"net/http"
+)
+
+// request sends a request to SLS.
+func request(project *LogProject, method, uri string, headers map[string]string,
+	body []byte) (resp *http.Response, err error) {
+
+	// The caller should provide 'x-sls-bodyrawsize' header
+	if _, ok := headers["x-sls-bodyrawsize"]; !ok {
+		err = fmt.Errorf("Can't find 'x-sls-bodyrawsize' header")
+		return
+	}
+
+	// SLS public request headers
+	headers["Host"] = project.Name + "." + project.Endpoint
+	headers["Date"] = nowRFC1123()
+	headers["x-sls-apiversion"] = version
+	headers["x-sls-signaturemethod"] = signatureMethod
+	if body != nil {
+		bodyMD5 := fmt.Sprintf("%X", md5.Sum(body))
+		headers["Content-MD5"] = bodyMD5
+
+		if _, ok := headers["Content-Type"]; !ok {
+			err = fmt.Errorf("Can't find 'Content-Type' header")
+			return
+		}
+	}
+
+	// Calc Authorization
+	// Authorization = "SLS <AccessKeyID>:<Signature>"
+	digest, err := signature(project, method, uri, headers)
+	if err != nil {
+		return
+	}
+	auth := fmt.Sprintf("SLS %v:%v", project.AccessKeyID, digest)
+	headers["Authorization"] = auth
+
+	// Initialize http request
+	reader := bytes.NewReader(body)
+	urlStr := fmt.Sprintf("http://%v.%v%v", project.Name, project.Endpoint, uri)
+	req, err := http.NewRequest(method, urlStr, reader)
+	if err != nil {
+		return
+	}
+	for k, v := range headers {
+		req.Header.Add(k, v)
+	}
+
+	// Get ready to do request
+	resp, err = http.DefaultClient.Do(req)
+	if err != nil {
+		return
+	}
+
+	return
+}

+ 111 - 0
vendor/github.com/astaxie/beego/logs/alils/signature.go

@@ -0,0 +1,111 @@
+package alils
+
+import (
+	"crypto/hmac"
+	"crypto/sha1"
+	"encoding/base64"
+	"fmt"
+	"net/url"
+	"sort"
+	"strings"
+	"time"
+)
+
+// GMT location
+var gmtLoc = time.FixedZone("GMT", 0)
+
+// NowRFC1123 returns now time in RFC1123 format with GMT timezone,
+// eg. "Mon, 02 Jan 2006 15:04:05 GMT".
+func nowRFC1123() string {
+	return time.Now().In(gmtLoc).Format(time.RFC1123)
+}
+
+// signature calculates a request's signature digest.
+func signature(project *LogProject, method, uri string,
+	headers map[string]string) (digest string, err error) {
+	var contentMD5, contentType, date, canoHeaders, canoResource string
+	var slsHeaderKeys sort.StringSlice
+
+	// SignString = VERB + "\n"
+	//              + CONTENT-MD5 + "\n"
+	//              + CONTENT-TYPE + "\n"
+	//              + DATE + "\n"
+	//              + CanonicalizedSLSHeaders + "\n"
+	//              + CanonicalizedResource
+
+	if val, ok := headers["Content-MD5"]; ok {
+		contentMD5 = val
+	}
+
+	if val, ok := headers["Content-Type"]; ok {
+		contentType = val
+	}
+
+	date, ok := headers["Date"]
+	if !ok {
+		err = fmt.Errorf("Can't find 'Date' header")
+		return
+	}
+
+	// Calc CanonicalizedSLSHeaders
+	slsHeaders := make(map[string]string, len(headers))
+	for k, v := range headers {
+		l := strings.TrimSpace(strings.ToLower(k))
+		if strings.HasPrefix(l, "x-sls-") {
+			slsHeaders[l] = strings.TrimSpace(v)
+			slsHeaderKeys = append(slsHeaderKeys, l)
+		}
+	}
+
+	sort.Sort(slsHeaderKeys)
+	for i, k := range slsHeaderKeys {
+		canoHeaders += k + ":" + slsHeaders[k]
+		if i+1 < len(slsHeaderKeys) {
+			canoHeaders += "\n"
+		}
+	}
+
+	// Calc CanonicalizedResource
+	u, err := url.Parse(uri)
+	if err != nil {
+		return
+	}
+
+	canoResource += url.QueryEscape(u.Path)
+	if u.RawQuery != "" {
+		var keys sort.StringSlice
+
+		vals := u.Query()
+		for k := range vals {
+			keys = append(keys, k)
+		}
+
+		sort.Sort(keys)
+		canoResource += "?"
+		for i, k := range keys {
+			if i > 0 {
+				canoResource += "&"
+			}
+
+			for _, v := range vals[k] {
+				canoResource += k + "=" + v
+			}
+		}
+	}
+
+	signStr := method + "\n" +
+		contentMD5 + "\n" +
+		contentType + "\n" +
+		date + "\n" +
+		canoHeaders + "\n" +
+		canoResource
+
+	// Signature = base64(hmac-sha1(UTF8-Encoding-Of(SignString),AccessKeySecret))
+	mac := hmac.New(sha1.New, []byte(project.AccessKeySecret))
+	_, err = mac.Write([]byte(signStr))
+	if err != nil {
+		return
+	}
+	digest = base64.StdEncoding.EncodeToString(mac.Sum(nil))
+	return
+}

+ 28 - 0
vendor/github.com/astaxie/beego/logs/color.go

@@ -0,0 +1,28 @@
+// 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.
+
+// +build !windows
+
+package logs
+
+import "io"
+
+type ansiColorWriter struct {
+	w    io.Writer
+	mode outputMode
+}
+
+func (cw *ansiColorWriter) Write(p []byte) (int, error) {
+	return cw.w.Write(p)
+}

+ 428 - 0
vendor/github.com/astaxie/beego/logs/color_windows.go

@@ -0,0 +1,428 @@
+// 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.
+
+// +build windows
+
+package logs
+
+import (
+	"bytes"
+	"io"
+	"strings"
+	"syscall"
+	"unsafe"
+)
+
+type (
+	csiState    int
+	parseResult int
+)
+
+const (
+	outsideCsiCode csiState = iota
+	firstCsiCode
+	secondCsiCode
+)
+
+const (
+	noConsole parseResult = iota
+	changedColor
+	unknown
+)
+
+type ansiColorWriter struct {
+	w             io.Writer
+	mode          outputMode
+	state         csiState
+	paramStartBuf bytes.Buffer
+	paramBuf      bytes.Buffer
+}
+
+const (
+	firstCsiChar   byte = '\x1b'
+	secondeCsiChar byte = '['
+	separatorChar  byte = ';'
+	sgrCode        byte = 'm'
+)
+
+const (
+	foregroundBlue      = uint16(0x0001)
+	foregroundGreen     = uint16(0x0002)
+	foregroundRed       = uint16(0x0004)
+	foregroundIntensity = uint16(0x0008)
+	backgroundBlue      = uint16(0x0010)
+	backgroundGreen     = uint16(0x0020)
+	backgroundRed       = uint16(0x0040)
+	backgroundIntensity = uint16(0x0080)
+	underscore          = uint16(0x8000)
+
+	foregroundMask = foregroundBlue | foregroundGreen | foregroundRed | foregroundIntensity
+	backgroundMask = backgroundBlue | backgroundGreen | backgroundRed | backgroundIntensity
+)
+
+const (
+	ansiReset        = "0"
+	ansiIntensityOn  = "1"
+	ansiIntensityOff = "21"
+	ansiUnderlineOn  = "4"
+	ansiUnderlineOff = "24"
+	ansiBlinkOn      = "5"
+	ansiBlinkOff     = "25"
+
+	ansiForegroundBlack   = "30"
+	ansiForegroundRed     = "31"
+	ansiForegroundGreen   = "32"
+	ansiForegroundYellow  = "33"
+	ansiForegroundBlue    = "34"
+	ansiForegroundMagenta = "35"
+	ansiForegroundCyan    = "36"
+	ansiForegroundWhite   = "37"
+	ansiForegroundDefault = "39"
+
+	ansiBackgroundBlack   = "40"
+	ansiBackgroundRed     = "41"
+	ansiBackgroundGreen   = "42"
+	ansiBackgroundYellow  = "43"
+	ansiBackgroundBlue    = "44"
+	ansiBackgroundMagenta = "45"
+	ansiBackgroundCyan    = "46"
+	ansiBackgroundWhite   = "47"
+	ansiBackgroundDefault = "49"
+
+	ansiLightForegroundGray    = "90"
+	ansiLightForegroundRed     = "91"
+	ansiLightForegroundGreen   = "92"
+	ansiLightForegroundYellow  = "93"
+	ansiLightForegroundBlue    = "94"
+	ansiLightForegroundMagenta = "95"
+	ansiLightForegroundCyan    = "96"
+	ansiLightForegroundWhite   = "97"
+
+	ansiLightBackgroundGray    = "100"
+	ansiLightBackgroundRed     = "101"
+	ansiLightBackgroundGreen   = "102"
+	ansiLightBackgroundYellow  = "103"
+	ansiLightBackgroundBlue    = "104"
+	ansiLightBackgroundMagenta = "105"
+	ansiLightBackgroundCyan    = "106"
+	ansiLightBackgroundWhite   = "107"
+)
+
+type drawType int
+
+const (
+	foreground drawType = iota
+	background
+)
+
+type winColor struct {
+	code     uint16
+	drawType drawType
+}
+
+var colorMap = map[string]winColor{
+	ansiForegroundBlack:   {0, foreground},
+	ansiForegroundRed:     {foregroundRed, foreground},
+	ansiForegroundGreen:   {foregroundGreen, foreground},
+	ansiForegroundYellow:  {foregroundRed | foregroundGreen, foreground},
+	ansiForegroundBlue:    {foregroundBlue, foreground},
+	ansiForegroundMagenta: {foregroundRed | foregroundBlue, foreground},
+	ansiForegroundCyan:    {foregroundGreen | foregroundBlue, foreground},
+	ansiForegroundWhite:   {foregroundRed | foregroundGreen | foregroundBlue, foreground},
+	ansiForegroundDefault: {foregroundRed | foregroundGreen | foregroundBlue, foreground},
+
+	ansiBackgroundBlack:   {0, background},
+	ansiBackgroundRed:     {backgroundRed, background},
+	ansiBackgroundGreen:   {backgroundGreen, background},
+	ansiBackgroundYellow:  {backgroundRed | backgroundGreen, background},
+	ansiBackgroundBlue:    {backgroundBlue, background},
+	ansiBackgroundMagenta: {backgroundRed | backgroundBlue, background},
+	ansiBackgroundCyan:    {backgroundGreen | backgroundBlue, background},
+	ansiBackgroundWhite:   {backgroundRed | backgroundGreen | backgroundBlue, background},
+	ansiBackgroundDefault: {0, background},
+
+	ansiLightForegroundGray:    {foregroundIntensity, foreground},
+	ansiLightForegroundRed:     {foregroundIntensity | foregroundRed, foreground},
+	ansiLightForegroundGreen:   {foregroundIntensity | foregroundGreen, foreground},
+	ansiLightForegroundYellow:  {foregroundIntensity | foregroundRed | foregroundGreen, foreground},
+	ansiLightForegroundBlue:    {foregroundIntensity | foregroundBlue, foreground},
+	ansiLightForegroundMagenta: {foregroundIntensity | foregroundRed | foregroundBlue, foreground},
+	ansiLightForegroundCyan:    {foregroundIntensity | foregroundGreen | foregroundBlue, foreground},
+	ansiLightForegroundWhite:   {foregroundIntensity | foregroundRed | foregroundGreen | foregroundBlue, foreground},
+
+	ansiLightBackgroundGray:    {backgroundIntensity, background},
+	ansiLightBackgroundRed:     {backgroundIntensity | backgroundRed, background},
+	ansiLightBackgroundGreen:   {backgroundIntensity | backgroundGreen, background},
+	ansiLightBackgroundYellow:  {backgroundIntensity | backgroundRed | backgroundGreen, background},
+	ansiLightBackgroundBlue:    {backgroundIntensity | backgroundBlue, background},
+	ansiLightBackgroundMagenta: {backgroundIntensity | backgroundRed | backgroundBlue, background},
+	ansiLightBackgroundCyan:    {backgroundIntensity | backgroundGreen | backgroundBlue, background},
+	ansiLightBackgroundWhite:   {backgroundIntensity | backgroundRed | backgroundGreen | backgroundBlue, background},
+}
+
+var (
+	kernel32                       = syscall.NewLazyDLL("kernel32.dll")
+	procSetConsoleTextAttribute    = kernel32.NewProc("SetConsoleTextAttribute")
+	procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
+	defaultAttr                    *textAttributes
+)
+
+func init() {
+	screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout))
+	if screenInfo != nil {
+		colorMap[ansiForegroundDefault] = winColor{
+			screenInfo.WAttributes & (foregroundRed | foregroundGreen | foregroundBlue),
+			foreground,
+		}
+		colorMap[ansiBackgroundDefault] = winColor{
+			screenInfo.WAttributes & (backgroundRed | backgroundGreen | backgroundBlue),
+			background,
+		}
+		defaultAttr = convertTextAttr(screenInfo.WAttributes)
+	}
+}
+
+type coord struct {
+	X, Y int16
+}
+
+type smallRect struct {
+	Left, Top, Right, Bottom int16
+}
+
+type consoleScreenBufferInfo struct {
+	DwSize              coord
+	DwCursorPosition    coord
+	WAttributes         uint16
+	SrWindow            smallRect
+	DwMaximumWindowSize coord
+}
+
+func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *consoleScreenBufferInfo {
+	var csbi consoleScreenBufferInfo
+	ret, _, _ := procGetConsoleScreenBufferInfo.Call(
+		hConsoleOutput,
+		uintptr(unsafe.Pointer(&csbi)))
+	if ret == 0 {
+		return nil
+	}
+	return &csbi
+}
+
+func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool {
+	ret, _, _ := procSetConsoleTextAttribute.Call(
+		hConsoleOutput,
+		uintptr(wAttributes))
+	return ret != 0
+}
+
+type textAttributes struct {
+	foregroundColor     uint16
+	backgroundColor     uint16
+	foregroundIntensity uint16
+	backgroundIntensity uint16
+	underscore          uint16
+	otherAttributes     uint16
+}
+
+func convertTextAttr(winAttr uint16) *textAttributes {
+	fgColor := winAttr & (foregroundRed | foregroundGreen | foregroundBlue)
+	bgColor := winAttr & (backgroundRed | backgroundGreen | backgroundBlue)
+	fgIntensity := winAttr & foregroundIntensity
+	bgIntensity := winAttr & backgroundIntensity
+	underline := winAttr & underscore
+	otherAttributes := winAttr &^ (foregroundMask | backgroundMask | underscore)
+	return &textAttributes{fgColor, bgColor, fgIntensity, bgIntensity, underline, otherAttributes}
+}
+
+func convertWinAttr(textAttr *textAttributes) uint16 {
+	var winAttr uint16
+	winAttr |= textAttr.foregroundColor
+	winAttr |= textAttr.backgroundColor
+	winAttr |= textAttr.foregroundIntensity
+	winAttr |= textAttr.backgroundIntensity
+	winAttr |= textAttr.underscore
+	winAttr |= textAttr.otherAttributes
+	return winAttr
+}
+
+func changeColor(param []byte) parseResult {
+	screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout))
+	if screenInfo == nil {
+		return noConsole
+	}
+
+	winAttr := convertTextAttr(screenInfo.WAttributes)
+	strParam := string(param)
+	if len(strParam) <= 0 {
+		strParam = "0"
+	}
+	csiParam := strings.Split(strParam, string(separatorChar))
+	for _, p := range csiParam {
+		c, ok := colorMap[p]
+		switch {
+		case !ok:
+			switch p {
+			case ansiReset:
+				winAttr.foregroundColor = defaultAttr.foregroundColor
+				winAttr.backgroundColor = defaultAttr.backgroundColor
+				winAttr.foregroundIntensity = defaultAttr.foregroundIntensity
+				winAttr.backgroundIntensity = defaultAttr.backgroundIntensity
+				winAttr.underscore = 0
+				winAttr.otherAttributes = 0
+			case ansiIntensityOn:
+				winAttr.foregroundIntensity = foregroundIntensity
+			case ansiIntensityOff:
+				winAttr.foregroundIntensity = 0
+			case ansiUnderlineOn:
+				winAttr.underscore = underscore
+			case ansiUnderlineOff:
+				winAttr.underscore = 0
+			case ansiBlinkOn:
+				winAttr.backgroundIntensity = backgroundIntensity
+			case ansiBlinkOff:
+				winAttr.backgroundIntensity = 0
+			default:
+				// unknown code
+			}
+		case c.drawType == foreground:
+			winAttr.foregroundColor = c.code
+		case c.drawType == background:
+			winAttr.backgroundColor = c.code
+		}
+	}
+	winTextAttribute := convertWinAttr(winAttr)
+	setConsoleTextAttribute(uintptr(syscall.Stdout), winTextAttribute)
+
+	return changedColor
+}
+
+func parseEscapeSequence(command byte, param []byte) parseResult {
+	if defaultAttr == nil {
+		return noConsole
+	}
+
+	switch command {
+	case sgrCode:
+		return changeColor(param)
+	default:
+		return unknown
+	}
+}
+
+func (cw *ansiColorWriter) flushBuffer() (int, error) {
+	return cw.flushTo(cw.w)
+}
+
+func (cw *ansiColorWriter) resetBuffer() (int, error) {
+	return cw.flushTo(nil)
+}
+
+func (cw *ansiColorWriter) flushTo(w io.Writer) (int, error) {
+	var n1, n2 int
+	var err error
+
+	startBytes := cw.paramStartBuf.Bytes()
+	cw.paramStartBuf.Reset()
+	if w != nil {
+		n1, err = cw.w.Write(startBytes)
+		if err != nil {
+			return n1, err
+		}
+	} else {
+		n1 = len(startBytes)
+	}
+	paramBytes := cw.paramBuf.Bytes()
+	cw.paramBuf.Reset()
+	if w != nil {
+		n2, err = cw.w.Write(paramBytes)
+		if err != nil {
+			return n1 + n2, err
+		}
+	} else {
+		n2 = len(paramBytes)
+	}
+	return n1 + n2, nil
+}
+
+func isParameterChar(b byte) bool {
+	return ('0' <= b && b <= '9') || b == separatorChar
+}
+
+func (cw *ansiColorWriter) Write(p []byte) (int, error) {
+	var r, nw, first, last int
+	if cw.mode != DiscardNonColorEscSeq {
+		cw.state = outsideCsiCode
+		cw.resetBuffer()
+	}
+
+	var err error
+	for i, ch := range p {
+		switch cw.state {
+		case outsideCsiCode:
+			if ch == firstCsiChar {
+				cw.paramStartBuf.WriteByte(ch)
+				cw.state = firstCsiCode
+			}
+		case firstCsiCode:
+			switch ch {
+			case firstCsiChar:
+				cw.paramStartBuf.WriteByte(ch)
+				break
+			case secondeCsiChar:
+				cw.paramStartBuf.WriteByte(ch)
+				cw.state = secondCsiCode
+				last = i - 1
+			default:
+				cw.resetBuffer()
+				cw.state = outsideCsiCode
+			}
+		case secondCsiCode:
+			if isParameterChar(ch) {
+				cw.paramBuf.WriteByte(ch)
+			} else {
+				nw, err = cw.w.Write(p[first:last])
+				r += nw
+				if err != nil {
+					return r, err
+				}
+				first = i + 1
+				result := parseEscapeSequence(ch, cw.paramBuf.Bytes())
+				if result == noConsole || (cw.mode == OutputNonColorEscSeq && result == unknown) {
+					cw.paramBuf.WriteByte(ch)
+					nw, err := cw.flushBuffer()
+					if err != nil {
+						return r, err
+					}
+					r += nw
+				} else {
+					n, _ := cw.resetBuffer()
+					// Add one more to the size of the buffer for the last ch
+					r += n + 1
+				}
+
+				cw.state = outsideCsiCode
+			}
+		default:
+			cw.state = outsideCsiCode
+		}
+	}
+
+	if cw.mode != DiscardNonColorEscSeq || cw.state == outsideCsiCode {
+		nw, err = cw.w.Write(p[first:])
+		r += nw
+	}
+
+	return r, err
+}

+ 294 - 0
vendor/github.com/astaxie/beego/logs/color_windows_test.go

@@ -0,0 +1,294 @@
+// 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.
+
+// +build windows
+
+package logs
+
+import (
+	"bytes"
+	"fmt"
+	"syscall"
+	"testing"
+)
+
+var GetConsoleScreenBufferInfo = getConsoleScreenBufferInfo
+
+func ChangeColor(color uint16) {
+	setConsoleTextAttribute(uintptr(syscall.Stdout), color)
+}
+
+func ResetColor() {
+	ChangeColor(uint16(0x0007))
+}
+
+func TestWritePlanText(t *testing.T) {
+	inner := bytes.NewBufferString("")
+	w := NewAnsiColorWriter(inner)
+	expected := "plain text"
+	fmt.Fprintf(w, expected)
+	actual := inner.String()
+	if actual != expected {
+		t.Errorf("Get %q, want %q", actual, expected)
+	}
+}
+
+func TestWriteParseText(t *testing.T) {
+	inner := bytes.NewBufferString("")
+	w := NewAnsiColorWriter(inner)
+
+	inputTail := "\x1b[0mtail text"
+	expectedTail := "tail text"
+	fmt.Fprintf(w, inputTail)
+	actualTail := inner.String()
+	inner.Reset()
+	if actualTail != expectedTail {
+		t.Errorf("Get %q, want %q", actualTail, expectedTail)
+	}
+
+	inputHead := "head text\x1b[0m"
+	expectedHead := "head text"
+	fmt.Fprintf(w, inputHead)
+	actualHead := inner.String()
+	inner.Reset()
+	if actualHead != expectedHead {
+		t.Errorf("Get %q, want %q", actualHead, expectedHead)
+	}
+
+	inputBothEnds := "both ends \x1b[0m text"
+	expectedBothEnds := "both ends  text"
+	fmt.Fprintf(w, inputBothEnds)
+	actualBothEnds := inner.String()
+	inner.Reset()
+	if actualBothEnds != expectedBothEnds {
+		t.Errorf("Get %q, want %q", actualBothEnds, expectedBothEnds)
+	}
+
+	inputManyEsc := "\x1b\x1b\x1b\x1b[0m many esc"
+	expectedManyEsc := "\x1b\x1b\x1b many esc"
+	fmt.Fprintf(w, inputManyEsc)
+	actualManyEsc := inner.String()
+	inner.Reset()
+	if actualManyEsc != expectedManyEsc {
+		t.Errorf("Get %q, want %q", actualManyEsc, expectedManyEsc)
+	}
+
+	expectedSplit := "split  text"
+	for _, ch := range "split \x1b[0m text" {
+		fmt.Fprintf(w, string(ch))
+	}
+	actualSplit := inner.String()
+	inner.Reset()
+	if actualSplit != expectedSplit {
+		t.Errorf("Get %q, want %q", actualSplit, expectedSplit)
+	}
+}
+
+type screenNotFoundError struct {
+	error
+}
+
+func writeAnsiColor(expectedText, colorCode string) (actualText string, actualAttributes uint16, err error) {
+	inner := bytes.NewBufferString("")
+	w := NewAnsiColorWriter(inner)
+	fmt.Fprintf(w, "\x1b[%sm%s", colorCode, expectedText)
+
+	actualText = inner.String()
+	screenInfo := GetConsoleScreenBufferInfo(uintptr(syscall.Stdout))
+	if screenInfo != nil {
+		actualAttributes = screenInfo.WAttributes
+	} else {
+		err = &screenNotFoundError{}
+	}
+	return
+}
+
+type testParam struct {
+	text       string
+	attributes uint16
+	ansiColor  string
+}
+
+func TestWriteAnsiColorText(t *testing.T) {
+	screenInfo := GetConsoleScreenBufferInfo(uintptr(syscall.Stdout))
+	if screenInfo == nil {
+		t.Fatal("Could not get ConsoleScreenBufferInfo")
+	}
+	defer ChangeColor(screenInfo.WAttributes)
+	defaultFgColor := screenInfo.WAttributes & uint16(0x0007)
+	defaultBgColor := screenInfo.WAttributes & uint16(0x0070)
+	defaultFgIntensity := screenInfo.WAttributes & uint16(0x0008)
+	defaultBgIntensity := screenInfo.WAttributes & uint16(0x0080)
+
+	fgParam := []testParam{
+		{"foreground black  ", uint16(0x0000 | 0x0000), "30"},
+		{"foreground red    ", uint16(0x0004 | 0x0000), "31"},
+		{"foreground green  ", uint16(0x0002 | 0x0000), "32"},
+		{"foreground yellow ", uint16(0x0006 | 0x0000), "33"},
+		{"foreground blue   ", uint16(0x0001 | 0x0000), "34"},
+		{"foreground magenta", uint16(0x0005 | 0x0000), "35"},
+		{"foreground cyan   ", uint16(0x0003 | 0x0000), "36"},
+		{"foreground white  ", uint16(0x0007 | 0x0000), "37"},
+		{"foreground default", defaultFgColor | 0x0000, "39"},
+		{"foreground light gray   ", uint16(0x0000 | 0x0008 | 0x0000), "90"},
+		{"foreground light red    ", uint16(0x0004 | 0x0008 | 0x0000), "91"},
+		{"foreground light green  ", uint16(0x0002 | 0x0008 | 0x0000), "92"},
+		{"foreground light yellow ", uint16(0x0006 | 0x0008 | 0x0000), "93"},
+		{"foreground light blue   ", uint16(0x0001 | 0x0008 | 0x0000), "94"},
+		{"foreground light magenta", uint16(0x0005 | 0x0008 | 0x0000), "95"},
+		{"foreground light cyan   ", uint16(0x0003 | 0x0008 | 0x0000), "96"},
+		{"foreground light white  ", uint16(0x0007 | 0x0008 | 0x0000), "97"},
+	}
+
+	bgParam := []testParam{
+		{"background black  ", uint16(0x0007 | 0x0000), "40"},
+		{"background red    ", uint16(0x0007 | 0x0040), "41"},
+		{"background green  ", uint16(0x0007 | 0x0020), "42"},
+		{"background yellow ", uint16(0x0007 | 0x0060), "43"},
+		{"background blue   ", uint16(0x0007 | 0x0010), "44"},
+		{"background magenta", uint16(0x0007 | 0x0050), "45"},
+		{"background cyan   ", uint16(0x0007 | 0x0030), "46"},
+		{"background white  ", uint16(0x0007 | 0x0070), "47"},
+		{"background default", uint16(0x0007) | defaultBgColor, "49"},
+		{"background light gray   ", uint16(0x0007 | 0x0000 | 0x0080), "100"},
+		{"background light red    ", uint16(0x0007 | 0x0040 | 0x0080), "101"},
+		{"background light green  ", uint16(0x0007 | 0x0020 | 0x0080), "102"},
+		{"background light yellow ", uint16(0x0007 | 0x0060 | 0x0080), "103"},
+		{"background light blue   ", uint16(0x0007 | 0x0010 | 0x0080), "104"},
+		{"background light magenta", uint16(0x0007 | 0x0050 | 0x0080), "105"},
+		{"background light cyan   ", uint16(0x0007 | 0x0030 | 0x0080), "106"},
+		{"background light white  ", uint16(0x0007 | 0x0070 | 0x0080), "107"},
+	}
+
+	resetParam := []testParam{
+		{"all reset", defaultFgColor | defaultBgColor | defaultFgIntensity | defaultBgIntensity, "0"},
+		{"all reset", defaultFgColor | defaultBgColor | defaultFgIntensity | defaultBgIntensity, ""},
+	}
+
+	boldParam := []testParam{
+		{"bold on", uint16(0x0007 | 0x0008), "1"},
+		{"bold off", uint16(0x0007), "21"},
+	}
+
+	underscoreParam := []testParam{
+		{"underscore on", uint16(0x0007 | 0x8000), "4"},
+		{"underscore off", uint16(0x0007), "24"},
+	}
+
+	blinkParam := []testParam{
+		{"blink on", uint16(0x0007 | 0x0080), "5"},
+		{"blink off", uint16(0x0007), "25"},
+	}
+
+	mixedParam := []testParam{
+		{"both black,   bold, underline, blink", uint16(0x0000 | 0x0000 | 0x0008 | 0x8000 | 0x0080), "30;40;1;4;5"},
+		{"both red,     bold, underline, blink", uint16(0x0004 | 0x0040 | 0x0008 | 0x8000 | 0x0080), "31;41;1;4;5"},
+		{"both green,   bold, underline, blink", uint16(0x0002 | 0x0020 | 0x0008 | 0x8000 | 0x0080), "32;42;1;4;5"},
+		{"both yellow,  bold, underline, blink", uint16(0x0006 | 0x0060 | 0x0008 | 0x8000 | 0x0080), "33;43;1;4;5"},
+		{"both blue,    bold, underline, blink", uint16(0x0001 | 0x0010 | 0x0008 | 0x8000 | 0x0080), "34;44;1;4;5"},
+		{"both magenta, bold, underline, blink", uint16(0x0005 | 0x0050 | 0x0008 | 0x8000 | 0x0080), "35;45;1;4;5"},
+		{"both cyan,    bold, underline, blink", uint16(0x0003 | 0x0030 | 0x0008 | 0x8000 | 0x0080), "36;46;1;4;5"},
+		{"both white,   bold, underline, blink", uint16(0x0007 | 0x0070 | 0x0008 | 0x8000 | 0x0080), "37;47;1;4;5"},
+		{"both default, bold, underline, blink", uint16(defaultFgColor | defaultBgColor | 0x0008 | 0x8000 | 0x0080), "39;49;1;4;5"},
+	}
+
+	assertTextAttribute := func(expectedText string, expectedAttributes uint16, ansiColor string) {
+		actualText, actualAttributes, err := writeAnsiColor(expectedText, ansiColor)
+		if actualText != expectedText {
+			t.Errorf("Get %q, want %q", actualText, expectedText)
+		}
+		if err != nil {
+			t.Fatal("Could not get ConsoleScreenBufferInfo")
+		}
+		if actualAttributes != expectedAttributes {
+			t.Errorf("Text: %q, Get 0x%04x, want 0x%04x", expectedText, actualAttributes, expectedAttributes)
+		}
+	}
+
+	for _, v := range fgParam {
+		ResetColor()
+		assertTextAttribute(v.text, v.attributes, v.ansiColor)
+	}
+
+	for _, v := range bgParam {
+		ChangeColor(uint16(0x0070 | 0x0007))
+		assertTextAttribute(v.text, v.attributes, v.ansiColor)
+	}
+
+	for _, v := range resetParam {
+		ChangeColor(uint16(0x0000 | 0x0070 | 0x0008))
+		assertTextAttribute(v.text, v.attributes, v.ansiColor)
+	}
+
+	ResetColor()
+	for _, v := range boldParam {
+		assertTextAttribute(v.text, v.attributes, v.ansiColor)
+	}
+
+	ResetColor()
+	for _, v := range underscoreParam {
+		assertTextAttribute(v.text, v.attributes, v.ansiColor)
+	}
+
+	ResetColor()
+	for _, v := range blinkParam {
+		assertTextAttribute(v.text, v.attributes, v.ansiColor)
+	}
+
+	for _, v := range mixedParam {
+		ResetColor()
+		assertTextAttribute(v.text, v.attributes, v.ansiColor)
+	}
+}
+
+func TestIgnoreUnknownSequences(t *testing.T) {
+	inner := bytes.NewBufferString("")
+	w := NewModeAnsiColorWriter(inner, OutputNonColorEscSeq)
+
+	inputText := "\x1b[=decpath mode"
+	expectedTail := inputText
+	fmt.Fprintf(w, inputText)
+	actualTail := inner.String()
+	inner.Reset()
+	if actualTail != expectedTail {
+		t.Errorf("Get %q, want %q", actualTail, expectedTail)
+	}
+
+	inputText = "\x1b[=tailing esc and bracket\x1b["
+	expectedTail = inputText
+	fmt.Fprintf(w, inputText)
+	actualTail = inner.String()
+	inner.Reset()
+	if actualTail != expectedTail {
+		t.Errorf("Get %q, want %q", actualTail, expectedTail)
+	}
+
+	inputText = "\x1b[?tailing esc\x1b"
+	expectedTail = inputText
+	fmt.Fprintf(w, inputText)
+	actualTail = inner.String()
+	inner.Reset()
+	if actualTail != expectedTail {
+		t.Errorf("Get %q, want %q", actualTail, expectedTail)
+	}
+
+	inputText = "\x1b[1h;3punended color code invalid\x1b3"
+	expectedTail = inputText
+	fmt.Fprintf(w, inputText)
+	actualTail = inner.String()
+	inner.Reset()
+	if actualTail != expectedTail {
+		t.Errorf("Get %q, want %q", actualTail, expectedTail)
+	}
+}

+ 117 - 0
vendor/github.com/astaxie/beego/logs/conn.go

@@ -0,0 +1,117 @@
+// 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 logs
+
+import (
+	"encoding/json"
+	"io"
+	"net"
+	"time"
+)
+
+// connWriter implements LoggerInterface.
+// it writes messages in keep-live tcp connection.
+type connWriter struct {
+	lg             *logWriter
+	innerWriter    io.WriteCloser
+	ReconnectOnMsg bool   `json:"reconnectOnMsg"`
+	Reconnect      bool   `json:"reconnect"`
+	Net            string `json:"net"`
+	Addr           string `json:"addr"`
+	Level          int    `json:"level"`
+}
+
+// NewConn create new ConnWrite returning as LoggerInterface.
+func NewConn() Logger {
+	conn := new(connWriter)
+	conn.Level = LevelTrace
+	return conn
+}
+
+// Init init connection writer with json config.
+// json config only need key "level".
+func (c *connWriter) Init(jsonConfig string) error {
+	return json.Unmarshal([]byte(jsonConfig), c)
+}
+
+// WriteMsg write message in connection.
+// if connection is down, try to re-connect.
+func (c *connWriter) WriteMsg(when time.Time, msg string, level int) error {
+	if level > c.Level {
+		return nil
+	}
+	if c.needToConnectOnMsg() {
+		err := c.connect()
+		if err != nil {
+			return err
+		}
+	}
+
+	if c.ReconnectOnMsg {
+		defer c.innerWriter.Close()
+	}
+
+	c.lg.println(when, msg)
+	return nil
+}
+
+// Flush implementing method. empty.
+func (c *connWriter) Flush() {
+
+}
+
+// Destroy destroy connection writer and close tcp listener.
+func (c *connWriter) Destroy() {
+	if c.innerWriter != nil {
+		c.innerWriter.Close()
+	}
+}
+
+func (c *connWriter) connect() error {
+	if c.innerWriter != nil {
+		c.innerWriter.Close()
+		c.innerWriter = nil
+	}
+
+	conn, err := net.Dial(c.Net, c.Addr)
+	if err != nil {
+		return err
+	}
+
+	if tcpConn, ok := conn.(*net.TCPConn); ok {
+		tcpConn.SetKeepAlive(true)
+	}
+
+	c.innerWriter = conn
+	c.lg = newLogWriter(conn)
+	return nil
+}
+
+func (c *connWriter) needToConnectOnMsg() bool {
+	if c.Reconnect {
+		c.Reconnect = false
+		return true
+	}
+
+	if c.innerWriter == nil {
+		return true
+	}
+
+	return c.ReconnectOnMsg
+}
+
+func init() {
+	Register(AdapterConn, NewConn)
+}

+ 25 - 0
vendor/github.com/astaxie/beego/logs/conn_test.go

@@ -0,0 +1,25 @@
+// 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 logs
+
+import (
+	"testing"
+)
+
+func TestConn(t *testing.T) {
+	log := NewLogger(1000)
+	log.SetLogger("conn", `{"net":"tcp","addr":":7020"}`)
+	log.Informational("informational")
+}

+ 101 - 0
vendor/github.com/astaxie/beego/logs/console.go

@@ -0,0 +1,101 @@
+// 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 logs
+
+import (
+	"encoding/json"
+	"os"
+	"runtime"
+	"time"
+)
+
+// brush is a color join function
+type brush func(string) string
+
+// newBrush return a fix color Brush
+func newBrush(color string) brush {
+	pre := "\033["
+	reset := "\033[0m"
+	return func(text string) string {
+		return pre + color + "m" + text + reset
+	}
+}
+
+var colors = []brush{
+	newBrush("1;37"), // Emergency          white
+	newBrush("1;36"), // Alert              cyan
+	newBrush("1;35"), // Critical           magenta
+	newBrush("1;31"), // Error              red
+	newBrush("1;33"), // Warning            yellow
+	newBrush("1;32"), // Notice             green
+	newBrush("1;34"), // Informational      blue
+	newBrush("1;44"), // Debug              Background blue
+}
+
+// consoleWriter implements LoggerInterface and writes messages to terminal.
+type consoleWriter struct {
+	lg       *logWriter
+	Level    int  `json:"level"`
+	Colorful bool `json:"color"` //this filed is useful only when system's terminal supports color
+}
+
+// NewConsole create ConsoleWriter returning as LoggerInterface.
+func NewConsole() Logger {
+	cw := &consoleWriter{
+		lg:       newLogWriter(os.Stdout),
+		Level:    LevelDebug,
+		Colorful: runtime.GOOS != "windows",
+	}
+	return cw
+}
+
+// Init init console logger.
+// jsonConfig like '{"level":LevelTrace}'.
+func (c *consoleWriter) Init(jsonConfig string) error {
+	if len(jsonConfig) == 0 {
+		return nil
+	}
+	err := json.Unmarshal([]byte(jsonConfig), c)
+	if runtime.GOOS == "windows" {
+		c.Colorful = false
+	}
+	return err
+}
+
+// WriteMsg write message in console.
+func (c *consoleWriter) WriteMsg(when time.Time, msg string, level int) error {
+	if level > c.Level {
+		return nil
+	}
+	if c.Colorful {
+		msg = colors[level](msg)
+	}
+	c.lg.println(when, msg)
+	return nil
+}
+
+// Destroy implementing method. empty.
+func (c *consoleWriter) Destroy() {
+
+}
+
+// Flush implementing method. empty.
+func (c *consoleWriter) Flush() {
+
+}
+
+func init() {
+	Register(AdapterConsole, NewConsole)
+}

+ 51 - 0
vendor/github.com/astaxie/beego/logs/console_test.go

@@ -0,0 +1,51 @@
+// 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 logs
+
+import (
+	"testing"
+)
+
+// Try each log level in decreasing order of priority.
+func testConsoleCalls(bl *BeeLogger) {
+	bl.Emergency("emergency")
+	bl.Alert("alert")
+	bl.Critical("critical")
+	bl.Error("error")
+	bl.Warning("warning")
+	bl.Notice("notice")
+	bl.Informational("informational")
+	bl.Debug("debug")
+}
+
+// Test console logging by visually comparing the lines being output with and
+// without a log level specification.
+func TestConsole(t *testing.T) {
+	log1 := NewLogger(10000)
+	log1.EnableFuncCallDepth(true)
+	log1.SetLogger("console", "")
+	testConsoleCalls(log1)
+
+	log2 := NewLogger(100)
+	log2.SetLogger("console", `{"level":3}`)
+	testConsoleCalls(log2)
+}
+
+// Test console without color
+func TestConsoleNoColor(t *testing.T) {
+	log := NewLogger(100)
+	log.SetLogger("console", `{"color":false}`)
+	testConsoleCalls(log)
+}

+ 80 - 0
vendor/github.com/astaxie/beego/logs/es/es.go

@@ -0,0 +1,80 @@
+package es
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net"
+	"net/url"
+	"time"
+
+	"github.com/astaxie/beego/logs"
+	"github.com/belogik/goes"
+)
+
+// NewES return a LoggerInterface
+func NewES() logs.Logger {
+	cw := &esLogger{
+		Level: logs.LevelDebug,
+	}
+	return cw
+}
+
+type esLogger struct {
+	*goes.Connection
+	DSN   string `json:"dsn"`
+	Level int    `json:"level"`
+}
+
+// {"dsn":"http://localhost:9200/","level":1}
+func (el *esLogger) Init(jsonconfig string) error {
+	err := json.Unmarshal([]byte(jsonconfig), el)
+	if err != nil {
+		return err
+	}
+	if el.DSN == "" {
+		return errors.New("empty dsn")
+	} else if u, err := url.Parse(el.DSN); err != nil {
+		return err
+	} else if u.Path == "" {
+		return errors.New("missing prefix")
+	} else if host, port, err := net.SplitHostPort(u.Host); err != nil {
+		return err
+	} else {
+		conn := goes.NewConnection(host, port)
+		el.Connection = conn
+	}
+	return nil
+}
+
+// WriteMsg will write the msg and level into es
+func (el *esLogger) WriteMsg(when time.Time, msg string, level int) error {
+	if level > el.Level {
+		return nil
+	}
+
+	vals := make(map[string]interface{})
+	vals["@timestamp"] = when.Format(time.RFC3339)
+	vals["@msg"] = msg
+	d := goes.Document{
+		Index:  fmt.Sprintf("%04d.%02d.%02d", when.Year(), when.Month(), when.Day()),
+		Type:   "logs",
+		Fields: vals,
+	}
+	_, err := el.Index(d, nil)
+	return err
+}
+
+// Destroy is a empty method
+func (el *esLogger) Destroy() {
+
+}
+
+// Flush is a empty method
+func (el *esLogger) Flush() {
+
+}
+
+func init() {
+	logs.Register(logs.AdapterEs, NewES)
+}

+ 327 - 0
vendor/github.com/astaxie/beego/logs/file.go

@@ -0,0 +1,327 @@
+// 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 logs
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+)
+
+// fileLogWriter implements LoggerInterface.
+// It writes messages by lines limit, file size limit, or time frequency.
+type fileLogWriter struct {
+	sync.RWMutex // write log order by order and  atomic incr maxLinesCurLines and maxSizeCurSize
+	// The opened file
+	Filename   string `json:"filename"`
+	fileWriter *os.File
+
+	// Rotate at line
+	MaxLines         int `json:"maxlines"`
+	maxLinesCurLines int
+
+	// Rotate at size
+	MaxSize        int `json:"maxsize"`
+	maxSizeCurSize int
+
+	// Rotate daily
+	Daily         bool  `json:"daily"`
+	MaxDays       int64 `json:"maxdays"`
+	dailyOpenDate int
+	dailyOpenTime time.Time
+
+	Rotate bool `json:"rotate"`
+
+	Level int `json:"level"`
+
+	Perm string `json:"perm"`
+
+	fileNameOnly, suffix string // like "project.log", project is fileNameOnly and .log is suffix
+}
+
+// newFileWriter create a FileLogWriter returning as LoggerInterface.
+func newFileWriter() Logger {
+	w := &fileLogWriter{
+		Daily:   true,
+		MaxDays: 7,
+		Rotate:  true,
+		Level:   LevelTrace,
+		Perm:    "0660",
+	}
+	return w
+}
+
+// Init file logger with json config.
+// jsonConfig like:
+//	{
+//	"filename":"logs/beego.log",
+//	"maxLines":10000,
+//	"maxsize":1024,
+//	"daily":true,
+//	"maxDays":15,
+//	"rotate":true,
+//  	"perm":"0600"
+//	}
+func (w *fileLogWriter) Init(jsonConfig string) error {
+	err := json.Unmarshal([]byte(jsonConfig), w)
+	if err != nil {
+		return err
+	}
+	if len(w.Filename) == 0 {
+		return errors.New("jsonconfig must have filename")
+	}
+	w.suffix = filepath.Ext(w.Filename)
+	w.fileNameOnly = strings.TrimSuffix(w.Filename, w.suffix)
+	if w.suffix == "" {
+		w.suffix = ".log"
+	}
+	err = w.startLogger()
+	return err
+}
+
+// start file logger. create log file and set to locker-inside file writer.
+func (w *fileLogWriter) startLogger() error {
+	file, err := w.createLogFile()
+	if err != nil {
+		return err
+	}
+	if w.fileWriter != nil {
+		w.fileWriter.Close()
+	}
+	w.fileWriter = file
+	return w.initFd()
+}
+
+func (w *fileLogWriter) needRotate(size int, day int) bool {
+	return (w.MaxLines > 0 && w.maxLinesCurLines >= w.MaxLines) ||
+		(w.MaxSize > 0 && w.maxSizeCurSize >= w.MaxSize) ||
+		(w.Daily && day != w.dailyOpenDate)
+
+}
+
+// WriteMsg write logger message into file.
+func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error {
+	if level > w.Level {
+		return nil
+	}
+	h, d := formatTimeHeader(when)
+	msg = string(h) + msg + "\n"
+	if w.Rotate {
+		w.RLock()
+		if w.needRotate(len(msg), d) {
+			w.RUnlock()
+			w.Lock()
+			if w.needRotate(len(msg), d) {
+				if err := w.doRotate(when); err != nil {
+					fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err)
+				}
+			}
+			w.Unlock()
+		} else {
+			w.RUnlock()
+		}
+	}
+
+	w.Lock()
+	_, err := w.fileWriter.Write([]byte(msg))
+	if err == nil {
+		w.maxLinesCurLines++
+		w.maxSizeCurSize += len(msg)
+	}
+	w.Unlock()
+	return err
+}
+
+func (w *fileLogWriter) createLogFile() (*os.File, error) {
+	// Open the log file
+	perm, err := strconv.ParseInt(w.Perm, 8, 64)
+	if err != nil {
+		return nil, err
+	}
+	fd, err := os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(perm))
+	if err == nil {
+		// Make sure file perm is user set perm cause of `os.OpenFile` will obey umask
+		os.Chmod(w.Filename, os.FileMode(perm))
+	}
+	return fd, err
+}
+
+func (w *fileLogWriter) initFd() error {
+	fd := w.fileWriter
+	fInfo, err := fd.Stat()
+	if err != nil {
+		return fmt.Errorf("get stat err: %s", err)
+	}
+	w.maxSizeCurSize = int(fInfo.Size())
+	w.dailyOpenTime = time.Now()
+	w.dailyOpenDate = w.dailyOpenTime.Day()
+	w.maxLinesCurLines = 0
+	if w.Daily {
+		go w.dailyRotate(w.dailyOpenTime)
+	}
+	if fInfo.Size() > 0 {
+		count, err := w.lines()
+		if err != nil {
+			return err
+		}
+		w.maxLinesCurLines = count
+	}
+	return nil
+}
+
+func (w *fileLogWriter) dailyRotate(openTime time.Time) {
+	y, m, d := openTime.Add(24 * time.Hour).Date()
+	nextDay := time.Date(y, m, d, 0, 0, 0, 0, openTime.Location())
+	tm := time.NewTimer(time.Duration(nextDay.UnixNano() - openTime.UnixNano() + 100))
+	<-tm.C
+	w.Lock()
+	if w.needRotate(0, time.Now().Day()) {
+		if err := w.doRotate(time.Now()); err != nil {
+			fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err)
+		}
+	}
+	w.Unlock()
+}
+
+func (w *fileLogWriter) lines() (int, error) {
+	fd, err := os.Open(w.Filename)
+	if err != nil {
+		return 0, err
+	}
+	defer fd.Close()
+
+	buf := make([]byte, 32768) // 32k
+	count := 0
+	lineSep := []byte{'\n'}
+
+	for {
+		c, err := fd.Read(buf)
+		if err != nil && err != io.EOF {
+			return count, err
+		}
+
+		count += bytes.Count(buf[:c], lineSep)
+
+		if err == io.EOF {
+			break
+		}
+	}
+
+	return count, nil
+}
+
+// DoRotate means it need to write file in new file.
+// new file name like xx.2013-01-01.log (daily) or xx.001.log (by line or size)
+func (w *fileLogWriter) doRotate(logTime time.Time) error {
+	// file exists
+	// Find the next available number
+	num := 1
+	fName := ""
+
+	_, err := os.Lstat(w.Filename)
+	if err != nil {
+		//even if the file is not exist or other ,we should RESTART the logger
+		goto RESTART_LOGGER
+	}
+
+	if w.MaxLines > 0 || w.MaxSize > 0 {
+		for ; err == nil && num <= 999; num++ {
+			fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", logTime.Format("2006-01-02"), num, w.suffix)
+			_, err = os.Lstat(fName)
+		}
+	} else {
+		fName = fmt.Sprintf("%s.%s%s", w.fileNameOnly, w.dailyOpenTime.Format("2006-01-02"), w.suffix)
+		_, err = os.Lstat(fName)
+		for ; err == nil && num <= 999; num++ {
+			fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", w.dailyOpenTime.Format("2006-01-02"), num, w.suffix)
+			_, err = os.Lstat(fName)
+		}
+	}
+	// return error if the last file checked still existed
+	if err == nil {
+		return fmt.Errorf("Rotate: Cannot find free log number to rename %s", w.Filename)
+	}
+
+	// close fileWriter before rename
+	w.fileWriter.Close()
+
+	// 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:
+
+	startLoggerErr := w.startLogger()
+	go w.deleteOldLog()
+
+	if startLoggerErr != nil {
+		return fmt.Errorf("Rotate StartLogger: %s", startLoggerErr)
+	}
+	if err != nil {
+		return fmt.Errorf("Rotate: %s", err)
+	}
+	return nil
+}
+
+func (w *fileLogWriter) deleteOldLog() {
+	dir := filepath.Dir(w.Filename)
+	filepath.Walk(dir, func(path string, info os.FileInfo, err error) (returnErr error) {
+		defer func() {
+			if r := recover(); r != nil {
+				fmt.Fprintf(os.Stderr, "Unable to delete old log '%s', error: %v\n", path, r)
+			}
+		}()
+
+		if info == nil {
+			return
+		}
+
+		if !info.IsDir() && info.ModTime().Add(24*time.Hour*time.Duration(w.MaxDays)).Before(time.Now()) {
+			if strings.HasPrefix(filepath.Base(path), filepath.Base(w.fileNameOnly)) &&
+				strings.HasSuffix(filepath.Base(path), w.suffix) {
+				os.Remove(path)
+			}
+		}
+		return
+	})
+}
+
+// Destroy close the file description, close file writer.
+func (w *fileLogWriter) Destroy() {
+	w.fileWriter.Close()
+}
+
+// Flush flush file logger.
+// there are no buffering messages in file logger in memory.
+// flush file means sync file from disk.
+func (w *fileLogWriter) Flush() {
+	w.fileWriter.Sync()
+}
+
+func init() {
+	Register(AdapterFile, newFileWriter)
+}

+ 300 - 0
vendor/github.com/astaxie/beego/logs/file_test.go

@@ -0,0 +1,300 @@
+// 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 logs
+
+import (
+	"bufio"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"strconv"
+	"testing"
+	"time"
+)
+
+func TestFilePerm(t *testing.T) {
+	log := NewLogger(10000)
+	// use 0666 as test perm cause the default umask is 022
+	log.SetLogger("file", `{"filename":"test.log", "perm": "0666"}`)
+	log.Debug("debug")
+	log.Informational("info")
+	log.Notice("notice")
+	log.Warning("warning")
+	log.Error("error")
+	log.Alert("alert")
+	log.Critical("critical")
+	log.Emergency("emergency")
+	file, err := os.Stat("test.log")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if file.Mode() != 0666 {
+		t.Fatal("unexpected log file permission")
+	}
+	os.Remove("test.log")
+}
+
+func TestFile1(t *testing.T) {
+	log := NewLogger(10000)
+	log.SetLogger("file", `{"filename":"test.log"}`)
+	log.Debug("debug")
+	log.Informational("info")
+	log.Notice("notice")
+	log.Warning("warning")
+	log.Error("error")
+	log.Alert("alert")
+	log.Critical("critical")
+	log.Emergency("emergency")
+	f, err := os.Open("test.log")
+	if err != nil {
+		t.Fatal(err)
+	}
+	b := bufio.NewReader(f)
+	lineNum := 0
+	for {
+		line, _, err := b.ReadLine()
+		if err != nil {
+			break
+		}
+		if len(line) > 0 {
+			lineNum++
+		}
+	}
+	var expected = LevelDebug + 1
+	if lineNum != expected {
+		t.Fatal(lineNum, "not "+strconv.Itoa(expected)+" lines")
+	}
+	os.Remove("test.log")
+}
+
+func TestFile2(t *testing.T) {
+	log := NewLogger(10000)
+	log.SetLogger("file", fmt.Sprintf(`{"filename":"test2.log","level":%d}`, LevelError))
+	log.Debug("debug")
+	log.Info("info")
+	log.Notice("notice")
+	log.Warning("warning")
+	log.Error("error")
+	log.Alert("alert")
+	log.Critical("critical")
+	log.Emergency("emergency")
+	f, err := os.Open("test2.log")
+	if err != nil {
+		t.Fatal(err)
+	}
+	b := bufio.NewReader(f)
+	lineNum := 0
+	for {
+		line, _, err := b.ReadLine()
+		if err != nil {
+			break
+		}
+		if len(line) > 0 {
+			lineNum++
+		}
+	}
+	var expected = LevelError + 1
+	if lineNum != expected {
+		t.Fatal(lineNum, "not "+strconv.Itoa(expected)+" lines")
+	}
+	os.Remove("test2.log")
+}
+
+func TestFileRotate_01(t *testing.T) {
+	log := NewLogger(10000)
+	log.SetLogger("file", `{"filename":"test3.log","maxlines":4}`)
+	log.Debug("debug")
+	log.Info("info")
+	log.Notice("notice")
+	log.Warning("warning")
+	log.Error("error")
+	log.Alert("alert")
+	log.Critical("critical")
+	log.Emergency("emergency")
+	rotateName := "test3" + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), 1) + ".log"
+	b, err := exists(rotateName)
+	if !b || err != nil {
+		os.Remove("test3.log")
+		t.Fatal("rotate not generated")
+	}
+	os.Remove(rotateName)
+	os.Remove("test3.log")
+}
+
+func TestFileRotate_02(t *testing.T) {
+	fn1 := "rotate_day.log"
+	fn2 := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".log"
+	testFileRotate(t, fn1, fn2)
+}
+
+func TestFileRotate_03(t *testing.T) {
+	fn1 := "rotate_day.log"
+	fn := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".log"
+	os.Create(fn)
+	fn2 := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".001.log"
+	testFileRotate(t, fn1, fn2)
+	os.Remove(fn)
+}
+
+func TestFileRotate_04(t *testing.T) {
+	fn1 := "rotate_day.log"
+	fn2 := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".log"
+	testFileDailyRotate(t, fn1, fn2)
+}
+
+func TestFileRotate_05(t *testing.T) {
+	fn1 := "rotate_day.log"
+	fn := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".log"
+	os.Create(fn)
+	fn2 := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".001.log"
+	testFileDailyRotate(t, fn1, fn2)
+	os.Remove(fn)
+}
+func TestFileRotate_06(t *testing.T) { //test file mode
+	log := NewLogger(10000)
+	log.SetLogger("file", `{"filename":"test3.log","maxlines":4}`)
+	log.Debug("debug")
+	log.Info("info")
+	log.Notice("notice")
+	log.Warning("warning")
+	log.Error("error")
+	log.Alert("alert")
+	log.Critical("critical")
+	log.Emergency("emergency")
+	rotateName := "test3" + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), 1) + ".log"
+	s, _ := os.Lstat(rotateName)
+	if s.Mode() != 0440 {
+		os.Remove(rotateName)
+		os.Remove("test3.log")
+		t.Fatal("rotate file mode error")
+	}
+	os.Remove(rotateName)
+	os.Remove("test3.log")
+}
+func testFileRotate(t *testing.T, fn1, fn2 string) {
+	fw := &fileLogWriter{
+		Daily:   true,
+		MaxDays: 7,
+		Rotate:  true,
+		Level:   LevelTrace,
+		Perm:    "0660",
+	}
+	fw.Init(fmt.Sprintf(`{"filename":"%v","maxdays":1}`, fn1))
+	fw.dailyOpenTime = time.Now().Add(-24 * time.Hour)
+	fw.dailyOpenDate = fw.dailyOpenTime.Day()
+	fw.WriteMsg(time.Now(), "this is a msg for test", LevelDebug)
+
+	for _, file := range []string{fn1, fn2} {
+		_, err := os.Stat(file)
+		if err != nil {
+			t.FailNow()
+		}
+		os.Remove(file)
+	}
+	fw.Destroy()
+}
+
+func testFileDailyRotate(t *testing.T, fn1, fn2 string) {
+	fw := &fileLogWriter{
+		Daily:   true,
+		MaxDays: 7,
+		Rotate:  true,
+		Level:   LevelTrace,
+		Perm:    "0660",
+	}
+	fw.Init(fmt.Sprintf(`{"filename":"%v","maxdays":1}`, fn1))
+	fw.dailyOpenTime = time.Now().Add(-24 * time.Hour)
+	fw.dailyOpenDate = fw.dailyOpenTime.Day()
+	today, _ := time.ParseInLocation("2006-01-02", time.Now().Format("2006-01-02"), fw.dailyOpenTime.Location())
+	today = today.Add(-1 * time.Second)
+	fw.dailyRotate(today)
+	for _, file := range []string{fn1, fn2} {
+		_, err := os.Stat(file)
+		if err != nil {
+			t.FailNow()
+		}
+		content, err := ioutil.ReadFile(file)
+		if err != nil {
+			t.FailNow()
+		}
+		if len(content) > 0 {
+			t.FailNow()
+		}
+		os.Remove(file)
+	}
+	fw.Destroy()
+}
+
+func exists(path string) (bool, error) {
+	_, err := os.Stat(path)
+	if err == nil {
+		return true, nil
+	}
+	if os.IsNotExist(err) {
+		return false, nil
+	}
+	return false, err
+}
+
+func BenchmarkFile(b *testing.B) {
+	log := NewLogger(100000)
+	log.SetLogger("file", `{"filename":"test4.log"}`)
+	for i := 0; i < b.N; i++ {
+		log.Debug("debug")
+	}
+	os.Remove("test4.log")
+}
+
+func BenchmarkFileAsynchronous(b *testing.B) {
+	log := NewLogger(100000)
+	log.SetLogger("file", `{"filename":"test4.log"}`)
+	log.Async()
+	for i := 0; i < b.N; i++ {
+		log.Debug("debug")
+	}
+	os.Remove("test4.log")
+}
+
+func BenchmarkFileCallDepth(b *testing.B) {
+	log := NewLogger(100000)
+	log.SetLogger("file", `{"filename":"test4.log"}`)
+	log.EnableFuncCallDepth(true)
+	log.SetLogFuncCallDepth(2)
+	for i := 0; i < b.N; i++ {
+		log.Debug("debug")
+	}
+	os.Remove("test4.log")
+}
+
+func BenchmarkFileAsynchronousCallDepth(b *testing.B) {
+	log := NewLogger(100000)
+	log.SetLogger("file", `{"filename":"test4.log"}`)
+	log.EnableFuncCallDepth(true)
+	log.SetLogFuncCallDepth(2)
+	log.Async()
+	for i := 0; i < b.N; i++ {
+		log.Debug("debug")
+	}
+	os.Remove("test4.log")
+}
+
+func BenchmarkFileOnGoroutine(b *testing.B) {
+	log := NewLogger(100000)
+	log.SetLogger("file", `{"filename":"test4.log"}`)
+	for i := 0; i < b.N; i++ {
+		go log.Debug("debug")
+	}
+	os.Remove("test4.log")
+}

+ 72 - 0
vendor/github.com/astaxie/beego/logs/jianliao.go

@@ -0,0 +1,72 @@
+package logs
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"net/url"
+	"time"
+)
+
+// JLWriter implements beego LoggerInterface and is used to send jiaoliao webhook
+type JLWriter struct {
+	AuthorName  string `json:"authorname"`
+	Title       string `json:"title"`
+	WebhookURL  string `json:"webhookurl"`
+	RedirectURL string `json:"redirecturl,omitempty"`
+	ImageURL    string `json:"imageurl,omitempty"`
+	Level       int    `json:"level"`
+}
+
+// newJLWriter create jiaoliao writer.
+func newJLWriter() Logger {
+	return &JLWriter{Level: LevelTrace}
+}
+
+// Init JLWriter with json config string
+func (s *JLWriter) Init(jsonconfig string) error {
+	return json.Unmarshal([]byte(jsonconfig), s)
+}
+
+// WriteMsg write message in smtp writer.
+// it will send an email with subject and only this message.
+func (s *JLWriter) WriteMsg(when time.Time, msg string, level int) error {
+	if level > s.Level {
+		return nil
+	}
+
+	text := fmt.Sprintf("%s %s", when.Format("2006-01-02 15:04:05"), msg)
+
+	form := url.Values{}
+	form.Add("authorName", s.AuthorName)
+	form.Add("title", s.Title)
+	form.Add("text", text)
+	if s.RedirectURL != "" {
+		form.Add("redirectUrl", s.RedirectURL)
+	}
+	if s.ImageURL != "" {
+		form.Add("imageUrl", s.ImageURL)
+	}
+
+	resp, err := http.PostForm(s.WebhookURL, form)
+	if err != nil {
+		return err
+	}
+	defer resp.Body.Close()
+	if resp.StatusCode != http.StatusOK {
+		return fmt.Errorf("Post webhook failed %s %d", resp.Status, resp.StatusCode)
+	}
+	return nil
+}
+
+// Flush implementing method. empty.
+func (s *JLWriter) Flush() {
+}
+
+// Destroy implementing method. empty.
+func (s *JLWriter) Destroy() {
+}
+
+func init() {
+	Register(AdapterJianLiao, newJLWriter)
+}

+ 646 - 0
vendor/github.com/astaxie/beego/logs/log.go

@@ -0,0 +1,646 @@
+// 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 logs provide a general log interface
+// Usage:
+//
+// import "github.com/astaxie/beego/logs"
+//
+//	log := NewLogger(10000)
+//	log.SetLogger("console", "")
+//
+//	> the first params stand for how many channel
+//
+// Use it like this:
+//
+//	log.Trace("trace")
+//	log.Info("info")
+//	log.Warn("warning")
+//	log.Debug("debug")
+//	log.Critical("critical")
+//
+//  more docs http://beego.me/docs/module/logs.md
+package logs
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"path"
+	"runtime"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+)
+
+// RFC5424 log message levels.
+const (
+	LevelEmergency = iota
+	LevelAlert
+	LevelCritical
+	LevelError
+	LevelWarning
+	LevelNotice
+	LevelInformational
+	LevelDebug
+)
+
+// levelLogLogger is defined to implement log.Logger
+// the real log level will be LevelEmergency
+const levelLoggerImpl = -1
+
+// Name for adapter with beego official support
+const (
+	AdapterConsole   = "console"
+	AdapterFile      = "file"
+	AdapterMultiFile = "multifile"
+	AdapterMail      = "smtp"
+	AdapterConn      = "conn"
+	AdapterEs        = "es"
+	AdapterJianLiao  = "jianliao"
+	AdapterSlack     = "slack"
+	AdapterAliLS     = "alils"
+)
+
+// Legacy log level constants to ensure backwards compatibility.
+const (
+	LevelInfo  = LevelInformational
+	LevelTrace = LevelDebug
+	LevelWarn  = LevelWarning
+)
+
+type newLoggerFunc func() Logger
+
+// Logger defines the behavior of a log provider.
+type Logger interface {
+	Init(config string) error
+	WriteMsg(when time.Time, msg string, level int) error
+	Destroy()
+	Flush()
+}
+
+var adapters = make(map[string]newLoggerFunc)
+var levelPrefix = [LevelDebug + 1]string{"[M] ", "[A] ", "[C] ", "[E] ", "[W] ", "[N] ", "[I] ", "[D] "}
+
+// Register makes a log provide available by the provided name.
+// If Register is called twice with the same name or if driver is nil,
+// it panics.
+func Register(name string, log newLoggerFunc) {
+	if log == nil {
+		panic("logs: Register provide is nil")
+	}
+	if _, dup := adapters[name]; dup {
+		panic("logs: Register called twice for provider " + name)
+	}
+	adapters[name] = log
+}
+
+// BeeLogger is default logger in beego application.
+// it can contain several providers and log message into all providers.
+type BeeLogger struct {
+	lock                sync.Mutex
+	level               int
+	init                bool
+	enableFuncCallDepth bool
+	loggerFuncCallDepth int
+	asynchronous        bool
+	msgChanLen          int64
+	msgChan             chan *logMsg
+	signalChan          chan string
+	wg                  sync.WaitGroup
+	outputs             []*nameLogger
+}
+
+const defaultAsyncMsgLen = 1e3
+
+type nameLogger struct {
+	Logger
+	name string
+}
+
+type logMsg struct {
+	level int
+	msg   string
+	when  time.Time
+}
+
+var logMsgPool *sync.Pool
+
+// NewLogger returns a new BeeLogger.
+// channelLen means the number of messages in chan(used where asynchronous is true).
+// if the buffering chan is full, logger adapters write to file or other way.
+func NewLogger(channelLens ...int64) *BeeLogger {
+	bl := new(BeeLogger)
+	bl.level = LevelDebug
+	bl.loggerFuncCallDepth = 2
+	bl.msgChanLen = append(channelLens, 0)[0]
+	if bl.msgChanLen <= 0 {
+		bl.msgChanLen = defaultAsyncMsgLen
+	}
+	bl.signalChan = make(chan string, 1)
+	bl.setLogger(AdapterConsole)
+	return bl
+}
+
+// Async set the log to asynchronous and start the goroutine
+func (bl *BeeLogger) Async(msgLen ...int64) *BeeLogger {
+	bl.lock.Lock()
+	defer bl.lock.Unlock()
+	if bl.asynchronous {
+		return bl
+	}
+	bl.asynchronous = true
+	if len(msgLen) > 0 && msgLen[0] > 0 {
+		bl.msgChanLen = msgLen[0]
+	}
+	bl.msgChan = make(chan *logMsg, bl.msgChanLen)
+	logMsgPool = &sync.Pool{
+		New: func() interface{} {
+			return &logMsg{}
+		},
+	}
+	bl.wg.Add(1)
+	go bl.startLogger()
+	return bl
+}
+
+// SetLogger provides a given logger adapter into BeeLogger with config string.
+// config need to be correct JSON as string: {"interval":360}.
+func (bl *BeeLogger) setLogger(adapterName string, configs ...string) error {
+	config := append(configs, "{}")[0]
+	for _, l := range bl.outputs {
+		if l.name == adapterName {
+			return fmt.Errorf("logs: duplicate adaptername %q (you have set this logger before)", adapterName)
+		}
+	}
+
+	log, ok := adapters[adapterName]
+	if !ok {
+		return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName)
+	}
+
+	lg := log()
+	err := lg.Init(config)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, "logs.BeeLogger.SetLogger: "+err.Error())
+		return err
+	}
+	bl.outputs = append(bl.outputs, &nameLogger{name: adapterName, Logger: lg})
+	return nil
+}
+
+// SetLogger provides a given logger adapter into BeeLogger with config string.
+// config need to be correct JSON as string: {"interval":360}.
+func (bl *BeeLogger) SetLogger(adapterName string, configs ...string) error {
+	bl.lock.Lock()
+	defer bl.lock.Unlock()
+	if !bl.init {
+		bl.outputs = []*nameLogger{}
+		bl.init = true
+	}
+	return bl.setLogger(adapterName, configs...)
+}
+
+// DelLogger remove a logger adapter in BeeLogger.
+func (bl *BeeLogger) DelLogger(adapterName string) error {
+	bl.lock.Lock()
+	defer bl.lock.Unlock()
+	outputs := []*nameLogger{}
+	for _, lg := range bl.outputs {
+		if lg.name == adapterName {
+			lg.Destroy()
+		} else {
+			outputs = append(outputs, lg)
+		}
+	}
+	if len(outputs) == len(bl.outputs) {
+		return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName)
+	}
+	bl.outputs = outputs
+	return nil
+}
+
+func (bl *BeeLogger) writeToLoggers(when time.Time, msg string, level int) {
+	for _, l := range bl.outputs {
+		err := l.WriteMsg(when, msg, level)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "unable to WriteMsg to adapter:%v,error:%v\n", l.name, err)
+		}
+	}
+}
+
+func (bl *BeeLogger) Write(p []byte) (n int, err error) {
+	if len(p) == 0 {
+		return 0, nil
+	}
+	// writeMsg will always add a '\n' character
+	if p[len(p)-1] == '\n' {
+		p = p[0 : len(p)-1]
+	}
+	// set levelLoggerImpl to ensure all log message will be write out
+	err = bl.writeMsg(levelLoggerImpl, string(p))
+	if err == nil {
+		return len(p), err
+	}
+	return 0, err
+}
+
+func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error {
+	if !bl.init {
+		bl.lock.Lock()
+		bl.setLogger(AdapterConsole)
+		bl.lock.Unlock()
+	}
+
+	if len(v) > 0 {
+		msg = fmt.Sprintf(msg, v...)
+	}
+	when := time.Now()
+	if bl.enableFuncCallDepth {
+		_, file, line, ok := runtime.Caller(bl.loggerFuncCallDepth)
+		if !ok {
+			file = "???"
+			line = 0
+		}
+		_, filename := path.Split(file)
+		msg = "[" + filename + ":" + strconv.Itoa(line) + "] " + msg
+	}
+
+	//set level info in front of filename info
+	if logLevel == levelLoggerImpl {
+		// set to emergency to ensure all log will be print out correctly
+		logLevel = LevelEmergency
+	} else {
+		msg = levelPrefix[logLevel] + msg
+	}
+
+	if bl.asynchronous {
+		lm := logMsgPool.Get().(*logMsg)
+		lm.level = logLevel
+		lm.msg = msg
+		lm.when = when
+		bl.msgChan <- lm
+	} else {
+		bl.writeToLoggers(when, msg, logLevel)
+	}
+	return nil
+}
+
+// SetLevel Set log message level.
+// If message level (such as LevelDebug) is higher than logger level (such as LevelWarning),
+// log providers will not even be sent the message.
+func (bl *BeeLogger) SetLevel(l int) {
+	bl.level = l
+}
+
+// SetLogFuncCallDepth set log funcCallDepth
+func (bl *BeeLogger) SetLogFuncCallDepth(d int) {
+	bl.loggerFuncCallDepth = d
+}
+
+// GetLogFuncCallDepth return log funcCallDepth for wrapper
+func (bl *BeeLogger) GetLogFuncCallDepth() int {
+	return bl.loggerFuncCallDepth
+}
+
+// EnableFuncCallDepth enable log funcCallDepth
+func (bl *BeeLogger) EnableFuncCallDepth(b bool) {
+	bl.enableFuncCallDepth = b
+}
+
+// start logger chan reading.
+// when chan is not empty, write logs.
+func (bl *BeeLogger) startLogger() {
+	gameOver := false
+	for {
+		select {
+		case bm := <-bl.msgChan:
+			bl.writeToLoggers(bm.when, bm.msg, bm.level)
+			logMsgPool.Put(bm)
+		case sg := <-bl.signalChan:
+			// Now should only send "flush" or "close" to bl.signalChan
+			bl.flush()
+			if sg == "close" {
+				for _, l := range bl.outputs {
+					l.Destroy()
+				}
+				bl.outputs = nil
+				gameOver = true
+			}
+			bl.wg.Done()
+		}
+		if gameOver {
+			break
+		}
+	}
+}
+
+// Emergency Log EMERGENCY level message.
+func (bl *BeeLogger) Emergency(format string, v ...interface{}) {
+	if LevelEmergency > bl.level {
+		return
+	}
+	bl.writeMsg(LevelEmergency, format, v...)
+}
+
+// Alert Log ALERT level message.
+func (bl *BeeLogger) Alert(format string, v ...interface{}) {
+	if LevelAlert > bl.level {
+		return
+	}
+	bl.writeMsg(LevelAlert, format, v...)
+}
+
+// Critical Log CRITICAL level message.
+func (bl *BeeLogger) Critical(format string, v ...interface{}) {
+	if LevelCritical > bl.level {
+		return
+	}
+	bl.writeMsg(LevelCritical, format, v...)
+}
+
+// Error Log ERROR level message.
+func (bl *BeeLogger) Error(format string, v ...interface{}) {
+	if LevelError > bl.level {
+		return
+	}
+	bl.writeMsg(LevelError, format, v...)
+}
+
+// Warning Log WARNING level message.
+func (bl *BeeLogger) Warning(format string, v ...interface{}) {
+	if LevelWarn > bl.level {
+		return
+	}
+	bl.writeMsg(LevelWarn, format, v...)
+}
+
+// Notice Log NOTICE level message.
+func (bl *BeeLogger) Notice(format string, v ...interface{}) {
+	if LevelNotice > bl.level {
+		return
+	}
+	bl.writeMsg(LevelNotice, format, v...)
+}
+
+// Informational Log INFORMATIONAL level message.
+func (bl *BeeLogger) Informational(format string, v ...interface{}) {
+	if LevelInfo > bl.level {
+		return
+	}
+	bl.writeMsg(LevelInfo, format, v...)
+}
+
+// Debug Log DEBUG level message.
+func (bl *BeeLogger) Debug(format string, v ...interface{}) {
+	if LevelDebug > bl.level {
+		return
+	}
+	bl.writeMsg(LevelDebug, format, v...)
+}
+
+// Warn Log WARN level message.
+// compatibility alias for Warning()
+func (bl *BeeLogger) Warn(format string, v ...interface{}) {
+	if LevelWarn > bl.level {
+		return
+	}
+	bl.writeMsg(LevelWarn, format, v...)
+}
+
+// Info Log INFO level message.
+// compatibility alias for Informational()
+func (bl *BeeLogger) Info(format string, v ...interface{}) {
+	if LevelInfo > bl.level {
+		return
+	}
+	bl.writeMsg(LevelInfo, format, v...)
+}
+
+// Trace Log TRACE level message.
+// compatibility alias for Debug()
+func (bl *BeeLogger) Trace(format string, v ...interface{}) {
+	if LevelDebug > bl.level {
+		return
+	}
+	bl.writeMsg(LevelDebug, format, v...)
+}
+
+// Flush flush all chan data.
+func (bl *BeeLogger) Flush() {
+	if bl.asynchronous {
+		bl.signalChan <- "flush"
+		bl.wg.Wait()
+		bl.wg.Add(1)
+		return
+	}
+	bl.flush()
+}
+
+// Close close logger, flush all chan data and destroy all adapters in BeeLogger.
+func (bl *BeeLogger) Close() {
+	if bl.asynchronous {
+		bl.signalChan <- "close"
+		bl.wg.Wait()
+		close(bl.msgChan)
+	} else {
+		bl.flush()
+		for _, l := range bl.outputs {
+			l.Destroy()
+		}
+		bl.outputs = nil
+	}
+	close(bl.signalChan)
+}
+
+// Reset close all outputs, and set bl.outputs to nil
+func (bl *BeeLogger) Reset() {
+	bl.Flush()
+	for _, l := range bl.outputs {
+		l.Destroy()
+	}
+	bl.outputs = nil
+}
+
+func (bl *BeeLogger) flush() {
+	if bl.asynchronous {
+		for {
+			if len(bl.msgChan) > 0 {
+				bm := <-bl.msgChan
+				bl.writeToLoggers(bm.when, bm.msg, bm.level)
+				logMsgPool.Put(bm)
+				continue
+			}
+			break
+		}
+	}
+	for _, l := range bl.outputs {
+		l.Flush()
+	}
+}
+
+// beeLogger references the used application logger.
+var beeLogger = NewLogger()
+
+// GetBeeLogger returns the default BeeLogger
+func GetBeeLogger() *BeeLogger {
+	return beeLogger
+}
+
+var beeLoggerMap = struct {
+	sync.RWMutex
+	logs map[string]*log.Logger
+}{
+	logs: map[string]*log.Logger{},
+}
+
+// GetLogger returns the default BeeLogger
+func GetLogger(prefixes ...string) *log.Logger {
+	prefix := append(prefixes, "")[0]
+	if prefix != "" {
+		prefix = fmt.Sprintf(`[%s] `, strings.ToUpper(prefix))
+	}
+	beeLoggerMap.RLock()
+	l, ok := beeLoggerMap.logs[prefix]
+	if ok {
+		beeLoggerMap.RUnlock()
+		return l
+	}
+	beeLoggerMap.RUnlock()
+	beeLoggerMap.Lock()
+	defer beeLoggerMap.Unlock()
+	l, ok = beeLoggerMap.logs[prefix]
+	if !ok {
+		l = log.New(beeLogger, prefix, 0)
+		beeLoggerMap.logs[prefix] = l
+	}
+	return l
+}
+
+// Reset will remove all the adapter
+func Reset() {
+	beeLogger.Reset()
+}
+
+// Async set the beelogger with Async mode and hold msglen messages
+func Async(msgLen ...int64) *BeeLogger {
+	return beeLogger.Async(msgLen...)
+}
+
+// SetLevel sets the global log level used by the simple logger.
+func SetLevel(l int) {
+	beeLogger.SetLevel(l)
+}
+
+// EnableFuncCallDepth enable log funcCallDepth
+func EnableFuncCallDepth(b bool) {
+	beeLogger.enableFuncCallDepth = b
+}
+
+// SetLogFuncCall set the CallDepth, default is 4
+func SetLogFuncCall(b bool) {
+	beeLogger.EnableFuncCallDepth(b)
+	beeLogger.SetLogFuncCallDepth(4)
+}
+
+// SetLogFuncCallDepth set log funcCallDepth
+func SetLogFuncCallDepth(d int) {
+	beeLogger.loggerFuncCallDepth = d
+}
+
+// SetLogger sets a new logger.
+func SetLogger(adapter string, config ...string) error {
+	return beeLogger.SetLogger(adapter, config...)
+}
+
+// Emergency logs a message at emergency level.
+func Emergency(f interface{}, v ...interface{}) {
+	beeLogger.Emergency(formatLog(f, v...))
+}
+
+// Alert logs a message at alert level.
+func Alert(f interface{}, v ...interface{}) {
+	beeLogger.Alert(formatLog(f, v...))
+}
+
+// Critical logs a message at critical level.
+func Critical(f interface{}, v ...interface{}) {
+	beeLogger.Critical(formatLog(f, v...))
+}
+
+// Error logs a message at error level.
+func Error(f interface{}, v ...interface{}) {
+	beeLogger.Error(formatLog(f, v...))
+}
+
+// Warning logs a message at warning level.
+func Warning(f interface{}, v ...interface{}) {
+	beeLogger.Warn(formatLog(f, v...))
+}
+
+// Warn compatibility alias for Warning()
+func Warn(f interface{}, v ...interface{}) {
+	beeLogger.Warn(formatLog(f, v...))
+}
+
+// Notice logs a message at notice level.
+func Notice(f interface{}, v ...interface{}) {
+	beeLogger.Notice(formatLog(f, v...))
+}
+
+// Informational logs a message at info level.
+func Informational(f interface{}, v ...interface{}) {
+	beeLogger.Info(formatLog(f, v...))
+}
+
+// Info compatibility alias for Warning()
+func Info(f interface{}, v ...interface{}) {
+	beeLogger.Info(formatLog(f, v...))
+}
+
+// Debug logs a message at debug level.
+func Debug(f interface{}, v ...interface{}) {
+	beeLogger.Debug(formatLog(f, v...))
+}
+
+// Trace logs a message at trace level.
+// compatibility alias for Warning()
+func Trace(f interface{}, v ...interface{}) {
+	beeLogger.Trace(formatLog(f, v...))
+}
+
+func formatLog(f interface{}, v ...interface{}) string {
+	var msg string
+	switch f.(type) {
+	case string:
+		msg = f.(string)
+		if len(v) == 0 {
+			return msg
+		}
+		if strings.Contains(msg, "%") && !strings.Contains(msg, "%%") {
+			//format string
+		} else {
+			//do not contain format char
+			msg += strings.Repeat(" %v", len(v))
+		}
+	default:
+		msg = fmt.Sprint(f)
+		if len(v) == 0 {
+			return msg
+		}
+		msg += strings.Repeat(" %v", len(v))
+	}
+	return fmt.Sprintf(msg, v...)
+}

+ 201 - 0
vendor/github.com/astaxie/beego/logs/logger.go

@@ -0,0 +1,201 @@
+// 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 logs
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"sync"
+	"time"
+)
+
+type logWriter struct {
+	sync.Mutex
+	writer io.Writer
+}
+
+func newLogWriter(wr io.Writer) *logWriter {
+	return &logWriter{writer: wr}
+}
+
+func (lg *logWriter) println(when time.Time, msg string) {
+	lg.Lock()
+	h, _ := formatTimeHeader(when)
+	lg.writer.Write(append(append(h, msg...), '\n'))
+	lg.Unlock()
+}
+
+type outputMode int
+
+// DiscardNonColorEscSeq supports the divided color escape sequence.
+// But non-color escape sequence is not output.
+// Please use the OutputNonColorEscSeq If you want to output a non-color
+// escape sequences such as ncurses. However, it does not support the divided
+// color escape sequence.
+const (
+	_ outputMode = iota
+	DiscardNonColorEscSeq
+	OutputNonColorEscSeq
+)
+
+// NewAnsiColorWriter creates and initializes a new ansiColorWriter
+// using io.Writer w as its initial contents.
+// In the console of Windows, which change the foreground and background
+// colors of the text by the escape sequence.
+// In the console of other systems, which writes to w all text.
+func NewAnsiColorWriter(w io.Writer) io.Writer {
+	return NewModeAnsiColorWriter(w, DiscardNonColorEscSeq)
+}
+
+// NewModeAnsiColorWriter create and initializes a new ansiColorWriter
+// by specifying the outputMode.
+func NewModeAnsiColorWriter(w io.Writer, mode outputMode) io.Writer {
+	if _, ok := w.(*ansiColorWriter); !ok {
+		return &ansiColorWriter{
+			w:    w,
+			mode: mode,
+		}
+	}
+	return w
+}
+
+const (
+	y1  = `0123456789`
+	y2  = `0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789`
+	y3  = `0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999`
+	y4  = `0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789`
+	mo1 = `000000000111`
+	mo2 = `123456789012`
+	d1  = `0000000001111111111222222222233`
+	d2  = `1234567890123456789012345678901`
+	h1  = `000000000011111111112222`
+	h2  = `012345678901234567890123`
+	mi1 = `000000000011111111112222222222333333333344444444445555555555`
+	mi2 = `012345678901234567890123456789012345678901234567890123456789`
+	s1  = `000000000011111111112222222222333333333344444444445555555555`
+	s2  = `012345678901234567890123456789012345678901234567890123456789`
+)
+
+func formatTimeHeader(when time.Time) ([]byte, int) {
+	y, mo, d := when.Date()
+	h, mi, s := when.Clock()
+	//len("2006/01/02 15:04:05 ")==20
+	var buf [20]byte
+
+	buf[0] = y1[y/1000%10]
+	buf[1] = y2[y/100]
+	buf[2] = y3[y-y/100*100]
+	buf[3] = y4[y-y/100*100]
+	buf[4] = '/'
+	buf[5] = mo1[mo-1]
+	buf[6] = mo2[mo-1]
+	buf[7] = '/'
+	buf[8] = d1[d-1]
+	buf[9] = d2[d-1]
+	buf[10] = ' '
+	buf[11] = h1[h]
+	buf[12] = h2[h]
+	buf[13] = ':'
+	buf[14] = mi1[mi]
+	buf[15] = mi2[mi]
+	buf[16] = ':'
+	buf[17] = s1[s]
+	buf[18] = s2[s]
+	buf[19] = ' '
+
+	return buf[0:], d
+}
+
+var (
+	green   = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
+	white   = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
+	yellow  = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
+	red     = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
+	blue    = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
+	magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
+	cyan    = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
+
+	w32Green   = string([]byte{27, 91, 52, 50, 109})
+	w32White   = string([]byte{27, 91, 52, 55, 109})
+	w32Yellow  = string([]byte{27, 91, 52, 51, 109})
+	w32Red     = string([]byte{27, 91, 52, 49, 109})
+	w32Blue    = string([]byte{27, 91, 52, 52, 109})
+	w32Magenta = string([]byte{27, 91, 52, 53, 109})
+	w32Cyan    = string([]byte{27, 91, 52, 54, 109})
+
+	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:
+		return map[bool]string{true: green, false: w32Green}[cond]
+	case code >= 300 && code < 400:
+		return map[bool]string{true: white, false: w32White}[cond]
+	case code >= 400 && code < 500:
+		return map[bool]string{true: yellow, false: w32Yellow}[cond]
+	default:
+		return map[bool]string{true: red, false: w32Red}[cond]
+	}
+}
+
+// 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":
+		return map[bool]string{true: blue, false: w32Blue}[cond]
+	case "POST":
+		return map[bool]string{true: cyan, false: w32Cyan}[cond]
+	case "PUT":
+		return map[bool]string{true: yellow, false: w32Yellow}[cond]
+	case "DELETE":
+		return map[bool]string{true: red, false: w32Red}[cond]
+	case "PATCH":
+		return map[bool]string{true: green, false: w32Green}[cond]
+	case "HEAD":
+		return map[bool]string{true: magenta, false: w32Magenta}[cond]
+	case "OPTIONS":
+		return map[bool]string{true: white, false: w32White}[cond]
+	default:
+		return reset
+	}
+}
+
+// Guard Mutex to guarantee atomic of W32Debug(string) function
+var mu sync.Mutex
+
+// W32Debug Helper method to output colored logs in Windows terminals
+func W32Debug(msg string) {
+	mu.Lock()
+	defer mu.Unlock()
+
+	current := time.Now()
+	w := NewAnsiColorWriter(os.Stdout)
+
+	fmt.Fprintf(w, "[beego] %v %s\n", current.Format("2006/01/02 - 15:04:05"), msg)
+}

+ 75 - 0
vendor/github.com/astaxie/beego/logs/logger_test.go

@@ -0,0 +1,75 @@
+// Copyright 2016 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 logs
+
+import (
+	"bytes"
+	"testing"
+	"time"
+)
+
+func TestFormatHeader_0(t *testing.T) {
+	tm := time.Now()
+	if tm.Year() >= 2100 {
+		t.FailNow()
+	}
+	dur := time.Second
+	for {
+		if tm.Year() >= 2100 {
+			break
+		}
+		h, _ := formatTimeHeader(tm)
+		if tm.Format("2006/01/02 15:04:05 ") != string(h) {
+			t.Log(tm)
+			t.FailNow()
+		}
+		tm = tm.Add(dur)
+		dur *= 2
+	}
+}
+
+func TestFormatHeader_1(t *testing.T) {
+	tm := time.Now()
+	year := tm.Year()
+	dur := time.Second
+	for {
+		if tm.Year() >= year+1 {
+			break
+		}
+		h, _ := formatTimeHeader(tm)
+		if tm.Format("2006/01/02 15:04:05 ") != string(h) {
+			t.Log(tm)
+			t.FailNow()
+		}
+		tm = tm.Add(dur)
+	}
+}
+
+func TestNewAnsiColor1(t *testing.T) {
+	inner := bytes.NewBufferString("")
+	w := NewAnsiColorWriter(inner)
+	if w == inner {
+		t.Errorf("Get %#v, want %#v", w, inner)
+	}
+}
+
+func TestNewAnsiColor2(t *testing.T) {
+	inner := bytes.NewBufferString("")
+	w1 := NewAnsiColorWriter(inner)
+	w2 := NewAnsiColorWriter(w1)
+	if w1 != w2 {
+		t.Errorf("Get %#v, want %#v", w1, w2)
+	}
+}

+ 116 - 0
vendor/github.com/astaxie/beego/logs/multifile.go

@@ -0,0 +1,116 @@
+// 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 logs
+
+import (
+	"encoding/json"
+	"time"
+)
+
+// A filesLogWriter manages several fileLogWriter
+// filesLogWriter will write logs to the file in json configuration  and write the same level log to correspond file
+// means if the file name in configuration is project.log filesLogWriter will create project.error.log/project.debug.log
+// and write the error-level logs to project.error.log and write the debug-level logs to project.debug.log
+// the rotate attribute also  acts like fileLogWriter
+type multiFileLogWriter struct {
+	writers       [LevelDebug + 1 + 1]*fileLogWriter // the last one for fullLogWriter
+	fullLogWriter *fileLogWriter
+	Separate      []string `json:"separate"`
+}
+
+var levelNames = [...]string{"emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"}
+
+// Init file logger with json config.
+// jsonConfig like:
+//	{
+//	"filename":"logs/beego.log",
+//	"maxLines":0,
+//	"maxsize":0,
+//	"daily":true,
+//	"maxDays":15,
+//	"rotate":true,
+//  	"perm":0600,
+//	"separate":["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"],
+//	}
+
+func (f *multiFileLogWriter) Init(config string) error {
+	writer := newFileWriter().(*fileLogWriter)
+	err := writer.Init(config)
+	if err != nil {
+		return err
+	}
+	f.fullLogWriter = writer
+	f.writers[LevelDebug+1] = writer
+
+	//unmarshal "separate" field to f.Separate
+	json.Unmarshal([]byte(config), f)
+
+	jsonMap := map[string]interface{}{}
+	json.Unmarshal([]byte(config), &jsonMap)
+
+	for i := LevelEmergency; i < LevelDebug+1; i++ {
+		for _, v := range f.Separate {
+			if v == levelNames[i] {
+				jsonMap["filename"] = f.fullLogWriter.fileNameOnly + "." + levelNames[i] + f.fullLogWriter.suffix
+				jsonMap["level"] = i
+				bs, _ := json.Marshal(jsonMap)
+				writer = newFileWriter().(*fileLogWriter)
+				writer.Init(string(bs))
+				f.writers[i] = writer
+			}
+		}
+	}
+
+	return nil
+}
+
+func (f *multiFileLogWriter) Destroy() {
+	for i := 0; i < len(f.writers); i++ {
+		if f.writers[i] != nil {
+			f.writers[i].Destroy()
+		}
+	}
+}
+
+func (f *multiFileLogWriter) WriteMsg(when time.Time, msg string, level int) error {
+	if f.fullLogWriter != nil {
+		f.fullLogWriter.WriteMsg(when, msg, level)
+	}
+	for i := 0; i < len(f.writers)-1; i++ {
+		if f.writers[i] != nil {
+			if level == f.writers[i].Level {
+				f.writers[i].WriteMsg(when, msg, level)
+			}
+		}
+	}
+	return nil
+}
+
+func (f *multiFileLogWriter) Flush() {
+	for i := 0; i < len(f.writers); i++ {
+		if f.writers[i] != nil {
+			f.writers[i].Flush()
+		}
+	}
+}
+
+// newFilesWriter create a FileLogWriter returning as LoggerInterface.
+func newFilesWriter() Logger {
+	return &multiFileLogWriter{}
+}
+
+func init() {
+	Register(AdapterMultiFile, newFilesWriter)
+}

+ 78 - 0
vendor/github.com/astaxie/beego/logs/multifile_test.go

@@ -0,0 +1,78 @@
+// 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 logs
+
+import (
+	"bufio"
+	"os"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+func TestFiles_1(t *testing.T) {
+	log := NewLogger(10000)
+	log.SetLogger("multifile", `{"filename":"test.log","separate":["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"]}`)
+	log.Debug("debug")
+	log.Informational("info")
+	log.Notice("notice")
+	log.Warning("warning")
+	log.Error("error")
+	log.Alert("alert")
+	log.Critical("critical")
+	log.Emergency("emergency")
+	fns := []string{""}
+	fns = append(fns, levelNames[0:]...)
+	name := "test"
+	suffix := ".log"
+	for _, fn := range fns {
+
+		file := name + suffix
+		if fn != "" {
+			file = name + "." + fn + suffix
+		}
+		f, err := os.Open(file)
+		if err != nil {
+			t.Fatal(err)
+		}
+		b := bufio.NewReader(f)
+		lineNum := 0
+		lastLine := ""
+		for {
+			line, _, err := b.ReadLine()
+			if err != nil {
+				break
+			}
+			if len(line) > 0 {
+				lastLine = string(line)
+				lineNum++
+			}
+		}
+		var expected = 1
+		if fn == "" {
+			expected = LevelDebug + 1
+		}
+		if lineNum != expected {
+			t.Fatal(file, "has", lineNum, "lines not "+strconv.Itoa(expected)+" lines")
+		}
+		if lineNum == 1 {
+			if !strings.Contains(lastLine, fn) {
+				t.Fatal(file + " " + lastLine + " not contains the log msg " + fn)
+			}
+		}
+		os.Remove(file)
+	}
+
+}

+ 60 - 0
vendor/github.com/astaxie/beego/logs/slack.go

@@ -0,0 +1,60 @@
+package logs
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"net/url"
+	"time"
+)
+
+// SLACKWriter implements beego LoggerInterface and is used to send jiaoliao webhook
+type SLACKWriter struct {
+	WebhookURL string `json:"webhookurl"`
+	Level      int    `json:"level"`
+}
+
+// newSLACKWriter create jiaoliao writer.
+func newSLACKWriter() Logger {
+	return &SLACKWriter{Level: LevelTrace}
+}
+
+// Init SLACKWriter with json config string
+func (s *SLACKWriter) Init(jsonconfig string) error {
+	return json.Unmarshal([]byte(jsonconfig), s)
+}
+
+// WriteMsg write message in smtp writer.
+// it will send an email with subject and only this message.
+func (s *SLACKWriter) WriteMsg(when time.Time, msg string, level int) error {
+	if level > s.Level {
+		return nil
+	}
+
+	text := fmt.Sprintf("{\"text\": \"%s %s\"}", when.Format("2006-01-02 15:04:05"), msg)
+
+	form := url.Values{}
+	form.Add("payload", text)
+
+	resp, err := http.PostForm(s.WebhookURL, form)
+	if err != nil {
+		return err
+	}
+	defer resp.Body.Close()
+	if resp.StatusCode != http.StatusOK {
+		return fmt.Errorf("Post webhook failed %s %d", resp.Status, resp.StatusCode)
+	}
+	return nil
+}
+
+// Flush implementing method. empty.
+func (s *SLACKWriter) Flush() {
+}
+
+// Destroy implementing method. empty.
+func (s *SLACKWriter) Destroy() {
+}
+
+func init() {
+	Register(AdapterSlack, newSLACKWriter)
+}

+ 149 - 0
vendor/github.com/astaxie/beego/logs/smtp.go

@@ -0,0 +1,149 @@
+// 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 logs
+
+import (
+	"crypto/tls"
+	"encoding/json"
+	"fmt"
+	"net"
+	"net/smtp"
+	"strings"
+	"time"
+)
+
+// SMTPWriter implements LoggerInterface and is used to send emails via given SMTP-server.
+type SMTPWriter struct {
+	Username           string   `json:"username"`
+	Password           string   `json:"password"`
+	Host               string   `json:"host"`
+	Subject            string   `json:"subject"`
+	FromAddress        string   `json:"fromAddress"`
+	RecipientAddresses []string `json:"sendTos"`
+	Level              int      `json:"level"`
+}
+
+// NewSMTPWriter create smtp writer.
+func newSMTPWriter() Logger {
+	return &SMTPWriter{Level: LevelTrace}
+}
+
+// Init smtp writer with json config.
+// config like:
+//	{
+//		"username":"[email protected]",
+//		"password:"password",
+//		"host":"smtp.gmail.com:465",
+//		"subject":"email title",
+//		"fromAddress":"[email protected]",
+//		"sendTos":["email1","email2"],
+//		"level":LevelError
+//	}
+func (s *SMTPWriter) Init(jsonconfig string) error {
+	return json.Unmarshal([]byte(jsonconfig), s)
+}
+
+func (s *SMTPWriter) getSMTPAuth(host string) smtp.Auth {
+	if len(strings.Trim(s.Username, " ")) == 0 && len(strings.Trim(s.Password, " ")) == 0 {
+		return nil
+	}
+	return smtp.PlainAuth(
+		"",
+		s.Username,
+		s.Password,
+		host,
+	)
+}
+
+func (s *SMTPWriter) sendMail(hostAddressWithPort string, auth smtp.Auth, fromAddress string, recipients []string, msgContent []byte) error {
+	client, err := smtp.Dial(hostAddressWithPort)
+	if err != nil {
+		return err
+	}
+
+	host, _, _ := net.SplitHostPort(hostAddressWithPort)
+	tlsConn := &tls.Config{
+		InsecureSkipVerify: true,
+		ServerName:         host,
+	}
+	if err = client.StartTLS(tlsConn); err != nil {
+		return err
+	}
+
+	if auth != nil {
+		if err = client.Auth(auth); err != nil {
+			return err
+		}
+	}
+
+	if err = client.Mail(fromAddress); err != nil {
+		return err
+	}
+
+	for _, rec := range recipients {
+		if err = client.Rcpt(rec); err != nil {
+			return err
+		}
+	}
+
+	w, err := client.Data()
+	if err != nil {
+		return err
+	}
+	_, err = w.Write(msgContent)
+	if err != nil {
+		return err
+	}
+
+	err = w.Close()
+	if err != nil {
+		return err
+	}
+
+	return client.Quit()
+}
+
+// WriteMsg write message in smtp writer.
+// it will send an email with subject and only this message.
+func (s *SMTPWriter) WriteMsg(when time.Time, msg string, level int) error {
+	if level > s.Level {
+		return nil
+	}
+
+	hp := strings.Split(s.Host, ":")
+
+	// Set up authentication information.
+	auth := s.getSMTPAuth(hp[0])
+
+	// Connect to the server, authenticate, set the sender and recipient,
+	// and send the email all in one step.
+	contentType := "Content-Type: text/plain" + "; charset=UTF-8"
+	mailmsg := []byte("To: " + strings.Join(s.RecipientAddresses, ";") + "\r\nFrom: " + s.FromAddress + "<" + s.FromAddress +
+		">\r\nSubject: " + s.Subject + "\r\n" + contentType + "\r\n\r\n" + fmt.Sprintf(".%s", when.Format("2006-01-02 15:04:05")) + msg)
+
+	return s.sendMail(s.Host, auth, s.FromAddress, s.RecipientAddresses, mailmsg)
+}
+
+// Flush implementing method. empty.
+func (s *SMTPWriter) Flush() {
+}
+
+// Destroy implementing method. empty.
+func (s *SMTPWriter) Destroy() {
+}
+
+func init() {
+	Register(AdapterMail, newSMTPWriter)
+}

+ 27 - 0
vendor/github.com/astaxie/beego/logs/smtp_test.go

@@ -0,0 +1,27 @@
+// 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 logs
+
+import (
+	"testing"
+	"time"
+)
+
+func TestSmtp(t *testing.T) {
+	log := NewLogger(10000)
+	log.SetLogger("smtp", `{"username":"[email protected]","password":"xxxxxxxx","host":"smtp.gmail.com:587","sendTos":["[email protected]"]}`)
+	log.Critical("sendmail critical")
+	time.Sleep(time.Second * 30)
+}

+ 53 - 0
vendor/github.com/astaxie/beego/migration/ddl.go

@@ -0,0 +1,53 @@
+// 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 migration
+
+// Table store the tablename and Column
+type Table struct {
+	TableName string
+	Columns   []*Column
+}
+
+// Create return the create sql
+func (t *Table) Create() string {
+	return ""
+}
+
+// Drop return the drop sql
+func (t *Table) Drop() string {
+	return ""
+}
+
+// Column define the columns name type and Default
+type Column struct {
+	Name    string
+	Type    string
+	Default interface{}
+}
+
+// Create return create sql with the provided tbname and columns
+func Create(tbname string, columns ...Column) string {
+	return ""
+}
+
+// Drop return the drop sql with the provided tbname and columns
+func Drop(tbname string, columns ...Column) string {
+	return ""
+}
+
+// TableDDL is still in think
+func TableDDL(tbname string, columns ...Column) string {
+	return ""
+}

+ 278 - 0
vendor/github.com/astaxie/beego/migration/migration.go

@@ -0,0 +1,278 @@
+// 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 migration is used for migration
+//
+// The table structure is as follow:
+//
+//	CREATE TABLE `migrations` (
+//		`id_migration` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'surrogate key',
+//		`name` varchar(255) DEFAULT NULL COMMENT 'migration name, unique',
+//		`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'date migrated or rolled back',
+//		`statements` longtext COMMENT 'SQL statements for this migration',
+//		`rollback_statements` longtext,
+//		`status` enum('update','rollback') DEFAULT NULL COMMENT 'update indicates it is a normal migration while rollback means this migration is rolled back',
+//		PRIMARY KEY (`id_migration`)
+//	) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+package migration
+
+import (
+	"errors"
+	"sort"
+	"strings"
+	"time"
+
+	"github.com/astaxie/beego/logs"
+	"github.com/astaxie/beego/orm"
+)
+
+// const the data format for the bee generate migration datatype
+const (
+	DateFormat   = "20060102_150405"
+	DBDateFormat = "2006-01-02 15:04:05"
+)
+
+// Migrationer is an interface for all Migration struct
+type Migrationer interface {
+	Up()
+	Down()
+	Reset()
+	Exec(name, status string) error
+	GetCreated() int64
+}
+
+var (
+	migrationMap map[string]Migrationer
+)
+
+func init() {
+	migrationMap = make(map[string]Migrationer)
+}
+
+// Migration the basic type which will implement the basic type
+type Migration struct {
+	sqls    []string
+	Created string
+}
+
+// Up implement in the Inheritance struct for upgrade
+func (m *Migration) Up() {
+
+}
+
+// Down implement in the Inheritance struct for down
+func (m *Migration) Down() {
+
+}
+
+// SQL add sql want to execute
+func (m *Migration) SQL(sql string) {
+	m.sqls = append(m.sqls, sql)
+}
+
+// Reset the sqls
+func (m *Migration) Reset() {
+	m.sqls = make([]string, 0)
+}
+
+// Exec execute the sql already add in the sql
+func (m *Migration) Exec(name, status string) error {
+	o := orm.NewOrm()
+	for _, s := range m.sqls {
+		logs.Info("exec sql:", s)
+		r := o.Raw(s)
+		_, err := r.Exec()
+		if err != nil {
+			return err
+		}
+	}
+	return m.addOrUpdateRecord(name, status)
+}
+
+func (m *Migration) addOrUpdateRecord(name, status string) error {
+	o := orm.NewOrm()
+	if status == "down" {
+		status = "rollback"
+		p, err := o.Raw("update migrations set status = ?, rollback_statements = ?, created_at = ? where name = ?").Prepare()
+		if err != nil {
+			return nil
+		}
+		_, err = p.Exec(status, strings.Join(m.sqls, "; "), time.Now().Format(DBDateFormat), name)
+		return err
+	}
+	status = "update"
+	p, err := o.Raw("insert into migrations(name, created_at, statements, status) values(?,?,?,?)").Prepare()
+	if err != nil {
+		return err
+	}
+	_, err = p.Exec(name, time.Now().Format(DBDateFormat), strings.Join(m.sqls, "; "), status)
+	return err
+}
+
+// GetCreated get the unixtime from the Created
+func (m *Migration) GetCreated() int64 {
+	t, err := time.Parse(DateFormat, m.Created)
+	if err != nil {
+		return 0
+	}
+	return t.Unix()
+}
+
+// Register register the Migration in the map
+func Register(name string, m Migrationer) error {
+	if _, ok := migrationMap[name]; ok {
+		return errors.New("already exist name:" + name)
+	}
+	migrationMap[name] = m
+	return nil
+}
+
+// Upgrade upgrate the migration from lasttime
+func Upgrade(lasttime int64) error {
+	sm := sortMap(migrationMap)
+	i := 0
+	for _, v := range sm {
+		if v.created > lasttime {
+			logs.Info("start upgrade", v.name)
+			v.m.Reset()
+			v.m.Up()
+			err := v.m.Exec(v.name, "up")
+			if err != nil {
+				logs.Error("execute error:", err)
+				time.Sleep(2 * time.Second)
+				return err
+			}
+			logs.Info("end upgrade:", v.name)
+			i++
+		}
+	}
+	logs.Info("total success upgrade:", i, " migration")
+	time.Sleep(2 * time.Second)
+	return nil
+}
+
+// Rollback rollback the migration by the name
+func Rollback(name string) error {
+	if v, ok := migrationMap[name]; ok {
+		logs.Info("start rollback")
+		v.Reset()
+		v.Down()
+		err := v.Exec(name, "down")
+		if err != nil {
+			logs.Error("execute error:", err)
+			time.Sleep(2 * time.Second)
+			return err
+		}
+		logs.Info("end rollback")
+		time.Sleep(2 * time.Second)
+		return nil
+	}
+	logs.Error("not exist the migrationMap name:" + name)
+	time.Sleep(2 * time.Second)
+	return errors.New("not exist the migrationMap name:" + name)
+}
+
+// Reset reset all migration
+// run all migration's down function
+func Reset() error {
+	sm := sortMap(migrationMap)
+	i := 0
+	for j := len(sm) - 1; j >= 0; j-- {
+		v := sm[j]
+		if isRollBack(v.name) {
+			logs.Info("skip the", v.name)
+			time.Sleep(1 * time.Second)
+			continue
+		}
+		logs.Info("start reset:", v.name)
+		v.m.Reset()
+		v.m.Down()
+		err := v.m.Exec(v.name, "down")
+		if err != nil {
+			logs.Error("execute error:", err)
+			time.Sleep(2 * time.Second)
+			return err
+		}
+		i++
+		logs.Info("end reset:", v.name)
+	}
+	logs.Info("total success reset:", i, " migration")
+	time.Sleep(2 * time.Second)
+	return nil
+}
+
+// Refresh first Reset, then Upgrade
+func Refresh() error {
+	err := Reset()
+	if err != nil {
+		logs.Error("execute error:", err)
+		time.Sleep(2 * time.Second)
+		return err
+	}
+	err = Upgrade(0)
+	return err
+}
+
+type dataSlice []data
+
+type data struct {
+	created int64
+	name    string
+	m       Migrationer
+}
+
+// Len is part of sort.Interface.
+func (d dataSlice) Len() int {
+	return len(d)
+}
+
+// Swap is part of sort.Interface.
+func (d dataSlice) Swap(i, j int) {
+	d[i], d[j] = d[j], d[i]
+}
+
+// Less is part of sort.Interface. We use count as the value to sort by
+func (d dataSlice) Less(i, j int) bool {
+	return d[i].created < d[j].created
+}
+
+func sortMap(m map[string]Migrationer) dataSlice {
+	s := make(dataSlice, 0, len(m))
+	for k, v := range m {
+		d := data{}
+		d.created = v.GetCreated()
+		d.name = k
+		d.m = v
+		s = append(s, d)
+	}
+	sort.Sort(s)
+	return s
+}
+
+func isRollBack(name string) bool {
+	o := orm.NewOrm()
+	var maps []orm.Params
+	num, err := o.Raw("select * from migrations where `name` = ? order by id_migration desc", name).Values(&maps)
+	if err != nil {
+		logs.Info("get name has error", err)
+		return false
+	}
+	if num <= 0 {
+		return false
+	}
+	if maps[0]["status"] == "rollback" {
+		return true
+	}
+	return false
+}

Some files were not shown because too many files changed in this diff