From 144f102935567ae619b172a5bd2de0f2ba54779a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B2=B3?= Date: Sat, 25 May 2019 19:40:01 +0800 Subject: [PATCH 01/58] Http handle change --- server/proxy/http.go | 179 ++++++++++++++++++++++--------------------- 1 file changed, 92 insertions(+), 87 deletions(-) diff --git a/server/proxy/http.go b/server/proxy/http.go index 84026ff..49a605b 100644 --- a/server/proxy/http.go +++ b/server/proxy/http.go @@ -108,12 +108,11 @@ func (s *httpServer) handleTunneling(w http.ResponseWriter, r *http.Request) { if err != nil { http.Error(w, err.Error(), http.StatusServiceUnavailable) } - s.httpHandle(conn.NewConn(c), r) + s.handleHttp(conn.NewConn(c), r) } -func (s *httpServer) httpHandle(c *conn.Conn, r *http.Request) { +func (s *httpServer) handleHttp(c *conn.Conn, r *http.Request) { var ( - isConn = false host *file.Host target net.Conn lastHost *file.Host @@ -122,89 +121,80 @@ func (s *httpServer) httpHandle(c *conn.Conn, r *http.Request) { scheme = r.URL.Scheme lk *conn.Link targetAddr string - readReq bool - reqCh = make(chan *http.Request) + lenConn *conn.LenConn + isReset bool + wg sync.WaitGroup ) + defer func() { + if connClient != nil { + s.writeConnFail(c.Conn) + connClient.Close() + } + c.Close() + }() if host, err = file.GetDb().GetInfoByHost(r.Host, r); err != nil { logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI) - goto end + return } if err := s.CheckFlowAndConnNum(host.Client); err != nil { logs.Warn("client id %d, host id %d, error %s, when https connection", host.Client.Id, host.Id, err.Error()) - c.Close() return } defer host.Client.AddConn() + if err = s.auth(r, c, host.Client.Cnf.U, host.Client.Cnf.P); err != nil { + logs.Warn("auth error", err, r.RemoteAddr) + return + } +reset: + if targetAddr, err = host.Target.GetRandomTarget(); err != nil { + logs.Warn(err.Error()) + return + } + lk = conn.NewLink("http", targetAddr, host.Client.Cnf.Crypt, host.Client.Cnf.Compress, r.RemoteAddr, host.Target.LocalProxy) + if target, err = s.bridge.SendLinkInfo(host.Client.Id, lk, nil); err != nil { + logs.Notice("connect to target %s error %s", lk.Host, err) + return + } + connClient = conn.GetConn(target, lk.Crypt, lk.Compress, host.Client.Rate, true) lastHost = host - for { - start: - if isConn { - if err = s.auth(r, c, host.Client.Cnf.U, host.Client.Cnf.P); err != nil { - logs.Warn("auth error", err, r.RemoteAddr) - break + + //read from inc-client + go func() { + wg.Add(1) + isReset = false + defer connClient.Close() + defer func() { + wg.Done() + if !isReset { + c.Close() } - if targetAddr, err = host.Target.GetRandomTarget(); err != nil { - logs.Warn(err.Error()) - break - } - lk = conn.NewLink("http", targetAddr, host.Client.Cnf.Crypt, host.Client.Cnf.Compress, r.RemoteAddr, host.Target.LocalProxy) - if target, err = s.bridge.SendLinkInfo(host.Client.Id, lk, nil); err != nil { - logs.Notice("connect to target %s error %s", lk.Host, err) - break - } - connClient = conn.GetConn(target, lk.Crypt, lk.Compress, host.Client.Rate, true) - isConn = false - go func() { - defer connClient.Close() - defer c.Close() - for { - if resp, err := http.ReadResponse(bufio.NewReader(connClient), r); err != nil { + }() + for { + if resp, err := http.ReadResponse(bufio.NewReader(connClient), r); err != nil { + return + } else { + //if the cache is start and the response is in the extension,store the response to the cache list + if s.useCache && strings.Contains(r.URL.Path, ".") { + b, err := httputil.DumpResponse(resp, true) + if err != nil { return - } else { - r := <-reqCh - //if the cache is start and the response is in the extension,store the response to the cache list - if s.useCache && strings.Contains(r.URL.Path, ".") { - b, err := httputil.DumpResponse(resp, true) - if err != nil { - return - } - c.Write(b) - host.Flow.Add(0, int64(len(b))) - s.cache.Add(filepath.Join(host.Host, r.URL.Path), b) - } else { - lenConn := conn.NewLenConn(c) - if err := resp.Write(lenConn); err != nil { - logs.Error(err) - return - } - host.Flow.Add(0, int64(lenConn.Len)) - } } + c.Write(b) + host.Flow.Add(0, int64(len(b))) + s.cache.Add(filepath.Join(host.Host, r.URL.Path), b) + } else { + lenConn := conn.NewLenConn(c) + if err := resp.Write(lenConn); err != nil { + logs.Error(err) + return + } + host.Flow.Add(0, int64(lenConn.Len)) } - }() - } else if readReq { - r, err = http.ReadRequest(bufio.NewReader(c)) - if err != nil { - break - } - r.URL.Scheme = scheme - //What happened ,Why one character less??? - if r.Method == "ET" { - r.Method = "GET" - } - if r.Method == "OST" { - r.Method = "POST" - } - if hostTmp, err := file.GetDb().GetInfoByHost(r.Host, r); err != nil { - logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI) - break - } else if host != lastHost { - host = hostTmp - lastHost = host - isConn = true - goto start } } + }() + + for { //if the cache start and the request is in the cache list, return the cache if s.useCache { if v, ok := s.cache.Get(filepath.Join(host.Host, r.URL.Path)); ok { @@ -215,39 +205,54 @@ func (s *httpServer) httpHandle(c *conn.Conn, r *http.Request) { logs.Trace("%s request, method %s, host %s, url %s, remote address %s, return cache", r.URL.Scheme, r.Method, r.Host, r.URL.Path, c.RemoteAddr().String()) host.Flow.Add(0, int64(n)) //if return cache and does not create a new conn with client and Connection is not set or close, close the connection. - if connClient == nil && (strings.ToLower(r.Header.Get("Connection")) == "close" || strings.ToLower(r.Header.Get("Connection")) == "") { - c.Close() + if strings.ToLower(r.Header.Get("Connection")) == "close" || strings.ToLower(r.Header.Get("Connection")) == "" { break } - readReq = true - goto start + goto readReq } } - if connClient == nil { - isConn = true - goto start - } - readReq = true + //change the host and header and set proxy setting common.ChangeHostAndHeader(r, host.HostChange, host.HeaderChange, c.Conn.RemoteAddr().String()) logs.Trace("%s request, method %s, host %s, url %s, remote address %s, target %s", r.URL.Scheme, r.Method, r.Host, r.URL.Path, c.RemoteAddr().String(), lk.Host) //write - lenConn := conn.NewLenConn(connClient) + lenConn = conn.NewLenConn(connClient) if err := r.Write(lenConn); err != nil { logs.Error(err) break } host.Flow.Add(int64(lenConn.Len), 0) - reqCh <- r + + readReq: + //read req from connection + if r, err = http.ReadRequest(bufio.NewReader(c)); err != nil { + break + } + r.URL.Scheme = scheme + //What happened ,Why one character less??? + r.Method = resetReqMethod(r.Method) + if hostTmp, err := file.GetDb().GetInfoByHost(r.Host, r); err != nil { + logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI) + break + } else if host != lastHost { + host = hostTmp + lastHost = host + isReset = true + connClient.Close() + goto reset + } } -end: - if !readReq { - s.writeConnFail(c.Conn) + wg.Wait() +} + +func resetReqMethod(method string) string { + if method == "ET" { + return "GET" } - c.Close() - if target != nil { - target.Close() + if method == "OST" { + return "POST" } + return method } func (s *httpServer) NewServer(port int, scheme string) *http.Server { From 8078d712f94fb1b1ed410dd1f075272d4e0299b6 Mon Sep 17 00:00:00 2001 From: Roccoon Date: Tue, 2 Jul 2019 19:31:33 +0800 Subject: [PATCH 02/58] bugfix Change-Id: Ic7bc9661d1cdf3486c2d6c5aad40b0cd19f63cdb --- server/server.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/server/server.go b/server/server.go index 31e6f18..dff25bd 100644 --- a/server/server.go +++ b/server/server.go @@ -2,6 +2,12 @@ package server import ( "errors" + "math" + "os" + "strconv" + "strings" + "time" + "github.com/cnlh/nps/bridge" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/file" @@ -13,11 +19,6 @@ import ( "github.com/shirou/gopsutil/load" "github.com/shirou/gopsutil/mem" "github.com/shirou/gopsutil/net" - "math" - "os" - "strconv" - "strings" - "time" ) var ( @@ -359,7 +360,7 @@ func GetDashboardData() map[string]interface{} { case "tcp": tcp += 1 case "socks5": - udp += 1 + socks5 += 1 case "httpProxy": http += 1 case "udp": From 30fc6d1689ca31e5b2b22d311ef7f25c91cd43fc Mon Sep 17 00:00:00 2001 From: "To tell you the truth, I'm NoName!" Date: Thu, 1 Aug 2019 17:44:02 +0800 Subject: [PATCH 03/58] =?UTF-8?q?=E5=8D=95=E8=AF=8D=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 单词修正: 如果p2p双方都是Symmetic Nat 如果p2p双方都是Symmetric Nat --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5f08bee..41dd0b6 100644 --- a/README.md +++ b/README.md @@ -610,7 +610,7 @@ auto_reconnection=true ``` ./npc nat ``` -如果p2p双方都是Symmetic Nat,肯定不能成功,其他组合都有较大成功率。 +如果p2p双方都是Symmetric Nat,肯定不能成功,其他组合都有较大成功率。 #### 状态检查 ``` ./npc status -config=npc配置文件路径 From 0435dce9cdf932e3e2212ef5b777402e17e2b898 Mon Sep 17 00:00:00 2001 From: waysup Date: Wed, 7 Aug 2019 23:15:54 +0800 Subject: [PATCH 04/58] Update README.md Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 41dd0b6..1dd7f77 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,7 @@ nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务 **使用步骤** - 在刚才创建的客户端的隧道管理中添加一条udp隧道,填写监听的端口(53)、内网目标ip和目标端口(10.1.50.102:53),保存。 -- 修改需要使用的内网dns为127.0.0.1,则相当于使用10.1.50.202作为dns服务器 +- 修改需要使用的dns地址为1.1.1.1,则相当于使用10.1.50.102作为dns服务器 ### socks5代理 From 5fcbeb60aa6b29a8580fc1ab3c961346ec984d7d Mon Sep 17 00:00:00 2001 From: exfly Date: Sat, 10 Aug 2019 11:10:01 +0800 Subject: [PATCH 05/58] feat: go mod supported --- .gitignore | 4 +- Makefile | 75 + bridge/bridge.go | 4 +- client/client.go | 4 +- client/control.go | 6 +- client/health.go | 2 +- client/local.go | 4 +- cmd/npc/npc.go | 4 +- cmd/nps/nps.go | 4 +- go.mod | 29 + go.sum | 82 + lib/conn/conn.go | 2 +- lib/conn/listener.go | 4 +- lib/conn/snappy.go | 2 +- lib/crypt/tls.go | 2 +- lib/daemon/reload.go | 2 +- lib/mux/mux_test.go | 2 +- lib/mux/pmux.go | 2 +- lib/mux/pmux_test.go | 2 +- server/connection/connection.go | 4 +- server/proxy/base.go | 2 +- server/proxy/http.go | 2 +- server/proxy/https.go | 4 +- server/proxy/p2p.go | 2 +- server/proxy/socks5.go | 2 +- server/proxy/tcp.go | 13 +- server/proxy/udp.go | 2 +- server/server.go | 4 +- server/test/test.go | 2 +- server/tool/utils.go | 2 +- vender/github.com/astaxie/beego/.gitignore | 6 - .../github.com/astaxie/beego/.gosimpleignore | 4 - vender/github.com/astaxie/beego/.travis.yml | 63 - .../github.com/astaxie/beego/CONTRIBUTING.md | 52 - vender/github.com/astaxie/beego/LICENSE | 13 - vender/github.com/astaxie/beego/README.md | 63 - vender/github.com/astaxie/beego/admin.go | 416 --- vender/github.com/astaxie/beego/admin_test.go | 75 - vender/github.com/astaxie/beego/adminui.go | 356 --- vender/github.com/astaxie/beego/app.go | 497 --- vender/github.com/astaxie/beego/beego.go | 123 - vender/github.com/astaxie/beego/config.go | 510 ---- .../github.com/astaxie/beego/config/config.go | 242 -- .../astaxie/beego/config/config_test.go | 55 - .../astaxie/beego/config/env/env.go | 87 - .../astaxie/beego/config/env/env_test.go | 75 - .../github.com/astaxie/beego/config/fake.go | 134 - vender/github.com/astaxie/beego/config/ini.go | 504 --- .../astaxie/beego/config/ini_test.go | 190 -- .../github.com/astaxie/beego/config/json.go | 266 -- .../astaxie/beego/config/json_test.go | 222 -- .../astaxie/beego/config/xml/xml.go | 228 -- .../astaxie/beego/config/xml/xml_test.go | 125 - .../astaxie/beego/config/yaml/yaml.go | 316 -- .../astaxie/beego/config/yaml/yaml_test.go | 115 - .../github.com/astaxie/beego/config_test.go | 138 - .../astaxie/beego/context/acceptencoder.go | 232 -- .../beego/context/acceptencoder_test.go | 59 - .../astaxie/beego/context/context.go | 262 -- .../astaxie/beego/context/context_test.go | 47 - .../github.com/astaxie/beego/context/input.go | 668 ---- .../astaxie/beego/context/input_test.go | 207 -- .../astaxie/beego/context/output.go | 395 --- .../astaxie/beego/context/param/conv.go | 78 - .../beego/context/param/methodparams.go | 69 - .../astaxie/beego/context/param/options.go | 37 - .../astaxie/beego/context/param/parsers.go | 149 - .../beego/context/param/parsers_test.go | 84 - .../astaxie/beego/context/renderer.go | 12 - .../astaxie/beego/context/response.go | 27 - vender/github.com/astaxie/beego/controller.go | 683 ----- .../astaxie/beego/controller_test.go | 181 -- vender/github.com/astaxie/beego/doc.go | 17 - vender/github.com/astaxie/beego/error.go | 474 --- vender/github.com/astaxie/beego/error_test.go | 88 - vender/github.com/astaxie/beego/filter.go | 44 - .../github.com/astaxie/beego/filter_test.go | 68 - vender/github.com/astaxie/beego/flash.go | 110 - vender/github.com/astaxie/beego/flash_test.go | 54 - vender/github.com/astaxie/beego/go.mod | 8 - vender/github.com/astaxie/beego/go.sum | 7 - vender/github.com/astaxie/beego/grace/conn.go | 39 - .../github.com/astaxie/beego/grace/grace.go | 166 - .../astaxie/beego/grace/listener.go | 62 - .../github.com/astaxie/beego/grace/server.go | 363 --- vender/github.com/astaxie/beego/hooks.go | 103 - .../astaxie/beego/httplib/README.md | 97 - .../astaxie/beego/httplib/httplib.go | 624 ---- .../astaxie/beego/httplib/httplib_test.go | 226 -- vender/github.com/astaxie/beego/log.go | 111 - .../astaxie/beego/logs/accesslog.go | 83 - .../astaxie/beego/logs/alils/alils.go | 186 -- .../astaxie/beego/logs/alils/config.go | 13 - .../astaxie/beego/logs/alils/log.pb.go | 1038 ------- .../astaxie/beego/logs/alils/log_config.go | 42 - .../astaxie/beego/logs/alils/log_project.go | 819 ----- .../astaxie/beego/logs/alils/log_store.go | 271 -- .../astaxie/beego/logs/alils/machine_group.go | 91 - .../astaxie/beego/logs/alils/request.go | 62 - .../astaxie/beego/logs/alils/signature.go | 111 - vender/github.com/astaxie/beego/logs/color.go | 28 - .../astaxie/beego/logs/color_windows.go | 428 --- .../astaxie/beego/logs/color_windows_test.go | 294 -- vender/github.com/astaxie/beego/logs/conn.go | 117 - .../astaxie/beego/logs/conn_test.go | 25 - .../github.com/astaxie/beego/logs/console.go | 101 - .../astaxie/beego/logs/console_test.go | 51 - vender/github.com/astaxie/beego/logs/es/es.go | 80 - vender/github.com/astaxie/beego/logs/file.go | 405 --- .../astaxie/beego/logs/file_test.go | 420 --- .../github.com/astaxie/beego/logs/jianliao.go | 72 - vender/github.com/astaxie/beego/logs/log.go | 665 ---- .../github.com/astaxie/beego/logs/logger.go | 208 -- .../astaxie/beego/logs/logger_test.go | 75 - .../astaxie/beego/logs/multifile.go | 119 - .../astaxie/beego/logs/multifile_test.go | 78 - vender/github.com/astaxie/beego/logs/slack.go | 60 - vender/github.com/astaxie/beego/logs/smtp.go | 149 - .../astaxie/beego/logs/smtp_test.go | 27 - .../github.com/astaxie/beego/migration/ddl.go | 395 --- .../github.com/astaxie/beego/migration/doc.go | 32 - .../astaxie/beego/migration/migration.go | 312 -- vender/github.com/astaxie/beego/mime.go | 556 ---- vender/github.com/astaxie/beego/namespace.go | 396 --- .../astaxie/beego/namespace_test.go | 168 - vender/github.com/astaxie/beego/parser.go | 584 ---- .../astaxie/beego/plugins/apiauth/apiauth.go | 160 - .../beego/plugins/apiauth/apiauth_test.go | 20 - .../astaxie/beego/plugins/auth/basic.go | 107 - .../astaxie/beego/plugins/authz/authz.go | 86 - .../beego/plugins/authz/authz_model.conf | 14 - .../beego/plugins/authz/authz_policy.csv | 7 - .../astaxie/beego/plugins/authz/authz_test.go | 107 - .../astaxie/beego/plugins/cors/cors.go | 228 -- .../astaxie/beego/plugins/cors/cors_test.go | 253 -- vender/github.com/astaxie/beego/policy.go | 97 - vender/github.com/astaxie/beego/router.go | 1015 ------- .../github.com/astaxie/beego/router_test.go | 724 ----- .../astaxie/beego/session/README.md | 114 - .../beego/session/couchbase/sess_couchbase.go | 247 -- .../beego/session/ledis/ledis_session.go | 172 -- .../beego/session/memcache/sess_memcache.go | 227 -- .../astaxie/beego/session/mysql/sess_mysql.go | 228 -- .../beego/session/postgres/sess_postgresql.go | 243 -- .../astaxie/beego/session/redis/sess_redis.go | 261 -- .../session/redis_cluster/redis_cluster.go | 221 -- .../astaxie/beego/session/sess_cookie.go | 178 -- .../astaxie/beego/session/sess_cookie_test.go | 105 - .../astaxie/beego/session/sess_file.go | 301 -- .../astaxie/beego/session/sess_mem.go | 196 -- .../astaxie/beego/session/sess_mem_test.go | 58 - .../astaxie/beego/session/sess_test.go | 131 - .../astaxie/beego/session/sess_utils.go | 207 -- .../astaxie/beego/session/session.go | 361 --- .../astaxie/beego/session/ssdb/sess_ssdb.go | 199 -- vender/github.com/astaxie/beego/staticfile.go | 210 -- .../astaxie/beego/staticfile_test.go | 73 - .../astaxie/beego/swagger/swagger.go | 174 -- vender/github.com/astaxie/beego/template.go | 373 --- .../github.com/astaxie/beego/template_test.go | 258 -- .../github.com/astaxie/beego/templatefunc.go | 766 ----- .../astaxie/beego/templatefunc_test.go | 375 --- .../astaxie/beego/testing/assertions.go | 15 - .../astaxie/beego/testing/client.go | 65 - .../astaxie/beego/toolbox/healthcheck.go | 48 - .../astaxie/beego/toolbox/profile.go | 184 -- .../astaxie/beego/toolbox/profile_test.go | 28 - .../astaxie/beego/toolbox/statistics.go | 149 - .../astaxie/beego/toolbox/statistics_test.go | 40 - .../github.com/astaxie/beego/toolbox/task.go | 618 ---- .../astaxie/beego/toolbox/task_test.go | 63 - vender/github.com/astaxie/beego/tree.go | 585 ---- vender/github.com/astaxie/beego/tree_test.go | 306 -- .../astaxie/beego/unregroute_test.go | 226 -- .../github.com/astaxie/beego/utils/caller.go | 25 - .../astaxie/beego/utils/caller_test.go | 28 - .../astaxie/beego/utils/captcha/LICENSE | 19 - .../astaxie/beego/utils/captcha/README.md | 45 - .../astaxie/beego/utils/captcha/captcha.go | 270 -- .../astaxie/beego/utils/captcha/image.go | 501 --- .../astaxie/beego/utils/captcha/image_test.go | 52 - .../astaxie/beego/utils/captcha/siprng.go | 277 -- .../beego/utils/captcha/siprng_test.go | 33 - .../github.com/astaxie/beego/utils/debug.go | 478 --- .../astaxie/beego/utils/debug_test.go | 46 - vender/github.com/astaxie/beego/utils/file.go | 101 - .../astaxie/beego/utils/file_test.go | 75 - vender/github.com/astaxie/beego/utils/mail.go | 423 --- .../astaxie/beego/utils/mail_test.go | 41 - .../beego/utils/pagination/controller.go | 26 - .../astaxie/beego/utils/pagination/doc.go | 58 - .../beego/utils/pagination/paginator.go | 189 -- .../astaxie/beego/utils/pagination/utils.go | 34 - vender/github.com/astaxie/beego/utils/rand.go | 44 - .../astaxie/beego/utils/rand_test.go | 33 - .../github.com/astaxie/beego/utils/safemap.go | 91 - .../astaxie/beego/utils/safemap_test.go | 89 - .../github.com/astaxie/beego/utils/slice.go | 170 -- .../astaxie/beego/utils/slice_test.go | 29 - .../astaxie/beego/utils/testdata/grepe.test | 7 - .../github.com/astaxie/beego/utils/utils.go | 30 - .../astaxie/beego/validation/README.md | 147 - .../astaxie/beego/validation/util.go | 295 -- .../astaxie/beego/validation/util_test.go | 100 - .../astaxie/beego/validation/validation.go | 446 --- .../beego/validation/validation_test.go | 563 ---- .../astaxie/beego/validation/validators.go | 731 ----- .../beego/vendor/golang.org/x/crypto/LICENSE | 27 - .../beego/vendor/golang.org/x/crypto/PATENTS | 22 - .../vendor/golang.org/x/crypto/acme/acme.go | 921 ------ .../x/crypto/acme/autocert/autocert.go | 1127 ------- .../x/crypto/acme/autocert/cache.go | 130 - .../x/crypto/acme/autocert/listener.go | 157 - .../x/crypto/acme/autocert/renewal.go | 141 - .../vendor/golang.org/x/crypto/acme/http.go | 281 -- .../vendor/golang.org/x/crypto/acme/jws.go | 153 - .../vendor/golang.org/x/crypto/acme/types.go | 329 -- .../golang.org/x/crypto/pbkdf2/pbkdf2.go | 77 - .../beego/vendor/golang.org/x/net/LICENSE | 27 - .../beego/vendor/golang.org/x/net/PATENTS | 22 - .../golang.org/x/net/context/context.go | 54 - .../vendor/golang.org/x/net/context/go17.go | 72 - .../vendor/golang.org/x/net/context/go19.go | 20 - .../golang.org/x/net/context/pre_go17.go | 300 -- .../golang.org/x/net/context/pre_go19.go | 109 - .../google.golang.org/appengine/LICENSE | 202 -- .../appengine/cloudsql/cloudsql.go | 62 - .../appengine/cloudsql/cloudsql_classic.go | 17 - .../appengine/cloudsql/cloudsql_vm.go | 16 - .../beego/vendor/gopkg.in/yaml.v2/LICENSE | 201 -- .../vendor/gopkg.in/yaml.v2/LICENSE.libyaml | 31 - .../beego/vendor/gopkg.in/yaml.v2/NOTICE | 13 - .../beego/vendor/gopkg.in/yaml.v2/README.md | 133 - .../beego/vendor/gopkg.in/yaml.v2/apic.go | 739 ----- .../beego/vendor/gopkg.in/yaml.v2/decode.go | 775 ----- .../beego/vendor/gopkg.in/yaml.v2/emitterc.go | 1685 ----------- .../beego/vendor/gopkg.in/yaml.v2/encode.go | 362 --- .../beego/vendor/gopkg.in/yaml.v2/go.mod | 5 - .../beego/vendor/gopkg.in/yaml.v2/parserc.go | 1095 ------- .../beego/vendor/gopkg.in/yaml.v2/readerc.go | 412 --- .../beego/vendor/gopkg.in/yaml.v2/resolve.go | 258 -- .../beego/vendor/gopkg.in/yaml.v2/scannerc.go | 2696 ----------------- .../beego/vendor/gopkg.in/yaml.v2/sorter.go | 113 - .../beego/vendor/gopkg.in/yaml.v2/writerc.go | 26 - .../beego/vendor/gopkg.in/yaml.v2/yaml.go | 466 --- .../beego/vendor/gopkg.in/yaml.v2/yamlh.go | 738 ----- .../vendor/gopkg.in/yaml.v2/yamlprivateh.go | 173 -- .../astaxie/beego/vendor/vendor.json | 43 - vender/github.com/ccding/go-stun/.gitignore | 25 - vender/github.com/ccding/go-stun/LICENSE | 191 -- .../ccding/go-stun/linter_config.json | 27 - vender/github.com/ccding/go-stun/main.go | 56 - .../ccding/go-stun/stun/attribute.go | 106 - .../github.com/ccding/go-stun/stun/client.go | 126 - .../github.com/ccding/go-stun/stun/const.go | 178 -- .../ccding/go-stun/stun/discover.go | 168 - vender/github.com/ccding/go-stun/stun/doc.go | 25 - vender/github.com/ccding/go-stun/stun/host.go | 70 - vender/github.com/ccding/go-stun/stun/log.go | 87 - vender/github.com/ccding/go-stun/stun/net.go | 106 - .../github.com/ccding/go-stun/stun/packet.go | 129 - .../ccding/go-stun/stun/packet_test.go | 61 - .../ccding/go-stun/stun/response.go | 78 - .../github.com/ccding/go-stun/stun/tests.go | 33 - .../github.com/ccding/go-stun/stun/utils.go | 63 - .../ccding/go-stun/stun/utils_test.go | 69 - vender/github.com/golang/snappy/decode.go | 237 -- .../github.com/golang/snappy/decode_amd64.go | 14 - .../github.com/golang/snappy/decode_amd64.s | 490 --- .../github.com/golang/snappy/decode_other.go | 101 - vender/github.com/golang/snappy/encode.go | 285 -- .../github.com/golang/snappy/encode_amd64.go | 29 - .../github.com/golang/snappy/encode_amd64.s | 730 ----- .../github.com/golang/snappy/encode_other.go | 238 -- .../github.com/golang/snappy/golden_test.go | 1965 ------------ vender/github.com/golang/snappy/snappy.go | 98 - .../github.com/golang/snappy/snappy_test.go | 1353 --------- vender/github.com/xtaci/kcp/crypt.go | 785 ----- vender/github.com/xtaci/kcp/crypt_test.go | 289 -- vender/github.com/xtaci/kcp/entropy.go | 52 - vender/github.com/xtaci/kcp/fec.go | 311 -- vender/github.com/xtaci/kcp/fec_test.go | 43 - vender/github.com/xtaci/kcp/kcp.go | 1012 ------- vender/github.com/xtaci/kcp/kcp_test.go | 302 -- vender/github.com/xtaci/kcp/sess.go | 963 ------ vender/github.com/xtaci/kcp/sess_test.go | 475 --- vender/github.com/xtaci/kcp/snmp.go | 164 - vender/github.com/xtaci/kcp/updater.go | 104 - .../golang.org/x/net/internal/socks/client.go | 168 - .../x/net/internal/socks/dial_test.go | 170 -- .../golang.org/x/net/internal/socks/socks.go | 317 -- vender/golang.org/x/net/proxy/direct.go | 18 - vender/golang.org/x/net/proxy/per_host.go | 140 - .../golang.org/x/net/proxy/per_host_test.go | 55 - vender/golang.org/x/net/proxy/proxy.go | 134 - vender/golang.org/x/net/proxy/proxy_test.go | 123 - vender/golang.org/x/net/proxy/socks5.go | 36 - web/controllers/auth.go | 2 +- web/controllers/base.go | 2 +- web/controllers/client.go | 2 +- web/controllers/login.go | 2 +- web/routers/router.go | 2 +- 302 files changed, 237 insertions(+), 62683 deletions(-) create mode 100644 Makefile create mode 100644 go.mod create mode 100644 go.sum delete mode 100755 vender/github.com/astaxie/beego/.gitignore delete mode 100755 vender/github.com/astaxie/beego/.gosimpleignore delete mode 100755 vender/github.com/astaxie/beego/.travis.yml delete mode 100755 vender/github.com/astaxie/beego/CONTRIBUTING.md delete mode 100755 vender/github.com/astaxie/beego/LICENSE delete mode 100755 vender/github.com/astaxie/beego/README.md delete mode 100755 vender/github.com/astaxie/beego/admin.go delete mode 100755 vender/github.com/astaxie/beego/admin_test.go delete mode 100755 vender/github.com/astaxie/beego/adminui.go delete mode 100755 vender/github.com/astaxie/beego/app.go delete mode 100755 vender/github.com/astaxie/beego/beego.go delete mode 100755 vender/github.com/astaxie/beego/config.go delete mode 100755 vender/github.com/astaxie/beego/config/config.go delete mode 100755 vender/github.com/astaxie/beego/config/config_test.go delete mode 100755 vender/github.com/astaxie/beego/config/env/env.go delete mode 100755 vender/github.com/astaxie/beego/config/env/env_test.go delete mode 100755 vender/github.com/astaxie/beego/config/fake.go delete mode 100755 vender/github.com/astaxie/beego/config/ini.go delete mode 100755 vender/github.com/astaxie/beego/config/ini_test.go delete mode 100755 vender/github.com/astaxie/beego/config/json.go delete mode 100755 vender/github.com/astaxie/beego/config/json_test.go delete mode 100755 vender/github.com/astaxie/beego/config/xml/xml.go delete mode 100755 vender/github.com/astaxie/beego/config/xml/xml_test.go delete mode 100755 vender/github.com/astaxie/beego/config/yaml/yaml.go delete mode 100755 vender/github.com/astaxie/beego/config/yaml/yaml_test.go delete mode 100755 vender/github.com/astaxie/beego/config_test.go delete mode 100755 vender/github.com/astaxie/beego/context/acceptencoder.go delete mode 100755 vender/github.com/astaxie/beego/context/acceptencoder_test.go delete mode 100755 vender/github.com/astaxie/beego/context/context.go delete mode 100755 vender/github.com/astaxie/beego/context/context_test.go delete mode 100755 vender/github.com/astaxie/beego/context/input.go delete mode 100755 vender/github.com/astaxie/beego/context/input_test.go delete mode 100755 vender/github.com/astaxie/beego/context/output.go delete mode 100755 vender/github.com/astaxie/beego/context/param/conv.go delete mode 100755 vender/github.com/astaxie/beego/context/param/methodparams.go delete mode 100755 vender/github.com/astaxie/beego/context/param/options.go delete mode 100755 vender/github.com/astaxie/beego/context/param/parsers.go delete mode 100755 vender/github.com/astaxie/beego/context/param/parsers_test.go delete mode 100755 vender/github.com/astaxie/beego/context/renderer.go delete mode 100755 vender/github.com/astaxie/beego/context/response.go delete mode 100755 vender/github.com/astaxie/beego/controller.go delete mode 100755 vender/github.com/astaxie/beego/controller_test.go delete mode 100755 vender/github.com/astaxie/beego/doc.go delete mode 100755 vender/github.com/astaxie/beego/error.go delete mode 100755 vender/github.com/astaxie/beego/error_test.go delete mode 100755 vender/github.com/astaxie/beego/filter.go delete mode 100755 vender/github.com/astaxie/beego/filter_test.go delete mode 100755 vender/github.com/astaxie/beego/flash.go delete mode 100755 vender/github.com/astaxie/beego/flash_test.go delete mode 100755 vender/github.com/astaxie/beego/go.mod delete mode 100755 vender/github.com/astaxie/beego/go.sum delete mode 100755 vender/github.com/astaxie/beego/grace/conn.go delete mode 100755 vender/github.com/astaxie/beego/grace/grace.go delete mode 100755 vender/github.com/astaxie/beego/grace/listener.go delete mode 100755 vender/github.com/astaxie/beego/grace/server.go delete mode 100755 vender/github.com/astaxie/beego/hooks.go delete mode 100755 vender/github.com/astaxie/beego/httplib/README.md delete mode 100755 vender/github.com/astaxie/beego/httplib/httplib.go delete mode 100755 vender/github.com/astaxie/beego/httplib/httplib_test.go delete mode 100755 vender/github.com/astaxie/beego/log.go delete mode 100755 vender/github.com/astaxie/beego/logs/accesslog.go delete mode 100755 vender/github.com/astaxie/beego/logs/alils/alils.go delete mode 100755 vender/github.com/astaxie/beego/logs/alils/config.go delete mode 100755 vender/github.com/astaxie/beego/logs/alils/log.pb.go delete mode 100755 vender/github.com/astaxie/beego/logs/alils/log_config.go delete mode 100755 vender/github.com/astaxie/beego/logs/alils/log_project.go delete mode 100755 vender/github.com/astaxie/beego/logs/alils/log_store.go delete mode 100755 vender/github.com/astaxie/beego/logs/alils/machine_group.go delete mode 100755 vender/github.com/astaxie/beego/logs/alils/request.go delete mode 100755 vender/github.com/astaxie/beego/logs/alils/signature.go delete mode 100755 vender/github.com/astaxie/beego/logs/color.go delete mode 100755 vender/github.com/astaxie/beego/logs/color_windows.go delete mode 100755 vender/github.com/astaxie/beego/logs/color_windows_test.go delete mode 100755 vender/github.com/astaxie/beego/logs/conn.go delete mode 100755 vender/github.com/astaxie/beego/logs/conn_test.go delete mode 100755 vender/github.com/astaxie/beego/logs/console.go delete mode 100755 vender/github.com/astaxie/beego/logs/console_test.go delete mode 100755 vender/github.com/astaxie/beego/logs/es/es.go delete mode 100755 vender/github.com/astaxie/beego/logs/file.go delete mode 100755 vender/github.com/astaxie/beego/logs/file_test.go delete mode 100755 vender/github.com/astaxie/beego/logs/jianliao.go delete mode 100755 vender/github.com/astaxie/beego/logs/log.go delete mode 100755 vender/github.com/astaxie/beego/logs/logger.go delete mode 100755 vender/github.com/astaxie/beego/logs/logger_test.go delete mode 100755 vender/github.com/astaxie/beego/logs/multifile.go delete mode 100755 vender/github.com/astaxie/beego/logs/multifile_test.go delete mode 100755 vender/github.com/astaxie/beego/logs/slack.go delete mode 100755 vender/github.com/astaxie/beego/logs/smtp.go delete mode 100755 vender/github.com/astaxie/beego/logs/smtp_test.go delete mode 100755 vender/github.com/astaxie/beego/migration/ddl.go delete mode 100755 vender/github.com/astaxie/beego/migration/doc.go delete mode 100755 vender/github.com/astaxie/beego/migration/migration.go delete mode 100755 vender/github.com/astaxie/beego/mime.go delete mode 100755 vender/github.com/astaxie/beego/namespace.go delete mode 100755 vender/github.com/astaxie/beego/namespace_test.go delete mode 100755 vender/github.com/astaxie/beego/parser.go delete mode 100755 vender/github.com/astaxie/beego/plugins/apiauth/apiauth.go delete mode 100755 vender/github.com/astaxie/beego/plugins/apiauth/apiauth_test.go delete mode 100755 vender/github.com/astaxie/beego/plugins/auth/basic.go delete mode 100755 vender/github.com/astaxie/beego/plugins/authz/authz.go delete mode 100755 vender/github.com/astaxie/beego/plugins/authz/authz_model.conf delete mode 100755 vender/github.com/astaxie/beego/plugins/authz/authz_policy.csv delete mode 100755 vender/github.com/astaxie/beego/plugins/authz/authz_test.go delete mode 100755 vender/github.com/astaxie/beego/plugins/cors/cors.go delete mode 100755 vender/github.com/astaxie/beego/plugins/cors/cors_test.go delete mode 100755 vender/github.com/astaxie/beego/policy.go delete mode 100755 vender/github.com/astaxie/beego/router.go delete mode 100755 vender/github.com/astaxie/beego/router_test.go delete mode 100755 vender/github.com/astaxie/beego/session/README.md delete mode 100755 vender/github.com/astaxie/beego/session/couchbase/sess_couchbase.go delete mode 100755 vender/github.com/astaxie/beego/session/ledis/ledis_session.go delete mode 100755 vender/github.com/astaxie/beego/session/memcache/sess_memcache.go delete mode 100755 vender/github.com/astaxie/beego/session/mysql/sess_mysql.go delete mode 100755 vender/github.com/astaxie/beego/session/postgres/sess_postgresql.go delete mode 100755 vender/github.com/astaxie/beego/session/redis/sess_redis.go delete mode 100755 vender/github.com/astaxie/beego/session/redis_cluster/redis_cluster.go delete mode 100755 vender/github.com/astaxie/beego/session/sess_cookie.go delete mode 100755 vender/github.com/astaxie/beego/session/sess_cookie_test.go delete mode 100755 vender/github.com/astaxie/beego/session/sess_file.go delete mode 100755 vender/github.com/astaxie/beego/session/sess_mem.go delete mode 100755 vender/github.com/astaxie/beego/session/sess_mem_test.go delete mode 100755 vender/github.com/astaxie/beego/session/sess_test.go delete mode 100755 vender/github.com/astaxie/beego/session/sess_utils.go delete mode 100755 vender/github.com/astaxie/beego/session/session.go delete mode 100755 vender/github.com/astaxie/beego/session/ssdb/sess_ssdb.go delete mode 100755 vender/github.com/astaxie/beego/staticfile.go delete mode 100755 vender/github.com/astaxie/beego/staticfile_test.go delete mode 100755 vender/github.com/astaxie/beego/swagger/swagger.go delete mode 100755 vender/github.com/astaxie/beego/template.go delete mode 100755 vender/github.com/astaxie/beego/template_test.go delete mode 100755 vender/github.com/astaxie/beego/templatefunc.go delete mode 100755 vender/github.com/astaxie/beego/templatefunc_test.go delete mode 100755 vender/github.com/astaxie/beego/testing/assertions.go delete mode 100755 vender/github.com/astaxie/beego/testing/client.go delete mode 100755 vender/github.com/astaxie/beego/toolbox/healthcheck.go delete mode 100755 vender/github.com/astaxie/beego/toolbox/profile.go delete mode 100755 vender/github.com/astaxie/beego/toolbox/profile_test.go delete mode 100755 vender/github.com/astaxie/beego/toolbox/statistics.go delete mode 100755 vender/github.com/astaxie/beego/toolbox/statistics_test.go delete mode 100755 vender/github.com/astaxie/beego/toolbox/task.go delete mode 100755 vender/github.com/astaxie/beego/toolbox/task_test.go delete mode 100755 vender/github.com/astaxie/beego/tree.go delete mode 100755 vender/github.com/astaxie/beego/tree_test.go delete mode 100755 vender/github.com/astaxie/beego/unregroute_test.go delete mode 100755 vender/github.com/astaxie/beego/utils/caller.go delete mode 100755 vender/github.com/astaxie/beego/utils/caller_test.go delete mode 100755 vender/github.com/astaxie/beego/utils/captcha/LICENSE delete mode 100755 vender/github.com/astaxie/beego/utils/captcha/README.md delete mode 100755 vender/github.com/astaxie/beego/utils/captcha/captcha.go delete mode 100755 vender/github.com/astaxie/beego/utils/captcha/image.go delete mode 100755 vender/github.com/astaxie/beego/utils/captcha/image_test.go delete mode 100755 vender/github.com/astaxie/beego/utils/captcha/siprng.go delete mode 100755 vender/github.com/astaxie/beego/utils/captcha/siprng_test.go delete mode 100755 vender/github.com/astaxie/beego/utils/debug.go delete mode 100755 vender/github.com/astaxie/beego/utils/debug_test.go delete mode 100755 vender/github.com/astaxie/beego/utils/file.go delete mode 100755 vender/github.com/astaxie/beego/utils/file_test.go delete mode 100755 vender/github.com/astaxie/beego/utils/mail.go delete mode 100755 vender/github.com/astaxie/beego/utils/mail_test.go delete mode 100755 vender/github.com/astaxie/beego/utils/pagination/controller.go delete mode 100755 vender/github.com/astaxie/beego/utils/pagination/doc.go delete mode 100755 vender/github.com/astaxie/beego/utils/pagination/paginator.go delete mode 100755 vender/github.com/astaxie/beego/utils/pagination/utils.go delete mode 100755 vender/github.com/astaxie/beego/utils/rand.go delete mode 100755 vender/github.com/astaxie/beego/utils/rand_test.go delete mode 100755 vender/github.com/astaxie/beego/utils/safemap.go delete mode 100755 vender/github.com/astaxie/beego/utils/safemap_test.go delete mode 100755 vender/github.com/astaxie/beego/utils/slice.go delete mode 100755 vender/github.com/astaxie/beego/utils/slice_test.go delete mode 100755 vender/github.com/astaxie/beego/utils/testdata/grepe.test delete mode 100755 vender/github.com/astaxie/beego/utils/utils.go delete mode 100755 vender/github.com/astaxie/beego/validation/README.md delete mode 100755 vender/github.com/astaxie/beego/validation/util.go delete mode 100755 vender/github.com/astaxie/beego/validation/util_test.go delete mode 100755 vender/github.com/astaxie/beego/validation/validation.go delete mode 100755 vender/github.com/astaxie/beego/validation/validation_test.go delete mode 100755 vender/github.com/astaxie/beego/validation/validators.go delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/LICENSE delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/PATENTS delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/acme.go delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/autocert/autocert.go delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/autocert/cache.go delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/autocert/listener.go delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/autocert/renewal.go delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/http.go delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/jws.go delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/types.go delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/net/LICENSE delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/net/PATENTS delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/context.go delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/go17.go delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/go19.go delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/pre_go17.go delete mode 100755 vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/pre_go19.go delete mode 100755 vender/github.com/astaxie/beego/vendor/google.golang.org/appengine/LICENSE delete mode 100755 vender/github.com/astaxie/beego/vendor/google.golang.org/appengine/cloudsql/cloudsql.go delete mode 100755 vender/github.com/astaxie/beego/vendor/google.golang.org/appengine/cloudsql/cloudsql_classic.go delete mode 100755 vender/github.com/astaxie/beego/vendor/google.golang.org/appengine/cloudsql/cloudsql_vm.go delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/LICENSE delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/LICENSE.libyaml delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/NOTICE delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/README.md delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/apic.go delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/decode.go delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/emitterc.go delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/encode.go delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/go.mod delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/parserc.go delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/readerc.go delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/resolve.go delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/scannerc.go delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/sorter.go delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/writerc.go delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/yaml.go delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/yamlh.go delete mode 100755 vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/yamlprivateh.go delete mode 100755 vender/github.com/astaxie/beego/vendor/vendor.json delete mode 100755 vender/github.com/ccding/go-stun/.gitignore delete mode 100755 vender/github.com/ccding/go-stun/LICENSE delete mode 100755 vender/github.com/ccding/go-stun/linter_config.json delete mode 100755 vender/github.com/ccding/go-stun/main.go delete mode 100755 vender/github.com/ccding/go-stun/stun/attribute.go delete mode 100755 vender/github.com/ccding/go-stun/stun/client.go delete mode 100755 vender/github.com/ccding/go-stun/stun/const.go delete mode 100755 vender/github.com/ccding/go-stun/stun/discover.go delete mode 100755 vender/github.com/ccding/go-stun/stun/doc.go delete mode 100755 vender/github.com/ccding/go-stun/stun/host.go delete mode 100755 vender/github.com/ccding/go-stun/stun/log.go delete mode 100755 vender/github.com/ccding/go-stun/stun/net.go delete mode 100755 vender/github.com/ccding/go-stun/stun/packet.go delete mode 100755 vender/github.com/ccding/go-stun/stun/packet_test.go delete mode 100755 vender/github.com/ccding/go-stun/stun/response.go delete mode 100755 vender/github.com/ccding/go-stun/stun/tests.go delete mode 100755 vender/github.com/ccding/go-stun/stun/utils.go delete mode 100755 vender/github.com/ccding/go-stun/stun/utils_test.go delete mode 100644 vender/github.com/golang/snappy/decode.go delete mode 100644 vender/github.com/golang/snappy/decode_amd64.go delete mode 100644 vender/github.com/golang/snappy/decode_amd64.s delete mode 100644 vender/github.com/golang/snappy/decode_other.go delete mode 100644 vender/github.com/golang/snappy/encode.go delete mode 100644 vender/github.com/golang/snappy/encode_amd64.go delete mode 100644 vender/github.com/golang/snappy/encode_amd64.s delete mode 100644 vender/github.com/golang/snappy/encode_other.go delete mode 100644 vender/github.com/golang/snappy/golden_test.go delete mode 100644 vender/github.com/golang/snappy/snappy.go delete mode 100644 vender/github.com/golang/snappy/snappy_test.go delete mode 100644 vender/github.com/xtaci/kcp/crypt.go delete mode 100644 vender/github.com/xtaci/kcp/crypt_test.go delete mode 100644 vender/github.com/xtaci/kcp/entropy.go delete mode 100644 vender/github.com/xtaci/kcp/fec.go delete mode 100644 vender/github.com/xtaci/kcp/fec_test.go delete mode 100644 vender/github.com/xtaci/kcp/kcp.go delete mode 100644 vender/github.com/xtaci/kcp/kcp_test.go delete mode 100644 vender/github.com/xtaci/kcp/sess.go delete mode 100644 vender/github.com/xtaci/kcp/sess_test.go delete mode 100644 vender/github.com/xtaci/kcp/snmp.go delete mode 100644 vender/github.com/xtaci/kcp/updater.go delete mode 100644 vender/golang.org/x/net/internal/socks/client.go delete mode 100644 vender/golang.org/x/net/internal/socks/dial_test.go delete mode 100644 vender/golang.org/x/net/internal/socks/socks.go delete mode 100644 vender/golang.org/x/net/proxy/direct.go delete mode 100644 vender/golang.org/x/net/proxy/per_host.go delete mode 100644 vender/golang.org/x/net/proxy/per_host_test.go delete mode 100644 vender/golang.org/x/net/proxy/proxy.go delete mode 100644 vender/golang.org/x/net/proxy/proxy_test.go delete mode 100644 vender/golang.org/x/net/proxy/socks5.go diff --git a/.gitignore b/.gitignore index 723ef36..c2ccad1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -.idea \ No newline at end of file +.idea +nps +npc diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c650b50 --- /dev/null +++ b/Makefile @@ -0,0 +1,75 @@ +SOURCE_FILES?=./... +TEST_PATTERN?=. +TEST_OPTIONS?= + +export PATH := ./bin:$(PATH) +export GO111MODULE := on +export GOPROXY := https://gocenter.io + +# Build a beta version of goreleaser +build: + go build cmd/nps/nps.go + go build cmd/npc/npc.go +.PHONY: build + +# Install all the build and lint dependencies +setup: + curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh + curl -L https://git.io/misspell | sh + go mod download +.PHONY: setup + +# Run all the tests +test: + go test $(TEST_OPTIONS) -failfast -race -coverpkg=./... -covermode=atomic -coverprofile=coverage.txt $(SOURCE_FILES) -run $(TEST_PATTERN) -timeout=2m +.PHONY: test + +# Run all the tests and opens the coverage report +cover: test + go tool cover -html=coverage.txt +.PHONY: cover + +# gofmt and goimports all go files +fmt: + find . -name '*.go' -not -wholename './vendor/*' | while read -r file; do gofmt -w -s "$$file"; goimports -w "$$file"; done +.PHONY: fmt + +# Run all the linters +lint: + # TODO: fix tests and lll issues + ./bin/golangci-lint run --tests=false --enable-all --disable=lll ./... + ./bin/misspell -error **/* +.PHONY: lint + +# Clean go.mod +go-mod-tidy: + @go mod tidy -v + @git diff HEAD + @git diff-index --quiet HEAD +.PHONY: go-mod-tidy + +# Run all the tests and code checks +ci: build test lint go-mod-tidy +.PHONY: ci + +# Generate the static documentation +static: + @hugo --enableGitInfo --source www +.PHONY: static + +# Show to-do items per file. +todo: + @grep \ + --exclude-dir=vendor \ + --exclude-dir=node_modules \ + --exclude=Makefile \ + --text \ + --color \ + -nRo -E ' TODO:.*|SkipNow' . +.PHONY: todo + +clean: + rm npc nps +.PHONY: clean + +.DEFAULT_GOAL := build diff --git a/bridge/bridge.go b/bridge/bridge.go index e50e2ea..abaa737 100755 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -12,8 +12,8 @@ import ( "github.com/cnlh/nps/lib/version" "github.com/cnlh/nps/server/connection" "github.com/cnlh/nps/server/tool" - "github.com/cnlh/nps/vender/github.com/astaxie/beego" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/astaxie/beego" + "github.com/astaxie/beego/logs" "net" "os" "strconv" diff --git a/client/client.go b/client/client.go index 64910f6..c338293 100755 --- a/client/client.go +++ b/client/client.go @@ -7,8 +7,8 @@ import ( "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/crypt" "github.com/cnlh/nps/lib/mux" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" - "github.com/cnlh/nps/vender/github.com/xtaci/kcp" + "github.com/astaxie/beego/logs" + "github.com/xtaci/kcp-go" "net" "net/http" "strconv" diff --git a/client/control.go b/client/control.go index 53f1958..7b0e39b 100644 --- a/client/control.go +++ b/client/control.go @@ -10,9 +10,9 @@ import ( "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/crypt" "github.com/cnlh/nps/lib/version" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" - "github.com/cnlh/nps/vender/github.com/xtaci/kcp" - "github.com/cnlh/nps/vender/golang.org/x/net/proxy" + "github.com/astaxie/beego/logs" + "github.com/xtaci/kcp-go" + "golang.org/x/net/proxy" "io/ioutil" "log" "math" diff --git a/client/health.go b/client/health.go index ff2338f..b57e7c0 100644 --- a/client/health.go +++ b/client/health.go @@ -5,7 +5,7 @@ import ( "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/lib/sheap" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/astaxie/beego/logs" "github.com/pkg/errors" "net" "net/http" diff --git a/client/local.go b/client/local.go index 2958774..212fd70 100644 --- a/client/local.go +++ b/client/local.go @@ -8,8 +8,8 @@ import ( "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/lib/mux" "github.com/cnlh/nps/server/proxy" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" - "github.com/cnlh/nps/vender/github.com/xtaci/kcp" + "github.com/astaxie/beego/logs" + "github.com/xtaci/kcp-go" "net" "net/http" "sync" diff --git a/cmd/npc/npc.go b/cmd/npc/npc.go index f2c7b7c..501718b 100644 --- a/cmd/npc/npc.go +++ b/cmd/npc/npc.go @@ -9,8 +9,8 @@ import ( "github.com/cnlh/nps/lib/daemon" "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/lib/version" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" - "github.com/cnlh/nps/vender/github.com/ccding/go-stun/stun" + "github.com/astaxie/beego/logs" + "github.com/ccding/go-stun/stun" "os" "strings" "time" diff --git a/cmd/nps/nps.go b/cmd/nps/nps.go index 2cb9a28..ff54052 100644 --- a/cmd/nps/nps.go +++ b/cmd/nps/nps.go @@ -12,8 +12,8 @@ import ( "github.com/cnlh/nps/server/connection" "github.com/cnlh/nps/server/test" "github.com/cnlh/nps/server/tool" - "github.com/cnlh/nps/vender/github.com/astaxie/beego" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/astaxie/beego" + "github.com/astaxie/beego/logs" _ "github.com/cnlh/nps/web/routers" "log" "os" diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1f6b753 --- /dev/null +++ b/go.mod @@ -0,0 +1,29 @@ +module github.com/cnlh/nps + +go 1.12 + +require ( + github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect + github.com/astaxie/beego v1.12.0 + github.com/belogik/goes v0.0.0-20151229125003-e54d722c3aff // indirect + github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d + github.com/go-ole/go-ole v1.2.4 // indirect + github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db + github.com/klauspost/cpuid v1.2.1 // indirect + github.com/klauspost/reedsolomon v1.9.2 + github.com/onsi/gomega v1.5.0 // indirect + github.com/pkg/errors v0.8.0 + github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect + github.com/shirou/gopsutil v2.18.12+incompatible + github.com/stretchr/testify v1.3.0 // indirect + github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect + github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b + github.com/tjfoc/gmsm v1.0.1 + github.com/xtaci/kcp-go v5.4.4+incompatible + github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect + golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 + golang.org/x/net v0.0.0-20181114220301-adae6a3d119a + golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa // indirect +) + +replace github.com/astaxie/beego => github.com/exfly/beego v1.12.0-export-init diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..29de132 --- /dev/null +++ b/go.sum @@ -0,0 +1,82 @@ +github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/astaxie/beego v1.12.0 h1:MRhVoeeye5N+Flul5PoVfD9CslfdoH+xqC/xvSQ5u2Y= +github.com/astaxie/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= +github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ= +github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU= +github.com/belogik/goes v0.0.0-20151229125003-e54d722c3aff/go.mod h1:PhH1ZhyCzHKt4uAasyx+ljRCgoezetRNf59CUtwUkqY= +github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= +github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= +github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d h1:As4937T5NVbJ/DmZT9z33pyLEprMd6CUSfhbmMY57Io= +github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d/go.mod h1:3FK1bMar37f7jqVY7q/63k3OMX1c47pGCufzt3X0sYE= +github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= +github.com/couchbase/go-couchbase v0.0.0-20181122212707-3e9b6e1258bb/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U= +github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= +github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= +github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= +github.com/exfly/beego v1.12.0-export-init h1:VQNYKdXhAwZGUaFmQv8Aj921O3rQJZRIF8xeGrhsjrI= +github.com/exfly/beego v1.12.0-export-init/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= +github.com/exfly/beego v1.12.0 h1:OXwIwngaAx35Mga+jLiZmArusBxj8/H0jYXzGDAdwOg= +github.com/exfly/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/reedsolomon v1.9.2 h1:E9CMS2Pqbv+C7tsrYad4YC9MfhnMVWhMRsTi7U0UB18= +github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo= +github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= +github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAriGFsTZppLXDX93OM= +github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= +github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= +github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= +github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= +github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU= +github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= +github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b h1:mnG1fcsIB1d/3vbkBak2MM0u+vhGhlQwpeimUi7QncM= +github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= +github.com/tjfoc/gmsm v1.0.1 h1:R11HlqhXkDospckjZEihx9SW/2VW0RgdwrykyWMFOQU= +github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc= +github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= +github.com/xtaci/kcp-go v5.4.4+incompatible h1:QIJ0a0Q0N1G20yLHL2+fpdzyy2v/Cb3PI+xiwx/KK9c= +github.com/xtaci/kcp-go v5.4.4+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= +github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= +golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI= +golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M= +golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/lib/conn/conn.go b/lib/conn/conn.go index 7b6e729..91d1779 100755 --- a/lib/conn/conn.go +++ b/lib/conn/conn.go @@ -12,7 +12,7 @@ import ( "github.com/cnlh/nps/lib/mux" "github.com/cnlh/nps/lib/pool" "github.com/cnlh/nps/lib/rate" - "github.com/cnlh/nps/vender/github.com/xtaci/kcp" + "github.com/xtaci/kcp-go" "io" "net" "net/http" diff --git a/lib/conn/listener.go b/lib/conn/listener.go index 7f71560..1d23644 100644 --- a/lib/conn/listener.go +++ b/lib/conn/listener.go @@ -1,8 +1,8 @@ package conn import ( - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" - "github.com/cnlh/nps/vender/github.com/xtaci/kcp" + "github.com/astaxie/beego/logs" + "github.com/xtaci/kcp-go" "net" "strings" ) diff --git a/lib/conn/snappy.go b/lib/conn/snappy.go index cfd33c4..729acb3 100644 --- a/lib/conn/snappy.go +++ b/lib/conn/snappy.go @@ -2,7 +2,7 @@ package conn import ( "github.com/cnlh/nps/lib/pool" - "github.com/cnlh/nps/vender/github.com/golang/snappy" + "github.com/golang/snappy" "io" ) diff --git a/lib/crypt/tls.go b/lib/crypt/tls.go index ea7f8ee..75f291a 100644 --- a/lib/crypt/tls.go +++ b/lib/crypt/tls.go @@ -2,7 +2,7 @@ package crypt import ( "crypto/tls" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/astaxie/beego/logs" "net" "os" ) diff --git a/lib/daemon/reload.go b/lib/daemon/reload.go index d7a6cbe..6b075b6 100644 --- a/lib/daemon/reload.go +++ b/lib/daemon/reload.go @@ -4,7 +4,7 @@ package daemon import ( "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/vender/github.com/astaxie/beego" + "github.com/astaxie/beego" "os" "os/signal" "path/filepath" diff --git a/lib/mux/mux_test.go b/lib/mux/mux_test.go index f84e378..463291a 100644 --- a/lib/mux/mux_test.go +++ b/lib/mux/mux_test.go @@ -3,7 +3,7 @@ package mux import ( "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/pool" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/astaxie/beego/logs" "log" "net" "net/http" diff --git a/lib/mux/pmux.go b/lib/mux/pmux.go index 1609e26..b750838 100644 --- a/lib/mux/pmux.go +++ b/lib/mux/pmux.go @@ -6,7 +6,7 @@ import ( "bufio" "bytes" "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/astaxie/beego/logs" "github.com/pkg/errors" "io" "net" diff --git a/lib/mux/pmux_test.go b/lib/mux/pmux_test.go index 641ae2a..c3c0705 100644 --- a/lib/mux/pmux_test.go +++ b/lib/mux/pmux_test.go @@ -1,7 +1,7 @@ package mux import ( - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/astaxie/beego/logs" "testing" "time" ) diff --git a/server/connection/connection.go b/server/connection/connection.go index 9806869..73eac1d 100644 --- a/server/connection/connection.go +++ b/server/connection/connection.go @@ -2,8 +2,8 @@ package connection import ( "github.com/cnlh/nps/lib/mux" - "github.com/cnlh/nps/vender/github.com/astaxie/beego" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/astaxie/beego" + "github.com/astaxie/beego/logs" "net" "os" "strconv" diff --git a/server/proxy/base.go b/server/proxy/base.go index 2509dbd..68cce5b 100644 --- a/server/proxy/base.go +++ b/server/proxy/base.go @@ -6,7 +6,7 @@ import ( "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/file" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/astaxie/beego/logs" "net" "net/http" "sync" diff --git a/server/proxy/http.go b/server/proxy/http.go index 49a605b..bf12060 100644 --- a/server/proxy/http.go +++ b/server/proxy/http.go @@ -9,7 +9,7 @@ import ( "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/server/connection" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/astaxie/beego/logs" "io" "net" "net/http" diff --git a/server/proxy/https.go b/server/proxy/https.go index 9ccce29..997a851 100644 --- a/server/proxy/https.go +++ b/server/proxy/https.go @@ -6,8 +6,8 @@ import ( "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/crypt" "github.com/cnlh/nps/lib/file" - "github.com/cnlh/nps/vender/github.com/astaxie/beego" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/astaxie/beego" + "github.com/astaxie/beego/logs" "github.com/pkg/errors" "net" "net/http" diff --git a/server/proxy/p2p.go b/server/proxy/p2p.go index 44cdea3..470963f 100644 --- a/server/proxy/p2p.go +++ b/server/proxy/p2p.go @@ -3,7 +3,7 @@ package proxy import ( "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/pool" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/astaxie/beego/logs" "net" "strings" "time" diff --git a/server/proxy/socks5.go b/server/proxy/socks5.go index 5af021b..2215734 100755 --- a/server/proxy/socks5.go +++ b/server/proxy/socks5.go @@ -6,7 +6,7 @@ import ( "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/file" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/astaxie/beego/logs" "io" "net" "strconv" diff --git a/server/proxy/tcp.go b/server/proxy/tcp.go index b7c7267..cb7bc94 100755 --- a/server/proxy/tcp.go +++ b/server/proxy/tcp.go @@ -2,17 +2,18 @@ package proxy import ( "errors" + "net" + "net/http" + "path/filepath" + "strconv" + + "github.com/astaxie/beego" + "github.com/astaxie/beego/logs" "github.com/cnlh/nps/bridge" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/server/connection" - "github.com/cnlh/nps/vender/github.com/astaxie/beego" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" - "net" - "net/http" - "path/filepath" - "strconv" ) type TunnelModeServer struct { diff --git a/server/proxy/udp.go b/server/proxy/udp.go index 62358a4..82f2cf2 100755 --- a/server/proxy/udp.go +++ b/server/proxy/udp.go @@ -6,7 +6,7 @@ import ( "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/lib/pool" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/astaxie/beego/logs" "net" "strings" ) diff --git a/server/server.go b/server/server.go index dff25bd..2534f6e 100644 --- a/server/server.go +++ b/server/server.go @@ -13,8 +13,8 @@ import ( "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/server/proxy" "github.com/cnlh/nps/server/tool" - "github.com/cnlh/nps/vender/github.com/astaxie/beego" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" + "github.com/astaxie/beego" + "github.com/astaxie/beego/logs" "github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/load" "github.com/shirou/gopsutil/mem" diff --git a/server/test/test.go b/server/test/test.go index 3b83565..fbd8eb7 100644 --- a/server/test/test.go +++ b/server/test/test.go @@ -3,7 +3,7 @@ package test import ( "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/file" - "github.com/cnlh/nps/vender/github.com/astaxie/beego" + "github.com/astaxie/beego" "log" "path/filepath" "strconv" diff --git a/server/tool/utils.go b/server/tool/utils.go index f22bfe6..9d801a6 100644 --- a/server/tool/utils.go +++ b/server/tool/utils.go @@ -2,7 +2,7 @@ package tool import ( "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/vender/github.com/astaxie/beego" + "github.com/astaxie/beego" "github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/load" "github.com/shirou/gopsutil/mem" diff --git a/vender/github.com/astaxie/beego/.gitignore b/vender/github.com/astaxie/beego/.gitignore deleted file mode 100755 index e1b6529..0000000 --- a/vender/github.com/astaxie/beego/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -.idea -.vscode -.DS_Store -*.swp -*.swo -beego.iml diff --git a/vender/github.com/astaxie/beego/.gosimpleignore b/vender/github.com/astaxie/beego/.gosimpleignore deleted file mode 100755 index deba14e..0000000 --- a/vender/github.com/astaxie/beego/.gosimpleignore +++ /dev/null @@ -1,4 +0,0 @@ -github.com/cnlh/nps/vender/github.com/astaxie/beego/*/*:S1012 -github.com/cnlh/nps/vender/github.com/astaxie/beego/*:S1012 -github.com/cnlh/nps/vender/github.com/astaxie/beego/*/*:S1007 -github.com/cnlh/nps/vender/github.com/astaxie/beego/*:S1007 \ No newline at end of file diff --git a/vender/github.com/astaxie/beego/.travis.yml b/vender/github.com/astaxie/beego/.travis.yml deleted file mode 100755 index 1fd19c7..0000000 --- a/vender/github.com/astaxie/beego/.travis.yml +++ /dev/null @@ -1,63 +0,0 @@ -language: go - -go: - - "1.9.7" - - "1.10.3" - - "1.11" -services: - - redis-server - - mysql - - postgresql - - memcached -env: - - ORM_DRIVER=sqlite3 ORM_SOURCE=$TRAVIS_BUILD_DIR/orm_test.db - - 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/gomodule/redigo/redis - - go get github.com/beego/x2j - - go get github.com/couchbase/go-couchbase - - go get github.com/beego/goyaml2 - - go get gopkg.in/yaml.v2 - - 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/casbin/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 - - go get -u github.com/go-redis/redis -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 "go get github.com/golang/lint/golint; golint ./...;" - - sh -c "go list ./... | grep -v vendor | xargs go vet -v" - - 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.6" diff --git a/vender/github.com/astaxie/beego/CONTRIBUTING.md b/vender/github.com/astaxie/beego/CONTRIBUTING.md deleted file mode 100755 index ab9b7d1..0000000 --- a/vender/github.com/astaxie/beego/CONTRIBUTING.md +++ /dev/null @@ -1,52 +0,0 @@ -# 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/cnlh/nps/vender/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 \ No newline at end of file diff --git a/vender/github.com/astaxie/beego/LICENSE b/vender/github.com/astaxie/beego/LICENSE deleted file mode 100755 index 5dbd424..0000000 --- a/vender/github.com/astaxie/beego/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -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. -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. \ No newline at end of file diff --git a/vender/github.com/astaxie/beego/README.md b/vender/github.com/astaxie/beego/README.md deleted file mode 100755 index 18af3d3..0000000 --- a/vender/github.com/astaxie/beego/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# Beego [![Build Status](https://travis-ci.org/astaxie/beego.svg?branch=master)](https://travis-ci.org/astaxie/beego) [![GoDoc](http://godoc.org/github.com/cnlh/nps/vender/github.com/astaxie/beego?status.svg)](http://godoc.org/github.com/cnlh/nps/vender/github.com/astaxie/beego) [![Foundation](https://img.shields.io/badge/Golang-Foundation-green.svg)](http://golangfoundation.org) [![Go Report Card](https://goreportcard.com/badge/github.com/cnlh/nps/vender/github.com/astaxie/beego)](https://goreportcard.com/report/github.com/cnlh/nps/vender/github.com/astaxie/beego) - - -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. - - Response time ranking: [web-frameworks](https://github.com/the-benchmarker/web-frameworks). - -###### More info at [beego.me](http://beego.me). - -## Quick Start - -#### Download and install - - go get github.com/cnlh/nps/vender/github.com/astaxie/beego - -#### Create file `hello.go` -```go -package main - -import "github.com/cnlh/nps/vender/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). diff --git a/vender/github.com/astaxie/beego/admin.go b/vender/github.com/astaxie/beego/admin.go deleted file mode 100755 index 6827ef0..0000000 --- a/vender/github.com/astaxie/beego/admin.go +++ /dev/null @@ -1,416 +0,0 @@ -// 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/cnlh/nps/vender/github.com/astaxie/beego/grace" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/toolbox" - "github.com/cnlh/nps/vender/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, pattern string, statusCode int) 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, string, int) 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, string, int) bool { return true } -} - -// AdminIndex is the default http.Handler for admin module. -// it matches url pattern "/". -func adminIndex(rw http.ResponseWriter, _ *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, _ *http.Request) { - data := make(map[interface{}]interface{}) - data["Content"] = toolbox.StatisticsMap.GetMap() - - // do html escape before display path, avoid xss - if content, ok := (data["Content"]).(M); ok { - if resultLists, ok := (content["Data"]).([][]string); ok { - for i := range resultLists { - if len(resultLists[i]) > 0 { - resultLists[i][0] = template.HTMLEscapeString(resultLists[i][0]) - } - } - } - } - - 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(M) - 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 = M{ - "Fields": []string{ - "Router Pattern", - "Filter Function", - }, - } - filterTypes = []string{} - filterTypeData = make(M) - ) - - 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 M) { - 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() M { - var ( - content = M{} - methods = []string{} - methodsData = make(M) - ) - 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, _ *http.Request) { - var ( - result []string - data = make(map[interface{}]interface{}) - resultList = new([][]string) - content = M{ - "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
%s", taskname, t.GetStatus())} - } else { - data["Message"] = []string{"warning", fmt.Sprintf("there's no task which named: %s", taskname)} - } - } - - // List Tasks - content := make(M) - 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())) - } -} diff --git a/vender/github.com/astaxie/beego/admin_test.go b/vender/github.com/astaxie/beego/admin_test.go deleted file mode 100755 index 539837c..0000000 --- a/vender/github.com/astaxie/beego/admin_test.go +++ /dev/null @@ -1,75 +0,0 @@ -package beego - -import ( - "fmt" - "testing" -) - -func TestList_01(t *testing.T) { - m := make(M) - 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() M { - m := make(M) - 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.EnableStaticLogs"] = BConfig.Log.EnableStaticLogs - m["BConfig.Log.AccessLogsFormat"] = BConfig.Log.AccessLogsFormat - m["BConfig.Log.FileLineNum"] = BConfig.Log.FileLineNum - m["BConfig.Log.Outputs"] = BConfig.Log.Outputs - return m -} diff --git a/vender/github.com/astaxie/beego/adminui.go b/vender/github.com/astaxie/beego/adminui.go deleted file mode 100755 index cdcdef3..0000000 --- a/vender/github.com/astaxie/beego/adminui.go +++ /dev/null @@ -1,356 +0,0 @@ -// 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 - -var indexTpl = ` -{{define "content"}} -

Beego Admin Dashboard

-

-For detail usage please check our document: -

-

-Toolbox -

-

-Live Monitor -

-{{.Content}} -{{end}}` - -var profillingTpl = ` -{{define "content"}} -

{{.Title}}

-
-
{{.Content}}
-
-{{end}}` - -var defaultScriptsTpl = `` - -var gcAjaxTpl = ` -{{define "scripts"}} - -{{end}} -` - -var qpsTpl = `{{define "content"}} -

Requests statistics

- - - - {{range .Content.Fields}} - - {{end}} - - - - - {{range $i, $elem := .Content.Data}} - - - - - - - - - - - {{end}} - - -
- {{.}} -
{{index $elem 0}}{{index $elem 1}}{{index $elem 2}}{{index $elem 4}}{{index $elem 6}}{{index $elem 8}}{{index $elem 10}}
-{{end}}` - -var configTpl = ` -{{define "content"}} -

Configurations

-
-{{range $index, $elem := .Content}}
-{{$index}}={{$elem}}
-{{end}}
-
-{{end}} -` - -var routerAndFilterTpl = `{{define "content"}} - - -

{{.Title}}

- -{{range .Content.Methods}} - -
-
{{.}}
-
- - - - {{range $.Content.Fields}} - - {{end}} - - - - - {{$slice := index $.Content.Data .}} - {{range $i, $elem := $slice}} - - - {{range $elem}} - - {{end}} - - - {{end}} - - -
- {{.}} -
- {{.}} -
-
-
-{{end}} - - -{{end}}` - -var tasksTpl = `{{define "content"}} - -

{{.Title}}

- -{{if .Message }} -{{ $messageType := index .Message 0}} -

-{{index .Message 1}} -

-{{end}} - - - - - -{{range .Content.Fields}} - -{{end}} - - - - -{{range $i, $slice := .Content.Data}} - - {{range $slice}} - - {{end}} - - -{{end}} - -
-{{.}} -
- {{.}} - - Run -
- -{{end}}` - -var healthCheckTpl = ` -{{define "content"}} - -

{{.Title}}

- - - -{{range .Content.Fields}} - -{{end}} - - - -{{range $i, $slice := .Content.Data}} - {{ $header := index $slice 0}} - {{ if eq "success" $header}} - - {{else if eq "error" $header}} - - {{else}} - - {{end}} - {{range $j, $elem := $slice}} - {{if ne $j 0}} - - {{end}} - {{end}} - - -{{end}} - - -
- {{.}} -
- {{$elem}} - - {{$header}} -
-{{end}}` - -// The base dashboardTpl -var dashboardTpl = ` - - - - - - - - - - -Welcome to Beego Admin Dashboard - - - - - - - - - - - - - -
-{{template "content" .}} -
- - - - - - - -{{template "scripts" .}} - - -` diff --git a/vender/github.com/astaxie/beego/app.go b/vender/github.com/astaxie/beego/app.go deleted file mode 100755 index 40276c1..0000000 --- a/vender/github.com/astaxie/beego/app.go +++ /dev/null @@ -1,497 +0,0 @@ -// 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 ( - "crypto/tls" - "crypto/x509" - "fmt" - "io/ioutil" - "net" - "net/http" - "net/http/fcgi" - "os" - "path" - "strings" - "time" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/grace" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/utils" - "golang.org/x/crypto/acme/autocert" -) - -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 -} - -// MiddleWare function for http.Handler -type MiddleWare func(http.Handler) http.Handler - -// Run beego application. -func (app *App) Run(mws ...MiddleWare) { - 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 - for i := len(mws) - 1; i >= 0; i-- { - if mws[i] == nil { - continue - } - app.Server.Handler = mws[i](app.Server.Handler) - } - 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 || BConfig.Listen.EnableMutualHTTPS { - go func() { - time.Sleep(1000 * 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 BConfig.Listen.EnableMutualHTTPS { - if err := server.ListenAndServeMutualTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile, BConfig.Listen.TrustCaFile); err != nil { - logs.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid())) - time.Sleep(100 * time.Microsecond) - endRunning <- true - } - } else { - if BConfig.Listen.AutoTLS { - m := autocert.Manager{ - Prompt: autocert.AcceptTOS, - HostPolicy: autocert.HostWhitelist(BConfig.Listen.Domains...), - Cache: autocert.DirCache(BConfig.Listen.TLSCacheDir), - } - app.Server.TLSConfig = &tls.Config{GetCertificate: m.GetCertificate} - BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile = "", "" - } - 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 || BConfig.Listen.EnableMutualHTTPS { - go func() { - time.Sleep(1000 * 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, conflict with http. Please reset https port") - return - } - logs.Info("https server Running on https://%s", app.Server.Addr) - if BConfig.Listen.AutoTLS { - m := autocert.Manager{ - Prompt: autocert.AcceptTOS, - HostPolicy: autocert.HostWhitelist(BConfig.Listen.Domains...), - Cache: autocert.DirCache(BConfig.Listen.TLSCacheDir), - } - app.Server.TLSConfig = &tls.Config{GetCertificate: m.GetCertificate} - BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile = "", "" - } else if BConfig.Listen.EnableMutualHTTPS { - pool := x509.NewCertPool() - data, err := ioutil.ReadFile(BConfig.Listen.TrustCaFile) - if err != nil { - BeeLogger.Info("MutualHTTPS should provide TrustCaFile") - return - } - pool.AppendCertsFromPEM(data) - app.Server.TLSConfig = &tls.Config{ - ClientCAs: pool, - ClientAuth: tls.RequireAndVerifyClientCert, - } - } - 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 -} - -// UnregisterFixedRoute unregisters the route with the specified fixedRoute. It is particularly useful -// in web applications that inherit most routes from a base webapp via the underscore -// import, and aim to overwrite only certain paths. -// The method parameter can be empty or "*" for all HTTP methods, or a particular -// method type (e.g. "GET" or "POST") for selective removal. -// -// Usage (replace "GET" with "*" for all methods): -// beego.UnregisterFixedRoute("/yourpreviouspath", "GET") -// beego.Router("/yourpreviouspath", yourControllerAddress, "get:GetNewPage") -func UnregisterFixedRoute(fixedRoute string, method string) *App { - subPaths := splitPath(fixedRoute) - if method == "" || method == "*" { - for m := range HTTPMETHOD { - if _, ok := BeeApp.Handlers.routers[m]; !ok { - continue - } - if BeeApp.Handlers.routers[m].prefix == strings.Trim(fixedRoute, "/ ") { - findAndRemoveSingleTree(BeeApp.Handlers.routers[m]) - continue - } - findAndRemoveTree(subPaths, BeeApp.Handlers.routers[m], m) - } - return BeeApp - } - // Single HTTP method - um := strings.ToUpper(method) - if _, ok := BeeApp.Handlers.routers[um]; ok { - if BeeApp.Handlers.routers[um].prefix == strings.Trim(fixedRoute, "/ ") { - findAndRemoveSingleTree(BeeApp.Handlers.routers[um]) - return BeeApp - } - findAndRemoveTree(subPaths, BeeApp.Handlers.routers[um], um) - } - return BeeApp -} - -func findAndRemoveTree(paths []string, entryPointTree *Tree, method string) { - for i := range entryPointTree.fixrouters { - if entryPointTree.fixrouters[i].prefix == paths[0] { - if len(paths) == 1 { - if len(entryPointTree.fixrouters[i].fixrouters) > 0 { - // If the route had children subtrees, remove just the functional leaf, - // to allow children to function as before - if len(entryPointTree.fixrouters[i].leaves) > 0 { - entryPointTree.fixrouters[i].leaves[0] = nil - entryPointTree.fixrouters[i].leaves = entryPointTree.fixrouters[i].leaves[1:] - } - } else { - // Remove the *Tree from the fixrouters slice - entryPointTree.fixrouters[i] = nil - - if i == len(entryPointTree.fixrouters)-1 { - entryPointTree.fixrouters = entryPointTree.fixrouters[:i] - } else { - entryPointTree.fixrouters = append(entryPointTree.fixrouters[:i], entryPointTree.fixrouters[i+1:len(entryPointTree.fixrouters)]...) - } - } - return - } - findAndRemoveTree(paths[1:], entryPointTree.fixrouters[i], method) - } - } -} - -func findAndRemoveSingleTree(entryPointTree *Tree) { - if entryPointTree == nil { - return - } - if len(entryPointTree.fixrouters) > 0 { - // If the route had children subtrees, remove just the functional leaf, - // to allow children to function as before - if len(entryPointTree.leaves) > 0 { - entryPointTree.leaves[0] = nil - entryPointTree.leaves = entryPointTree.leaves[1:] - } - } -} - -// 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 -} diff --git a/vender/github.com/astaxie/beego/beego.go b/vender/github.com/astaxie/beego/beego.go deleted file mode 100755 index 7b55a0a..0000000 --- a/vender/github.com/astaxie/beego/beego.go +++ /dev/null @@ -1,123 +0,0 @@ -// 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.10.1" - - // DEV is for develop - DEV = "dev" - // PROD is for production - PROD = "prod" -) - -// Map shortcut -type M map[string]interface{} - -// 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 initiating session , starting middleware , building template, starting admin control and so on. -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]) - } - - BConfig.Listen.Domains = params - } - - BeeApp.Run() -} - -// RunWithMiddleWares Run beego application with middlewares. -func RunWithMiddleWares(addr string, mws ...MiddleWare) { - InitBeforeHTTPRun() - - strs := strings.Split(addr, ":") - if len(strs) > 0 && strs[0] != "" { - BConfig.Listen.HTTPAddr = strs[0] - BConfig.Listen.Domains = []string{strs[0]} - } - if len(strs) > 1 && strs[1] != "" { - BConfig.Listen.HTTPPort, _ = strconv.Atoi(strs[1]) - } - - BeeApp.Run(mws...) -} - -func InitBeforeHTTPRun() { - //init hooks - AddAPPStartHook( - registerMime, - registerDefaultErrorHandler, - registerSession, - registerTemplate, - registerAdmin, - 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() -} diff --git a/vender/github.com/astaxie/beego/config.go b/vender/github.com/astaxie/beego/config.go deleted file mode 100755 index 5832177..0000000 --- a/vender/github.com/astaxie/beego/config.go +++ /dev/null @@ -1,510 +0,0 @@ -// 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/cnlh/nps/vender/github.com/astaxie/beego/config" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" - "github.com/cnlh/nps/vender/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 - AutoTLS bool - Domains []string - TLSCacheDir string - EnableHTTPS bool - EnableMutualHTTPS bool - HTTPSAddr string - HTTPSPort int - HTTPSCertFile string - HTTPSKeyFile string - TrustCaFile 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 - EnableStaticLogs bool //log static files requests default: false - AccessLogsFormat string //access log format: JSON_FORMAT, APACHE_FORMAT or empty string - 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) - } - var filename = "app.conf" - if os.Getenv("BEEGO_RUNMODE") != "" { - filename = os.Getenv("BEEGO_RUNMODE") + ".app.conf" - } - appConfigPath = filepath.Join(workPath, "conf", filename) - if !utils.FileExists(appConfigPath) { - appConfigPath = filepath.Join(AppPath, "conf", filename) - 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) - } - if ctx.Output.Status != 0 { - ctx.ResponseWriter.WriteHeader(ctx.Output.Status) - } else { - ctx.ResponseWriter.WriteHeader(500) - } - } -} - -func newBConfig() *Config { - return &Config{ - AppName: "beego", - RunMode: PROD, - 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, - AutoTLS: false, - Domains: []string{}, - TLSCacheDir: ".", - 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, - EnableStaticLogs: false, - AccessLogsFormat: "APACHE_FORMAT", - 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) -} diff --git a/vender/github.com/astaxie/beego/config/config.go b/vender/github.com/astaxie/beego/config/config.go deleted file mode 100755 index e68e144..0000000 --- a/vender/github.com/astaxie/beego/config/config.go +++ /dev/null @@ -1,242 +0,0 @@ -// 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/cnlh/nps/vender/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 := "" - defaultV := "" - // value start with "${" - for i := 2; i < vLen; i++ { - if value[i] == '|' && (i+1 < vLen && value[i+1] == '|') { - key = value[2:i] - defaultV = 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 = defaultV - } - - 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("%d", v) - if strV == "1" { - return true, nil - } else if strV == "0" { - return false, nil - } - case float64: - if v == 1.0 { - return true, nil - } else if v == 0.0 { - return false, nil - } - } - return false, fmt.Errorf("parsing %q: invalid syntax", val) - } - return false, fmt.Errorf("parsing : 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) -} diff --git a/vender/github.com/astaxie/beego/config/config_test.go b/vender/github.com/astaxie/beego/config/config_test.go deleted file mode 100755 index 15d6ffa..0000000 --- a/vender/github.com/astaxie/beego/config/config_test.go +++ /dev/null @@ -1,55 +0,0 @@ -// 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) - } - } - -} diff --git a/vender/github.com/astaxie/beego/config/env/env.go b/vender/github.com/astaxie/beego/config/env/env.go deleted file mode 100755 index b2c0b82..0000000 --- a/vender/github.com/astaxie/beego/config/env/env.go +++ /dev/null @@ -1,87 +0,0 @@ -// 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/cnlh/nps/vender/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 -} diff --git a/vender/github.com/astaxie/beego/config/env/env_test.go b/vender/github.com/astaxie/beego/config/env/env_test.go deleted file mode 100755 index 3f1d4db..0000000 --- a/vender/github.com/astaxie/beego/config/env/env_test.go +++ /dev/null @@ -1,75 +0,0 @@ -// 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.") - } -} diff --git a/vender/github.com/astaxie/beego/config/fake.go b/vender/github.com/astaxie/beego/config/fake.go deleted file mode 100755 index d21ab82..0000000 --- a/vender/github.com/astaxie/beego/config/fake.go +++ /dev/null @@ -1,134 +0,0 @@ -// 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 Configer -func NewFakeConfig() Configer { - return &fakeConfigContainer{ - data: make(map[string]string), - } -} diff --git a/vender/github.com/astaxie/beego/config/ini.go b/vender/github.com/astaxie/beego/config/ini.go deleted file mode 100755 index 002e5e0..0000000 --- a/vender/github.com/astaxie/beego/config/ini.go +++ /dev/null @@ -1,504 +0,0 @@ -// 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 - tmpBuf := bytes.NewBuffer(nil) - for { - tmpBuf.Reset() - - shouldBreak := false - for { - tmp, isPrefix, err := buf.ReadLine() - if err == io.EOF { - shouldBreak = true - break - } - - //It might be a good idea to throw a error on all unknonw errors? - if _, ok := err.(*os.PathError); ok { - return nil, err - } - - tmpBuf.Write(tmp) - if isPrefix { - continue - } - - if !isPrefix { - break - } - } - if shouldBreak { - break - } - - line := tmpBuf.Bytes() - 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 defaultval -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 defaultval -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 defaultval -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 defaultval -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 defaultval -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 defaultval -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 Function. -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{}) -} diff --git a/vender/github.com/astaxie/beego/config/ini_test.go b/vender/github.com/astaxie/beego/config/ini_test.go deleted file mode 100755 index ffcdb29..0000000 --- a/vender/github.com/astaxie/beego/config/ini_test.go +++ /dev/null @@ -1,190 +0,0 @@ -// 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) - } - } - - } -} diff --git a/vender/github.com/astaxie/beego/config/json.go b/vender/github.com/astaxie/beego/config/json.go deleted file mode 100755 index 74c18c9..0000000 --- a/vender/github.com/astaxie/beego/config/json.go +++ /dev/null @@ -1,266 +0,0 @@ -// 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 defaultval -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 defaultval -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 defaultval -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 defaultval -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 defaultval -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{}) -} diff --git a/vender/github.com/astaxie/beego/config/json_test.go b/vender/github.com/astaxie/beego/config/json_test.go deleted file mode 100755 index 16f4240..0000000 --- a/vender/github.com/astaxie/beego/config/json_test.go +++ /dev/null @@ -1,222 +0,0 @@ -// 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("unknown", true) { - t.Error("unknown keys with default value wrong") - } -} diff --git a/vender/github.com/astaxie/beego/config/xml/xml.go b/vender/github.com/astaxie/beego/config/xml/xml.go deleted file mode 100755 index fa825df..0000000 --- a/vender/github.com/astaxie/beego/config/xml/xml.go +++ /dev/null @@ -1,228 +0,0 @@ -// 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/cnlh/nps/vender/github.com/astaxie/beego/config/xml" -// "github.com/cnlh/nps/vender/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/beego/x2j" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/config" -) - -// Config is a xml config parser and implements Config interface. -// xml configurations should be included in tag. -// only support key/value pair as value 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 defaultval -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 defaultval -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 defaultval -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 defaultval -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 defaultval -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{}) -} diff --git a/vender/github.com/astaxie/beego/config/xml/xml_test.go b/vender/github.com/astaxie/beego/config/xml/xml_test.go deleted file mode 100755 index 13d885e..0000000 --- a/vender/github.com/astaxie/beego/config/xml/xml_test.go +++ /dev/null @@ -1,125 +0,0 @@ -// 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/cnlh/nps/vender/github.com/astaxie/beego/config" -) - -func TestXML(t *testing.T) { - - var ( - //xml parse should incluce in tags - xmlcontext = ` - -beeapi -8080 -3600 -3.1415976 -dev -false -true -${GOPATH} -${GOPATH||/home/go} - -1 -MySection - - -` - 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") - } -} diff --git a/vender/github.com/astaxie/beego/config/yaml/yaml.go b/vender/github.com/astaxie/beego/config/yaml/yaml.go deleted file mode 100755 index c9086df..0000000 --- a/vender/github.com/astaxie/beego/config/yaml/yaml.go +++ /dev/null @@ -1,316 +0,0 @@ -// 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/cnlh/nps/vender/github.com/astaxie/beego/config/yaml" -// "github.com/cnlh/nps/vender/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/beego/goyaml2" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/config" -) - -// 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.RWMutex -} - -// 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 defaultval -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 defaultval -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 defaultval -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 defaultval -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 defaultval -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") - } - c.RLock() - defer c.RUnlock() - - keys := strings.Split(key, ".") - tmpData := c.data - for idx, k := range keys { - if v, ok := tmpData[k]; ok { - switch v.(type) { - case map[string]interface{}: - { - tmpData = v.(map[string]interface{}) - if idx == len(keys)-1 { - return tmpData, nil - } - } - default: - { - return v, nil - } - - } - } - } - return nil, fmt.Errorf("not exist key %q", key) -} - -func init() { - config.Register("yaml", &Config{}) -} diff --git a/vender/github.com/astaxie/beego/config/yaml/yaml_test.go b/vender/github.com/astaxie/beego/config/yaml/yaml_test.go deleted file mode 100755 index a8221c2..0000000 --- a/vender/github.com/astaxie/beego/config/yaml/yaml_test.go +++ /dev/null @@ -1,115 +0,0 @@ -// 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/cnlh/nps/vender/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") - } - -} diff --git a/vender/github.com/astaxie/beego/config_test.go b/vender/github.com/astaxie/beego/config_test.go deleted file mode 100755 index f8a82ce..0000000 --- a/vender/github.com/astaxie/beego/config_test.go +++ /dev/null @@ -1,138 +0,0 @@ -// 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/cnlh/nps/vender/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 := M{} - json.Unmarshal(bs, &jsonMap) - - configMap := M{} - for k, v := range jsonMap { - if reflect.TypeOf(v).Kind() == reflect.Map { - for k1, v1 := range v.(M) { - if reflect.TypeOf(v1).Kind() == reflect.Map { - for k2, v2 := range v1.(M) { - 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(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() - } -} diff --git a/vender/github.com/astaxie/beego/context/acceptencoder.go b/vender/github.com/astaxie/beego/context/acceptencoder.go deleted file mode 100755 index b4e2492..0000000 --- a/vender/github.com/astaxie/beego/context/acceptencoder.go +++ /dev/null @@ -1,232 +0,0 @@ -// 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 -} diff --git a/vender/github.com/astaxie/beego/context/acceptencoder_test.go b/vender/github.com/astaxie/beego/context/acceptencoder_test.go deleted file mode 100755 index e3d61e2..0000000 --- a/vender/github.com/astaxie/beego/context/acceptencoder_test.go +++ /dev/null @@ -1,59 +0,0 @@ -// 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() - } -} diff --git a/vender/github.com/astaxie/beego/context/context.go b/vender/github.com/astaxie/beego/context/context.go deleted file mode 100755 index 92b57f8..0000000 --- a/vender/github.com/astaxie/beego/context/context.go +++ /dev/null @@ -1,262 +0,0 @@ -// 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/cnlh/nps/vender/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/cnlh/nps/vender/github.com/astaxie/beego/utils" -) - -//commonly used mime-types -const ( - ApplicationJSON = "application/json" - ApplicationXML = "application/xml" - ApplicationYAML = "application/x-yaml" - TextXML = "text/xml" -) - -// 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 -} - -// Pusher http.Pusher -func (r *Response) Pusher() (pusher http.Pusher) { - if pusher, ok := r.ResponseWriter.(http.Pusher); ok { - return pusher - } - return nil -} diff --git a/vender/github.com/astaxie/beego/context/context_test.go b/vender/github.com/astaxie/beego/context/context_test.go deleted file mode 100755 index 7c0535e..0000000 --- a/vender/github.com/astaxie/beego/context/context_test.go +++ /dev/null @@ -1,47 +0,0 @@ -// 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() - } -} diff --git a/vender/github.com/astaxie/beego/context/input.go b/vender/github.com/astaxie/beego/context/input.go deleted file mode 100755 index 9bb05c6..0000000 --- a/vender/github.com/astaxie/beego/context/input.go +++ /dev/null @@ -1,668 +0,0 @@ -// 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" - "compress/gzip" - "errors" - "io" - "io/ioutil" - "net" - "net/http" - "net/url" - "reflect" - "regexp" - "strconv" - "strings" - - "github.com/cnlh/nps/vender/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)(?:,|$)`) - acceptsYAMLRegex = regexp.MustCompile(`(application/x-yaml)(?:,|$)`) - 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 != "" { - if hostPart, _, err := net.SplitHostPort(input.Context.Request.Host); err == nil { - return hostPart - } - 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")) -} - -// AcceptsYAML Checks if request accepts json response -func (input *BeegoInput) AcceptsYAML() bool { - return acceptsYAMLRegex.MatchString(input.Header("Accept")) -} - -// IP returns request client ip. -// if in proxy, return first proxy id. -// if error, return RemoteAddr. -func (input *BeegoInput) IP() string { - ips := input.Proxy() - if len(ips) > 0 && ips[0] != "" { - rip, _, err := net.SplitHostPort(ips[0]) - if err != nil { - rip = ips[0] - } - return rip - } - if ip, _, err := net.SplitHostPort(input.Context.Request.RemoteAddr); err == nil { - return ip - } - return input.Context.Request.RemoteAddr -} - -// 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 { - if _, portPart, err := net.SplitHostPort(input.Context.Request.Host); err == nil { - port, _ := strconv.Atoi(portPart) - 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{} - } - - var requestbody []byte - safe := &io.LimitedReader{R: input.Context.Request.Body, N: MaxMemory} - if input.Header("Content-Encoding") == "gzip" { - reader, err := gzip.NewReader(safe) - if err != nil { - return nil - } - requestbody, _ = ioutil.ReadAll(reader) - } else { - requestbody, _ = ioutil.ReadAll(safe) - } - - input.Context.Request.Body.Close() - bf := bytes.NewBuffer(requestbody) - input.Context.Request.Body = http.MaxBytesReader(input.Context.ResponseWriter, ioutil.NopCloser(bf), MaxMemory) - 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 -} diff --git a/vender/github.com/astaxie/beego/context/input_test.go b/vender/github.com/astaxie/beego/context/input_test.go deleted file mode 100755 index db812a0..0000000 --- a/vender/github.com/astaxie/beego/context/input_test.go +++ /dev/null @@ -1,207 +0,0 @@ -// 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") - } - -} diff --git a/vender/github.com/astaxie/beego/context/output.go b/vender/github.com/astaxie/beego/context/output.go deleted file mode 100755 index 3e277ab..0000000 --- a/vender/github.com/astaxie/beego/context/output.go +++ /dev/null @@ -1,395 +0,0 @@ -// 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" - "gopkg.in/yaml.v2" -) - -// 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.Output.Body([]byte(err.Error())) - }) -} - -// JSON writes json to response body. -// if encoding is true, it converts utf-8 to \u0000 type. -func (output *BeegoOutput) JSON(data interface{}, hasIndent bool, encoding 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 encoding { - content = []byte(stringsToJSON(string(content))) - } - return output.Body(content) -} - - -// YAML writes yaml to response body. -func (output *BeegoOutput) YAML(data interface{}) error { - output.Header("Content-Type", "application/x-yaml; charset=utf-8") - var content []byte - var err error - content, err = yaml.Marshal(data) - if err != nil { - http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError) - return err - } - 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) -} - -// ServeFormatted serve YAML, XML OR JSON, depending on the value of the Accept header -func (output *BeegoOutput) ServeFormatted(data interface{}, hasIndent bool, hasEncode ...bool) { - accept := output.Context.Input.Header("Accept") - switch accept { - case ApplicationYAML: - output.YAML(data) - case ApplicationXML, TextXML: - output.XML(data, hasIndent) - default: - output.JSON(data, hasIndent, len(hasEncode) > 0 && hasEncode[0]) - } -} - -// 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.PathEscape(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 not found. -func (output *BeegoOutput) IsNotFound() bool { - return output.Status == 404 -} - -// IsClientError returns boolean of this request client sends error data. -// HTTP 4xx means client error. -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") - if rint < 0x100 { - jsons.WriteString("00") - } else if rint < 0x1000 { - jsons.WriteString("0") - } - 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) -} diff --git a/vender/github.com/astaxie/beego/context/param/conv.go b/vender/github.com/astaxie/beego/context/param/conv.go deleted file mode 100755 index 765147d..0000000 --- a/vender/github.com/astaxie/beego/context/param/conv.go +++ /dev/null @@ -1,78 +0,0 @@ -package param - -import ( - "fmt" - "reflect" - - beecontext "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" -) - -// ConvertParams converts http method params to values that will be passed to the method controller as arguments -func ConvertParams(methodParams []*MethodParam, methodType reflect.Type, ctx *beecontext.Context) (result []reflect.Value) { - result = make([]reflect.Value, 0, len(methodParams)) - for i := 0; i < len(methodParams); i++ { - reflectValue := convertParam(methodParams[i], methodType.In(i), ctx) - result = append(result, reflectValue) - } - return -} - -func convertParam(param *MethodParam, paramType reflect.Type, ctx *beecontext.Context) (result reflect.Value) { - paramValue := getParamValue(param, ctx) - if paramValue == "" { - if param.required { - ctx.Abort(400, fmt.Sprintf("Missing parameter %s", param.name)) - } else { - paramValue = param.defaultValue - } - } - - reflectValue, err := parseValue(param, paramValue, paramType) - if err != nil { - logs.Debug(fmt.Sprintf("Error converting param %s to type %s. Value: %v, Error: %s", param.name, paramType, paramValue, err)) - ctx.Abort(400, fmt.Sprintf("Invalid parameter %s. Can not convert %v to type %s", param.name, paramValue, paramType)) - } - - return reflectValue -} - -func getParamValue(param *MethodParam, ctx *beecontext.Context) string { - switch param.in { - case body: - return string(ctx.Input.RequestBody) - case header: - return ctx.Input.Header(param.name) - case path: - return ctx.Input.Query(":" + param.name) - default: - return ctx.Input.Query(param.name) - } -} - -func parseValue(param *MethodParam, paramValue string, paramType reflect.Type) (result reflect.Value, err error) { - if paramValue == "" { - return reflect.Zero(paramType), nil - } - parser := getParser(param, paramType) - value, err := parser.parse(paramValue, paramType) - if err != nil { - return result, err - } - - return safeConvert(reflect.ValueOf(value), paramType) -} - -func safeConvert(value reflect.Value, t reflect.Type) (result reflect.Value, err error) { - defer func() { - if r := recover(); r != nil { - var ok bool - err, ok = r.(error) - if !ok { - err = fmt.Errorf("%v", r) - } - } - }() - result = value.Convert(t) - return -} diff --git a/vender/github.com/astaxie/beego/context/param/methodparams.go b/vender/github.com/astaxie/beego/context/param/methodparams.go deleted file mode 100755 index cd6708a..0000000 --- a/vender/github.com/astaxie/beego/context/param/methodparams.go +++ /dev/null @@ -1,69 +0,0 @@ -package param - -import ( - "fmt" - "strings" -) - -//MethodParam keeps param information to be auto passed to controller methods -type MethodParam struct { - name string - in paramType - required bool - defaultValue string -} - -type paramType byte - -const ( - param paramType = iota - path - body - header -) - -//New creates a new MethodParam with name and specific options -func New(name string, opts ...MethodParamOption) *MethodParam { - return newParam(name, nil, opts) -} - -func newParam(name string, parser paramParser, opts []MethodParamOption) (param *MethodParam) { - param = &MethodParam{name: name} - for _, option := range opts { - option(param) - } - return -} - -//Make creates an array of MethodParmas or an empty array -func Make(list ...*MethodParam) []*MethodParam { - if len(list) > 0 { - return list - } - return nil -} - -func (mp *MethodParam) String() string { - options := []string{} - result := "param.New(\"" + mp.name + "\"" - if mp.required { - options = append(options, "param.IsRequired") - } - switch mp.in { - case path: - options = append(options, "param.InPath") - case body: - options = append(options, "param.InBody") - case header: - options = append(options, "param.InHeader") - } - if mp.defaultValue != "" { - options = append(options, fmt.Sprintf(`param.Default("%s")`, mp.defaultValue)) - } - if len(options) > 0 { - result += ", " - } - result += strings.Join(options, ", ") - result += ")" - return result -} diff --git a/vender/github.com/astaxie/beego/context/param/options.go b/vender/github.com/astaxie/beego/context/param/options.go deleted file mode 100755 index 3d5ba01..0000000 --- a/vender/github.com/astaxie/beego/context/param/options.go +++ /dev/null @@ -1,37 +0,0 @@ -package param - -import ( - "fmt" -) - -// MethodParamOption defines a func which apply options on a MethodParam -type MethodParamOption func(*MethodParam) - -// IsRequired indicates that this param is required and can not be omitted from the http request -var IsRequired MethodParamOption = func(p *MethodParam) { - p.required = true -} - -// InHeader indicates that this param is passed via an http header -var InHeader MethodParamOption = func(p *MethodParam) { - p.in = header -} - -// InPath indicates that this param is part of the URL path -var InPath MethodParamOption = func(p *MethodParam) { - p.in = path -} - -// InBody indicates that this param is passed as an http request body -var InBody MethodParamOption = func(p *MethodParam) { - p.in = body -} - -// Default provides a default value for the http param -func Default(defaultValue interface{}) MethodParamOption { - return func(p *MethodParam) { - if defaultValue != nil { - p.defaultValue = fmt.Sprint(defaultValue) - } - } -} diff --git a/vender/github.com/astaxie/beego/context/param/parsers.go b/vender/github.com/astaxie/beego/context/param/parsers.go deleted file mode 100755 index 421aecf..0000000 --- a/vender/github.com/astaxie/beego/context/param/parsers.go +++ /dev/null @@ -1,149 +0,0 @@ -package param - -import ( - "encoding/json" - "reflect" - "strconv" - "strings" - "time" -) - -type paramParser interface { - parse(value string, toType reflect.Type) (interface{}, error) -} - -func getParser(param *MethodParam, t reflect.Type) paramParser { - switch t.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return intParser{} - case reflect.Slice: - if t.Elem().Kind() == reflect.Uint8 { //treat []byte as string - return stringParser{} - } - if param.in == body { - return jsonParser{} - } - elemParser := getParser(param, t.Elem()) - if elemParser == (jsonParser{}) { - return elemParser - } - return sliceParser(elemParser) - case reflect.Bool: - return boolParser{} - case reflect.String: - return stringParser{} - case reflect.Float32, reflect.Float64: - return floatParser{} - case reflect.Ptr: - elemParser := getParser(param, t.Elem()) - if elemParser == (jsonParser{}) { - return elemParser - } - return ptrParser(elemParser) - default: - if t.PkgPath() == "time" && t.Name() == "Time" { - return timeParser{} - } - return jsonParser{} - } -} - -type parserFunc func(value string, toType reflect.Type) (interface{}, error) - -func (f parserFunc) parse(value string, toType reflect.Type) (interface{}, error) { - return f(value, toType) -} - -type boolParser struct { -} - -func (p boolParser) parse(value string, toType reflect.Type) (interface{}, error) { - return strconv.ParseBool(value) -} - -type stringParser struct { -} - -func (p stringParser) parse(value string, toType reflect.Type) (interface{}, error) { - return value, nil -} - -type intParser struct { -} - -func (p intParser) parse(value string, toType reflect.Type) (interface{}, error) { - return strconv.Atoi(value) -} - -type floatParser struct { -} - -func (p floatParser) parse(value string, toType reflect.Type) (interface{}, error) { - if toType.Kind() == reflect.Float32 { - res, err := strconv.ParseFloat(value, 32) - if err != nil { - return nil, err - } - return float32(res), nil - } - return strconv.ParseFloat(value, 64) -} - -type timeParser struct { -} - -func (p timeParser) parse(value string, toType reflect.Type) (result interface{}, err error) { - result, err = time.Parse(time.RFC3339, value) - if err != nil { - result, err = time.Parse("2006-01-02", value) - } - return -} - -type jsonParser struct { -} - -func (p jsonParser) parse(value string, toType reflect.Type) (interface{}, error) { - pResult := reflect.New(toType) - v := pResult.Interface() - err := json.Unmarshal([]byte(value), v) - if err != nil { - return nil, err - } - return pResult.Elem().Interface(), nil -} - -func sliceParser(elemParser paramParser) paramParser { - return parserFunc(func(value string, toType reflect.Type) (interface{}, error) { - values := strings.Split(value, ",") - result := reflect.MakeSlice(toType, 0, len(values)) - elemType := toType.Elem() - for _, v := range values { - parsedValue, err := elemParser.parse(v, elemType) - if err != nil { - return nil, err - } - result = reflect.Append(result, reflect.ValueOf(parsedValue)) - } - return result.Interface(), nil - }) -} - -func ptrParser(elemParser paramParser) paramParser { - return parserFunc(func(value string, toType reflect.Type) (interface{}, error) { - parsedValue, err := elemParser.parse(value, toType.Elem()) - if err != nil { - return nil, err - } - newValPtr := reflect.New(toType.Elem()) - newVal := reflect.Indirect(newValPtr) - convertedVal, err := safeConvert(reflect.ValueOf(parsedValue), toType.Elem()) - if err != nil { - return nil, err - } - - newVal.Set(convertedVal) - return newValPtr.Interface(), nil - }) -} diff --git a/vender/github.com/astaxie/beego/context/param/parsers_test.go b/vender/github.com/astaxie/beego/context/param/parsers_test.go deleted file mode 100755 index 7065a28..0000000 --- a/vender/github.com/astaxie/beego/context/param/parsers_test.go +++ /dev/null @@ -1,84 +0,0 @@ -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("Conversion 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) - } -} diff --git a/vender/github.com/astaxie/beego/context/renderer.go b/vender/github.com/astaxie/beego/context/renderer.go deleted file mode 100755 index 36a7cb5..0000000 --- a/vender/github.com/astaxie/beego/context/renderer.go +++ /dev/null @@ -1,12 +0,0 @@ -package context - -// Renderer defines an http response renderer -type Renderer interface { - Render(ctx *Context) -} - -type rendererFunc func(ctx *Context) - -func (f rendererFunc) Render(ctx *Context) { - f(ctx) -} diff --git a/vender/github.com/astaxie/beego/context/response.go b/vender/github.com/astaxie/beego/context/response.go deleted file mode 100755 index 9c3c715..0000000 --- a/vender/github.com/astaxie/beego/context/response.go +++ /dev/null @@ -1,27 +0,0 @@ -package context - -import ( - "strconv" - - "net/http" -) - -const ( - //BadRequest indicates http error 400 - BadRequest StatusCode = http.StatusBadRequest - - //NotFound indicates http error 404 - NotFound StatusCode = http.StatusNotFound -) - -// StatusCode sets the http response status code -type StatusCode int - -func (s StatusCode) Error() string { - return strconv.Itoa(int(s)) -} - -// Render sets the http status code -func (s StatusCode) Render(ctx *Context) { - ctx.Output.SetStatus(int(s)) -} diff --git a/vender/github.com/astaxie/beego/controller.go b/vender/github.com/astaxie/beego/controller.go deleted file mode 100755 index 74cf8a8..0000000 --- a/vender/github.com/astaxie/beego/controller.go +++ /dev/null @@ -1,683 +0,0 @@ -// 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/cnlh/nps/vender/github.com/astaxie/beego/context" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context/param" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" -) - -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) -) - -// ControllerFilter store the filter for controller -type ControllerFilter struct { - Pattern string - Pos int - Filter FilterFunc - ReturnOnOutput bool - ResetParams bool -} - -// ControllerFilterComments store the comment for controller level filter -type ControllerFilterComments struct { - Pattern string - Pos int - Filter string // NOQA - ReturnOnOutput bool - ResetParams bool -} - -// ControllerImportComments store the import comment for controller needed -type ControllerImportComments struct { - ImportPath string - ImportAlias string -} - -// ControllerComments store the comment for the controller method -type ControllerComments struct { - Method string - Router string - Filters []*ControllerFilter - ImportComments []*ControllerImportComments - FilterComments []*ControllerFilterComments - AllowHTTPMethods []string - Params []map[string]string - MethodParams []*param.MethodParam -} - -// ControllerCommentsSlice implements the sort interface -type ControllerCommentsSlice []ControllerComments - -func (p ControllerCommentsSlice) Len() int { return len(p) } -func (p ControllerCommentsSlice) Less(i, j int) bool { return p[i].Router < p[j].Router } -func (p ControllerCommentsSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - -// 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) { - logAccess(c.Ctx, nil, code) - c.Ctx.Redirect(code, url) -} - -// Set the data depending on the accepted -func (c *Controller) SetData(data interface{}) { - accept := c.Ctx.Input.Header("Accept") - switch accept { - case context.ApplicationYAML: - c.Data["yaml"] = data - case context.ApplicationXML, context.TextXML: - c.Data["xml"] = data - default: - c.Data["json"] = data - } -} - -// 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 = BConfig.RunMode != PROD - hasEncoding = len(encoding) > 0 && encoding[0] - ) - - c.Ctx.Output.JSON(c.Data["json"], hasIndent, hasEncoding) -} - -// ServeJSONP sends a jsonp response. -func (c *Controller) ServeJSONP() { - hasIndent := BConfig.RunMode != PROD - c.Ctx.Output.JSONP(c.Data["jsonp"], hasIndent) -} - -// ServeXML sends xml response. -func (c *Controller) ServeXML() { - hasIndent := BConfig.RunMode != PROD - c.Ctx.Output.XML(c.Data["xml"], hasIndent) -} - -// ServeXML sends xml response. -func (c *Controller) ServeYAML() { - c.Ctx.Output.YAML(c.Data["yaml"]) -} - -// ServeFormatted serve YAML, XML OR JSON, depending on the value of the Accept header -func (c *Controller) ServeFormatted(encoding ...bool) { - hasIndent := BConfig.RunMode != PROD - hasEncoding := len(encoding) > 0 && encoding[0] - c.Ctx.Output.ServeFormatted(c.Data, hasIndent, hasEncoding) -} - -// 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 `` -} - -// GetControllerAndAction gets the executing controller name and action name. -func (c *Controller) GetControllerAndAction() (string, string) { - return c.controllerName, c.actionName -} diff --git a/vender/github.com/astaxie/beego/controller_test.go b/vender/github.com/astaxie/beego/controller_test.go deleted file mode 100755 index 910ddad..0000000 --- a/vender/github.com/astaxie/beego/controller_test.go +++ /dev/null @@ -1,181 +0,0 @@ -// 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/cnlh/nps/vender/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, `
{{.Content}}
`) - genFile(dir2, dir2file, `{{.Content}}`) - - 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 != "
value2
" { - t.Fatalf("TestAdditionalViewPaths expect %s got %s", "
value2
", 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() -} diff --git a/vender/github.com/astaxie/beego/doc.go b/vender/github.com/astaxie/beego/doc.go deleted file mode 100755 index f7dae32..0000000 --- a/vender/github.com/astaxie/beego/doc.go +++ /dev/null @@ -1,17 +0,0 @@ -/* -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/cnlh/nps/vender/github.com/astaxie/beego" - - func main() { - beego.Run() - } - -more information: http://beego.me -*/ -package beego diff --git a/vender/github.com/astaxie/beego/error.go b/vender/github.com/astaxie/beego/error.go deleted file mode 100755 index c3a4a5b..0000000 --- a/vender/github.com/astaxie/beego/error.go +++ /dev/null @@ -1,474 +0,0 @@ -// 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/cnlh/nps/vender/github.com/astaxie/beego/context" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/utils" -) - -const ( - errorTypeHandler = iota - errorTypeController -) - -var tpl = ` - - - - - beego application error - - - - - -
- - - - - - - - - - -
Request Method: {{.RequestMethod}}
Request URL: {{.RequestURL}}
RemoteAddr: {{.RemoteAddr }}
-
- Stack -
{{.Stack}}
-
-
- - - -` - -// 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(), - } - t.Execute(ctx.ResponseWriter, data) -} - -var errtpl = ` - - - - - {{.Title}} - - - -
-
- -
- {{.Content}} - Go Home
- -
Powered by beego {{.BeegoVersion}} -
-
-
- - -` - -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, - "
The page you have requested can't be authorized."+ - "
Perhaps you are here because:"+ - "

    "+ - "
    The credentials you supplied are incorrect"+ - "
    There are errors in the website address"+ - "
", - ) -} - -// show 402 Payment Required -func paymentRequired(rw http.ResponseWriter, r *http.Request) { - responseError(rw, r, - 402, - "
The page you have requested Payment Required."+ - "
Perhaps you are here because:"+ - "

    "+ - "
    The credentials you supplied are incorrect"+ - "
    There are errors in the website address"+ - "
", - ) -} - -// show 403 forbidden error. -func forbidden(rw http.ResponseWriter, r *http.Request) { - responseError(rw, r, - 403, - "
The page you have requested is forbidden."+ - "
Perhaps you are here because:"+ - "

    "+ - "
    Your address may be blocked"+ - "
    The site may be disabled"+ - "
    You need to log in"+ - "
", - ) -} - -// show 422 missing xsrf token -func missingxsrf(rw http.ResponseWriter, r *http.Request) { - responseError(rw, r, - 422, - "
The page you have requested is forbidden."+ - "
Perhaps you are here because:"+ - "

    "+ - "
    '_xsrf' argument missing from POST"+ - "
", - ) -} - -// show 417 invalid xsrf token -func invalidxsrf(rw http.ResponseWriter, r *http.Request) { - responseError(rw, r, - 417, - "
The page you have requested is forbidden."+ - "
Perhaps you are here because:"+ - "

    "+ - "
    expected XSRF not found"+ - "
", - ) -} - -// show 404 not found error. -func notFound(rw http.ResponseWriter, r *http.Request) { - responseError(rw, r, - 404, - "
The page you have requested has flown the coop."+ - "
Perhaps you are here because:"+ - "

    "+ - "
    The page has moved"+ - "
    The page no longer exists"+ - "
    You were looking for your puppy and got lost"+ - "
    You like 404 pages"+ - "
", - ) -} - -// show 405 Method Not Allowed -func methodNotAllowed(rw http.ResponseWriter, r *http.Request) { - responseError(rw, r, - 405, - "
The method you have requested Not Allowed."+ - "
Perhaps you are here because:"+ - "

    "+ - "
    The method specified in the Request-Line is not allowed for the resource identified by the Request-URI"+ - "
    The response MUST include an Allow header containing a list of valid methods for the requested resource."+ - "
", - ) -} - -// show 500 internal server error. -func internalServerError(rw http.ResponseWriter, r *http.Request) { - responseError(rw, r, - 500, - "
The page you have requested is down right now."+ - "

    "+ - "
    Please try again later and report the error to the website administrator"+ - "
", - ) -} - -// show 501 Not Implemented. -func notImplemented(rw http.ResponseWriter, r *http.Request) { - responseError(rw, r, - 501, - "
The page you have requested is Not Implemented."+ - "

    "+ - "
    Please try again later and report the error to the website administrator"+ - "
", - ) -} - -// show 502 Bad Gateway. -func badGateway(rw http.ResponseWriter, r *http.Request) { - responseError(rw, r, - 502, - "
The page you have requested is down right now."+ - "

    "+ - "
    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."+ - "
    Please try again later and report the error to the website administrator"+ - "
", - ) -} - -// show 503 service unavailable error. -func serviceUnavailable(rw http.ResponseWriter, r *http.Request) { - responseError(rw, r, - 503, - "
The page you have requested is unavailable."+ - "
Perhaps you are here because:"+ - "

    "+ - "

    The page is overloaded"+ - "
    Please try again later."+ - "
", - ) -} - -// show 504 Gateway Timeout. -func gatewayTimeout(rw http.ResponseWriter, r *http.Request) { - responseError(rw, r, - 504, - "
The page you have requested is unavailable"+ - "
Perhaps you are here because:"+ - "

    "+ - "

    The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI."+ - "
    Please try again later."+ - "
", - ) -} - -func responseError(rw http.ResponseWriter, r *http.Request, errCode int, errContent string) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := M{ - "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) { - //make sure to log the error in the access log - logAccess(ctx, nil, code) - - 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() - } -} diff --git a/vender/github.com/astaxie/beego/error_test.go b/vender/github.com/astaxie/beego/error_test.go deleted file mode 100755 index 378aa95..0000000 --- a/vender/github.com/astaxie/beego/error_test.go +++ /dev/null @@ -1,88 +0,0 @@ -// 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(w.Body.String(), 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 w.Body.String() != parseCodeError { - t.Fail() - } -} diff --git a/vender/github.com/astaxie/beego/filter.go b/vender/github.com/astaxie/beego/filter.go deleted file mode 100755 index 854ff0a..0000000 --- a/vender/github.com/astaxie/beego/filter.go +++ /dev/null @@ -1,44 +0,0 @@ -// 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/cnlh/nps/vender/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 -} diff --git a/vender/github.com/astaxie/beego/filter_test.go b/vender/github.com/astaxie/beego/filter_test.go deleted file mode 100755 index 03b57ed..0000000 --- a/vender/github.com/astaxie/beego/filter_test.go +++ /dev/null @@ -1,68 +0,0 @@ -// 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/cnlh/nps/vender/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") - } -} diff --git a/vender/github.com/astaxie/beego/flash.go b/vender/github.com/astaxie/beego/flash.go deleted file mode 100755 index a6485a1..0000000 --- a/vender/github.com/astaxie/beego/flash.go +++ /dev/null @@ -1,110 +0,0 @@ -// 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 -} diff --git a/vender/github.com/astaxie/beego/flash_test.go b/vender/github.com/astaxie/beego/flash_test.go deleted file mode 100755 index d5e9608..0000000 --- a/vender/github.com/astaxie/beego/flash_test.go +++ /dev/null @@ -1,54 +0,0 @@ -// 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") - } -} diff --git a/vender/github.com/astaxie/beego/go.mod b/vender/github.com/astaxie/beego/go.mod deleted file mode 100755 index c99332d..0000000 --- a/vender/github.com/astaxie/beego/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/cnlh/nps/vender/github.com/astaxie/beego - -require ( - golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb - golang.org/x/net v0.0.0-20170920234330-b60f3a92103d - google.golang.org/appengine v1.1.0 - gopkg.in/yaml.v2 v2.2.1 -) diff --git a/vender/github.com/astaxie/beego/go.sum b/vender/github.com/astaxie/beego/go.sum deleted file mode 100755 index 2e9030f..0000000 --- a/vender/github.com/astaxie/beego/go.sum +++ /dev/null @@ -1,7 +0,0 @@ -golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb h1:Ah9YqXLj6fEgeKqcmBuLCbAsrF3ScD7dJ/bYM0C6tXI= -golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/net v0.0.0-20170920234330-b60f3a92103d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vender/github.com/astaxie/beego/grace/conn.go b/vender/github.com/astaxie/beego/grace/conn.go deleted file mode 100755 index e020f85..0000000 --- a/vender/github.com/astaxie/beego/grace/conn.go +++ /dev/null @@ -1,39 +0,0 @@ -package grace - -import ( - "errors" - "net" - "sync" -) - -type graceConn struct { - net.Conn - server *Server - m sync.Mutex - closed bool -} - -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.m.Lock() - if c.closed { - c.m.Unlock() - return - } - c.server.wg.Done() - c.closed = true - c.m.Unlock() - return c.Conn.Close() -} diff --git a/vender/github.com/astaxie/beego/grace/grace.go b/vender/github.com/astaxie/beego/grace/grace.go deleted file mode 100755 index a060f94..0000000 --- a/vender/github.com/astaxie/beego/grace/grace.go +++ /dev/null @@ -1,166 +0,0 @@ -// 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/cnlh/nps/vender/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) -} diff --git a/vender/github.com/astaxie/beego/grace/listener.go b/vender/github.com/astaxie/beego/grace/listener.go deleted file mode 100755 index 7ede63a..0000000 --- a/vender/github.com/astaxie/beego/grace/listener.go +++ /dev/null @@ -1,62 +0,0 @@ -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 -} diff --git a/vender/github.com/astaxie/beego/grace/server.go b/vender/github.com/astaxie/beego/grace/server.go deleted file mode 100755 index 513a52a..0000000 --- a/vender/github.com/astaxie/beego/grace/server.go +++ /dev/null @@ -1,363 +0,0 @@ -package grace - -import ( - "crypto/tls" - "crypto/x509" - "fmt" - "io/ioutil" - "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.Signal(syscall.SIGTERM) - 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.Signal(syscall.SIGTERM) - if err != nil { - return err - } - } - log.Println(os.Getpid(), srv.Addr) - return srv.Serve() -} - -// ListenAndServeMutualTLS listens on the TCP network address srv.Addr and then calls -// Serve to handle requests on incoming mutual TLS connections. -func (srv *Server) ListenAndServeMutualTLS(certFile, keyFile, trustFile 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 - } - srv.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert - pool := x509.NewCertPool() - data, err := ioutil.ReadFile(trustFile) - if err != nil { - log.Println(err) - return err - } - pool.AppendCertsFromPEM(data) - srv.TLSConfig.ClientCAs = pool - log.Println("Mutual HTTPS") - 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 -} diff --git a/vender/github.com/astaxie/beego/hooks.go b/vender/github.com/astaxie/beego/hooks.go deleted file mode 100755 index e26ccae..0000000 --- a/vender/github.com/astaxie/beego/hooks.go +++ /dev/null @@ -1,103 +0,0 @@ -package beego - -import ( - "encoding/json" - "mime" - "net/http" - "path/filepath" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" - "github.com/cnlh/nps/vender/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 -} diff --git a/vender/github.com/astaxie/beego/httplib/README.md b/vender/github.com/astaxie/beego/httplib/README.md deleted file mode 100755 index a4fb8ee..0000000 --- a/vender/github.com/astaxie/beego/httplib/README.md +++ /dev/null @@ -1,97 +0,0 @@ -# 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/cnlh/nps/vender/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/cnlh/nps/vender/github.com/astaxie/beego/httplib](https://godoc.org/github.com/cnlh/nps/vender/github.com/astaxie/beego/httplib) diff --git a/vender/github.com/astaxie/beego/httplib/httplib.go b/vender/github.com/astaxie/beego/httplib/httplib.go deleted file mode 100755 index a611a6d..0000000 --- a/vender/github.com/astaxie/beego/httplib/httplib.go +++ /dev/null @@ -1,624 +0,0 @@ -// 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/cnlh/nps/vender/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" - "gopkg.in/yaml.v2" - "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 -} - -// XMLBody adds request raw body encoding by XML. -func (b *BeegoHTTPRequest) XMLBody(obj interface{}) (*BeegoHTTPRequest, error) { - if b.req.Body == nil && obj != nil { - byts, err := xml.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/xml") - } - return b, nil -} - -// YAMLBody adds request raw body encoding by YAML. -func (b *BeegoHTTPRequest) YAMLBody(obj interface{}) (*BeegoHTTPRequest, error) { - if b.req.Body == nil && obj != nil { - byts, err := yaml.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/x+yaml") - } - return b, nil -} - -// 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) - urlParsed, err := url.Parse(b.url) - if err != nil { - return nil, err - } - - b.req.URL = urlParsed - - 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: 100, - } - } 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) -} - -// ToYAML returns the map that marshals from the body bytes as yaml in response . -// it calls Response inner. -func (b *BeegoHTTPRequest) ToYAML(v interface{}) error { - data, err := b.Bytes() - if err != nil { - return err - } - return yaml.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 - } -} diff --git a/vender/github.com/astaxie/beego/httplib/httplib_test.go b/vender/github.com/astaxie/beego/httplib/httplib_test.go deleted file mode 100755 index 32d3e7f..0000000 --- a/vender/github.com/astaxie/beego/httplib/httplib_test.go +++ /dev/null @@ -1,226 +0,0 @@ -// 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) -} diff --git a/vender/github.com/astaxie/beego/log.go b/vender/github.com/astaxie/beego/log.go deleted file mode 100755 index d0bd670..0000000 --- a/vender/github.com/astaxie/beego/log.go +++ /dev/null @@ -1,111 +0,0 @@ -// 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/cnlh/nps/vender/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) -} diff --git a/vender/github.com/astaxie/beego/logs/accesslog.go b/vender/github.com/astaxie/beego/logs/accesslog.go deleted file mode 100755 index 3ff9e20..0000000 --- a/vender/github.com/astaxie/beego/logs/accesslog.go +++ /dev/null @@ -1,83 +0,0 @@ -// 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" - "strings" - "encoding/json" - "fmt" - "time" -) - -const ( - apacheFormatPattern = "%s - - [%s] \"%s %d %d\" %f %s %s" - apacheFormat = "APACHE_FORMAT" - jsonFormat = "JSON_FORMAT" -) - -// AccessLogRecord struct for holding access log data. -type AccessLogRecord struct { - RemoteAddr string `json:"remote_addr"` - RequestTime time.Time `json:"request_time"` - RequestMethod string `json:"request_method"` - Request string `json:"request"` - ServerProtocol string `json:"server_protocol"` - Host string `json:"host"` - Status int `json:"status"` - BodyBytesSent int64 `json:"body_bytes_sent"` - ElapsedTime time.Duration `json:"elapsed_time"` - HTTPReferrer string `json:"http_referrer"` - HTTPUserAgent string `json:"http_user_agent"` - RemoteUser string `json:"remote_user"` -} - -func (r *AccessLogRecord) json() ([]byte, error) { - buffer := &bytes.Buffer{} - encoder := json.NewEncoder(buffer) - disableEscapeHTML(encoder) - - err := encoder.Encode(r) - return buffer.Bytes(), err -} - -func disableEscapeHTML(i interface{}) { - if e, ok := i.(interface { - SetEscapeHTML(bool) - }); ok { - e.SetEscapeHTML(false) - } -} - -// AccessLog - Format and print access log. -func AccessLog(r *AccessLogRecord, format string) { - var msg string - switch format { - case apacheFormat: - timeFormatted := r.RequestTime.Format("02/Jan/2006 03:04:05") - msg = fmt.Sprintf(apacheFormatPattern, r.RemoteAddr, timeFormatted, r.Request, r.Status, r.BodyBytesSent, - r.ElapsedTime.Seconds(), r.HTTPReferrer, r.HTTPUserAgent) - case jsonFormat: - fallthrough - default: - jsonData, err := r.json() - if err != nil { - msg = fmt.Sprintf(`{"Error": "%s"}`, err) - } else { - msg = string(jsonData) - } - } - beeLogger.writeMsg(levelLoggerImpl, strings.TrimSpace(msg)) -} diff --git a/vender/github.com/astaxie/beego/logs/alils/alils.go b/vender/github.com/astaxie/beego/logs/alils/alils.go deleted file mode 100755 index f167a91..0000000 --- a/vender/github.com/astaxie/beego/logs/alils/alils.go +++ /dev/null @@ -1,186 +0,0 @@ -package alils - -import ( - "encoding/json" - "strings" - "sync" - "time" - - "github.com/cnlh/nps/vender/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) -} diff --git a/vender/github.com/astaxie/beego/logs/alils/config.go b/vender/github.com/astaxie/beego/logs/alils/config.go deleted file mode 100755 index e8c2444..0000000 --- a/vender/github.com/astaxie/beego/logs/alils/config.go +++ /dev/null @@ -1,13 +0,0 @@ -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" -) diff --git a/vender/github.com/astaxie/beego/logs/alils/log.pb.go b/vender/github.com/astaxie/beego/logs/alils/log.pb.go deleted file mode 100755 index 601b0d7..0000000 --- a/vender/github.com/astaxie/beego/logs/alils/log.pb.go +++ /dev/null @@ -1,1038 +0,0 @@ -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") -} diff --git a/vender/github.com/astaxie/beego/logs/alils/log_config.go b/vender/github.com/astaxie/beego/logs/alils/log_config.go deleted file mode 100755 index e8564ef..0000000 --- a/vender/github.com/astaxie/beego/logs/alils/log_config.go +++ /dev/null @@ -1,42 +0,0 @@ -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 -} diff --git a/vender/github.com/astaxie/beego/logs/alils/log_project.go b/vender/github.com/astaxie/beego/logs/alils/log_project.go deleted file mode 100755 index 59db8cb..0000000 --- a/vender/github.com/astaxie/beego/logs/alils/log_project.go +++ /dev/null @@ -1,819 +0,0 @@ -/* -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 -} diff --git a/vender/github.com/astaxie/beego/logs/alils/log_store.go b/vender/github.com/astaxie/beego/logs/alils/log_store.go deleted file mode 100755 index fa50273..0000000 --- a/vender/github.com/astaxie/beego/logs/alils/log_store.go +++ /dev/null @@ -1,271 +0,0 @@ -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 -} diff --git a/vender/github.com/astaxie/beego/logs/alils/machine_group.go b/vender/github.com/astaxie/beego/logs/alils/machine_group.go deleted file mode 100755 index b6c69a1..0000000 --- a/vender/github.com/astaxie/beego/logs/alils/machine_group.go +++ /dev/null @@ -1,91 +0,0 @@ -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 -} diff --git a/vender/github.com/astaxie/beego/logs/alils/request.go b/vender/github.com/astaxie/beego/logs/alils/request.go deleted file mode 100755 index 50d9c43..0000000 --- a/vender/github.com/astaxie/beego/logs/alils/request.go +++ /dev/null @@ -1,62 +0,0 @@ -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 :" - 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 -} diff --git a/vender/github.com/astaxie/beego/logs/alils/signature.go b/vender/github.com/astaxie/beego/logs/alils/signature.go deleted file mode 100755 index 2d61130..0000000 --- a/vender/github.com/astaxie/beego/logs/alils/signature.go +++ /dev/null @@ -1,111 +0,0 @@ -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 -} diff --git a/vender/github.com/astaxie/beego/logs/color.go b/vender/github.com/astaxie/beego/logs/color.go deleted file mode 100755 index 41d2363..0000000 --- a/vender/github.com/astaxie/beego/logs/color.go +++ /dev/null @@ -1,28 +0,0 @@ -// 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) -} diff --git a/vender/github.com/astaxie/beego/logs/color_windows.go b/vender/github.com/astaxie/beego/logs/color_windows.go deleted file mode 100755 index 4e28f18..0000000 --- a/vender/github.com/astaxie/beego/logs/color_windows.go +++ /dev/null @@ -1,428 +0,0 @@ -// 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 -} diff --git a/vender/github.com/astaxie/beego/logs/color_windows_test.go b/vender/github.com/astaxie/beego/logs/color_windows_test.go deleted file mode 100755 index 5074841..0000000 --- a/vender/github.com/astaxie/beego/logs/color_windows_test.go +++ /dev/null @@ -1,294 +0,0 @@ -// 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) - } -} diff --git a/vender/github.com/astaxie/beego/logs/conn.go b/vender/github.com/astaxie/beego/logs/conn.go deleted file mode 100755 index 6d5bf6b..0000000 --- a/vender/github.com/astaxie/beego/logs/conn.go +++ /dev/null @@ -1,117 +0,0 @@ -// 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) -} diff --git a/vender/github.com/astaxie/beego/logs/conn_test.go b/vender/github.com/astaxie/beego/logs/conn_test.go deleted file mode 100755 index 747fb89..0000000 --- a/vender/github.com/astaxie/beego/logs/conn_test.go +++ /dev/null @@ -1,25 +0,0 @@ -// 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") -} diff --git a/vender/github.com/astaxie/beego/logs/console.go b/vender/github.com/astaxie/beego/logs/console.go deleted file mode 100755 index e75f2a1..0000000 --- a/vender/github.com/astaxie/beego/logs/console.go +++ /dev/null @@ -1,101 +0,0 @@ -// 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) -} diff --git a/vender/github.com/astaxie/beego/logs/console_test.go b/vender/github.com/astaxie/beego/logs/console_test.go deleted file mode 100755 index 04f2bd7..0000000 --- a/vender/github.com/astaxie/beego/logs/console_test.go +++ /dev/null @@ -1,51 +0,0 @@ -// 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) -} diff --git a/vender/github.com/astaxie/beego/logs/es/es.go b/vender/github.com/astaxie/beego/logs/es/es.go deleted file mode 100755 index 5c24a06..0000000 --- a/vender/github.com/astaxie/beego/logs/es/es.go +++ /dev/null @@ -1,80 +0,0 @@ -package es - -import ( - "encoding/json" - "errors" - "fmt" - "net" - "net/url" - "time" - - "github.com/belogik/goes" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" -) - -// 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) -} diff --git a/vender/github.com/astaxie/beego/logs/file.go b/vender/github.com/astaxie/beego/logs/file.go deleted file mode 100755 index 588f786..0000000 --- a/vender/github.com/astaxie/beego/logs/file.go +++ /dev/null @@ -1,405 +0,0 @@ -// 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" - "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 - - MaxFiles int `json:"maxfiles"` - MaxFilesCurFiles 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 hourly - Hourly bool `json:"hourly"` - MaxHours int64 `json:"maxhours"` - hourlyOpenDate int - hourlyOpenTime time.Time - - Rotate bool `json:"rotate"` - - Level int `json:"level"` - - Perm string `json:"perm"` - - RotatePerm string `json:"rotateperm"` - - 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, - Hourly: false, - MaxHours: 168, - Rotate: true, - RotatePerm: "0440", - Level: LevelTrace, - Perm: "0660", - MaxLines: 10000000, - MaxFiles: 999, - MaxSize: 1 << 28, - } - 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) needRotateDaily(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) -} - -func (w *fileLogWriter) needRotateHourly(size int, hour int) bool { - return (w.MaxLines > 0 && w.maxLinesCurLines >= w.MaxLines) || - (w.MaxSize > 0 && w.maxSizeCurSize >= w.MaxSize) || - (w.Hourly && hour != w.hourlyOpenDate) - -} - -// WriteMsg write logger message into file. -func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error { - if level > w.Level { - return nil - } - hd, d, h := formatTimeHeader(when) - msg = string(hd) + msg + "\n" - if w.Rotate { - w.RLock() - if w.needRotateHourly(len(msg), h) { - w.RUnlock() - w.Lock() - if w.needRotateHourly(len(msg), h) { - if err := w.doRotate(when); err != nil { - fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err) - } - } - w.Unlock() - } else if w.needRotateDaily(len(msg), d) { - w.RUnlock() - w.Lock() - if w.needRotateDaily(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 - } - - filepath := path.Dir(w.Filename) - os.MkdirAll(filepath, os.FileMode(perm)) - - 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.hourlyOpenTime = time.Now() - w.hourlyOpenDate = w.hourlyOpenTime.Hour() - w.maxLinesCurLines = 0 - if w.Hourly { - go w.hourlyRotate(w.hourlyOpenTime) - } else if w.Daily { - go w.dailyRotate(w.dailyOpenTime) - } - if fInfo.Size() > 0 && w.MaxLines > 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.needRotateDaily(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) hourlyRotate(openTime time.Time) { - y, m, d := openTime.Add(1 * time.Hour).Date() - h, _, _ := openTime.Add(1 * time.Hour).Clock() - nextHour := time.Date(y, m, d, h, 0, 0, 0, openTime.Location()) - tm := time.NewTimer(time.Duration(nextHour.UnixNano() - openTime.UnixNano() + 100)) - <-tm.C - w.Lock() - if w.needRotateHourly(0, time.Now().Hour()) { - 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 := w.MaxFilesCurFiles + 1 - fName := "" - format := "" - var openTime time.Time - rotatePerm, err := strconv.ParseInt(w.RotatePerm, 8, 64) - if err != nil { - return err - } - - _, 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.Hourly { - format = "2006010215" - openTime = w.hourlyOpenTime - } else if w.Daily { - format = "2006-01-02" - openTime = w.dailyOpenTime - } - - // only when one of them be setted, then the file would be splited - if w.MaxLines > 0 || w.MaxSize > 0 { - for ; err == nil && num <= w.MaxFiles; num++ { - fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", logTime.Format(format), num, w.suffix) - _, err = os.Lstat(fName) - } - } else { - fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", openTime.Format(format), num, w.suffix) - _, err = os.Lstat(fName) - w.MaxFilesCurFiles = num - } - - // 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(rotatePerm)) - -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 w.Hourly { - if !info.IsDir() && info.ModTime().Add(1 * time.Hour * time.Duration(w.MaxHours)).Before(time.Now()) { - if strings.HasPrefix(filepath.Base(path), filepath.Base(w.fileNameOnly)) && - strings.HasSuffix(filepath.Base(path), w.suffix) { - os.Remove(path) - } - } - } else if w.Daily { - 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) -} diff --git a/vender/github.com/astaxie/beego/logs/file_test.go b/vender/github.com/astaxie/beego/logs/file_test.go deleted file mode 100755 index e7c2ca9..0000000 --- a/vender/github.com/astaxie/beego/logs/file_test.go +++ /dev/null @@ -1,420 +0,0 @@ -// 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 TestFileDailyRotate_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 TestFileDailyRotate_02(t *testing.T) { - fn1 := "rotate_day.log" - fn2 := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".001.log" - testFileRotate(t, fn1, fn2, true, false) -} - -func TestFileDailyRotate_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, true, false) - os.Remove(fn) -} - -func TestFileDailyRotate_04(t *testing.T) { - fn1 := "rotate_day.log" - fn2 := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".001.log" - testFileDailyRotate(t, fn1, fn2) -} - -func TestFileDailyRotate_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 TestFileDailyRotate_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 TestFileHourlyRotate_01(t *testing.T) { - log := NewLogger(10000) - log.SetLogger("file", `{"filename":"test3.log","hourly":true,"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("2006010215"), 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 TestFileHourlyRotate_02(t *testing.T) { - fn1 := "rotate_hour.log" - fn2 := "rotate_hour." + time.Now().Add(-1*time.Hour).Format("2006010215") + ".001.log" - testFileRotate(t, fn1, fn2, false, true) -} - -func TestFileHourlyRotate_03(t *testing.T) { - fn1 := "rotate_hour.log" - fn := "rotate_hour." + time.Now().Add(-1*time.Hour).Format("2006010215") + ".log" - os.Create(fn) - fn2 := "rotate_hour." + time.Now().Add(-1*time.Hour).Format("2006010215") + ".001.log" - testFileRotate(t, fn1, fn2, false, true) - os.Remove(fn) -} - -func TestFileHourlyRotate_04(t *testing.T) { - fn1 := "rotate_hour.log" - fn2 := "rotate_hour." + time.Now().Add(-1*time.Hour).Format("2006010215") + ".001.log" - testFileHourlyRotate(t, fn1, fn2) -} - -func TestFileHourlyRotate_05(t *testing.T) { - fn1 := "rotate_hour.log" - fn := "rotate_hour." + time.Now().Add(-1*time.Hour).Format("2006010215") + ".log" - os.Create(fn) - fn2 := "rotate_hour." + time.Now().Add(-1*time.Hour).Format("2006010215") + ".001.log" - testFileHourlyRotate(t, fn1, fn2) - os.Remove(fn) -} - -func TestFileHourlyRotate_06(t *testing.T) { //test file mode - log := NewLogger(10000) - log.SetLogger("file", `{"filename":"test3.log", "hourly":true, "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("2006010215"), 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, daily, hourly bool) { - fw := &fileLogWriter{ - Daily: daily, - MaxDays: 7, - Hourly: hourly, - MaxHours: 168, - Rotate: true, - Level: LevelTrace, - Perm: "0660", - RotatePerm: "0440", - } - - if daily { - fw.Init(fmt.Sprintf(`{"filename":"%v","maxdays":1}`, fn1)) - fw.dailyOpenTime = time.Now().Add(-24 * time.Hour) - fw.dailyOpenDate = fw.dailyOpenTime.Day() - } - - if hourly { - fw.Init(fmt.Sprintf(`{"filename":"%v","maxhours":1}`, fn1)) - fw.hourlyOpenTime = time.Now().Add(-1 * time.Hour) - fw.hourlyOpenDate = fw.hourlyOpenTime.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.Log(err) - 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", - RotatePerm: "0440", - } - 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 testFileHourlyRotate(t *testing.T, fn1, fn2 string) { - fw := &fileLogWriter{ - Hourly: true, - MaxHours: 168, - Rotate: true, - Level: LevelTrace, - Perm: "0660", - RotatePerm: "0440", - } - fw.Init(fmt.Sprintf(`{"filename":"%v","maxhours":1}`, fn1)) - fw.hourlyOpenTime = time.Now().Add(-1 * time.Hour) - fw.hourlyOpenDate = fw.hourlyOpenTime.Hour() - hour, _ := time.ParseInLocation("2006010215", time.Now().Format("2006010215"), fw.hourlyOpenTime.Location()) - hour = hour.Add(-1 * time.Second) - fw.hourlyRotate(hour) - 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") -} diff --git a/vender/github.com/astaxie/beego/logs/jianliao.go b/vender/github.com/astaxie/beego/logs/jianliao.go deleted file mode 100755 index 88ba0f9..0000000 --- a/vender/github.com/astaxie/beego/logs/jianliao.go +++ /dev/null @@ -1,72 +0,0 @@ -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) -} diff --git a/vender/github.com/astaxie/beego/logs/log.go b/vender/github.com/astaxie/beego/logs/log.go deleted file mode 100755 index 55263dc..0000000 --- a/vender/github.com/astaxie/beego/logs/log.go +++ /dev/null @@ -1,665 +0,0 @@ -// 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/cnlh/nps/vender/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 - prefix string - 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...) - } - - msg = bl.prefix + " " + msg - - 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 -} - -// GetLevel Get Current log message level. -func (bl *BeeLogger) GetLevel() int { - return bl.level -} - -// 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 -} - -// set prefix -func (bl *BeeLogger) SetPrefix(s string) { - bl.prefix = s -} - -// 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) -} - -// SetPrefix sets the prefix -func SetPrefix(s string) { - beeLogger.SetPrefix(s) -} - -// 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...) -} diff --git a/vender/github.com/astaxie/beego/logs/logger.go b/vender/github.com/astaxie/beego/logs/logger.go deleted file mode 100755 index 428d3aa..0000000 --- a/vender/github.com/astaxie/beego/logs/logger.go +++ /dev/null @@ -1,208 +0,0 @@ -// 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` - ns1 = `0123456789` -) - -func formatTimeHeader(when time.Time) ([]byte, int, int) { - y, mo, d := when.Date() - h, mi, s := when.Clock() - ns := when.Nanosecond() / 1000000 - //len("2006/01/02 15:04:05.123 ")==24 - var buf [24]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] = '.' - buf[20] = ns1[ns/100] - buf[21] = ns1[ns%100/10] - buf[22] = ns1[ns%10] - - buf[23] = ' ' - - return buf[0:], d, h -} - -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) -} diff --git a/vender/github.com/astaxie/beego/logs/logger_test.go b/vender/github.com/astaxie/beego/logs/logger_test.go deleted file mode 100755 index 78c6773..0000000 --- a/vender/github.com/astaxie/beego/logs/logger_test.go +++ /dev/null @@ -1,75 +0,0 @@ -// 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.000 ") != 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.000 ") != 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) - } -} diff --git a/vender/github.com/astaxie/beego/logs/multifile.go b/vender/github.com/astaxie/beego/logs/multifile.go deleted file mode 100755 index 9016827..0000000 --- a/vender/github.com/astaxie/beego/logs/multifile.go +++ /dev/null @@ -1,119 +0,0 @@ -// 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) - err := writer.Init(string(bs)) - if err != nil { - return err - } - 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) -} diff --git a/vender/github.com/astaxie/beego/logs/multifile_test.go b/vender/github.com/astaxie/beego/logs/multifile_test.go deleted file mode 100755 index 57b9609..0000000 --- a/vender/github.com/astaxie/beego/logs/multifile_test.go +++ /dev/null @@ -1,78 +0,0 @@ -// 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) - } - -} diff --git a/vender/github.com/astaxie/beego/logs/slack.go b/vender/github.com/astaxie/beego/logs/slack.go deleted file mode 100755 index 1cd2e5a..0000000 --- a/vender/github.com/astaxie/beego/logs/slack.go +++ /dev/null @@ -1,60 +0,0 @@ -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) -} diff --git a/vender/github.com/astaxie/beego/logs/smtp.go b/vender/github.com/astaxie/beego/logs/smtp.go deleted file mode 100755 index 6208d7b..0000000 --- a/vender/github.com/astaxie/beego/logs/smtp.go +++ /dev/null @@ -1,149 +0,0 @@ -// 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":"example@gmail.com", -// "password:"password", -// "host":"smtp.gmail.com:465", -// "subject":"email title", -// "fromAddress":"from@example.com", -// "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) -} diff --git a/vender/github.com/astaxie/beego/logs/smtp_test.go b/vender/github.com/astaxie/beego/logs/smtp_test.go deleted file mode 100755 index 28e762d..0000000 --- a/vender/github.com/astaxie/beego/logs/smtp_test.go +++ /dev/null @@ -1,27 +0,0 @@ -// 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":"beegotest@gmail.com","password":"xxxxxxxx","host":"smtp.gmail.com:587","sendTos":["xiemengjun@gmail.com"]}`) - log.Critical("sendmail critical") - time.Sleep(time.Second * 30) -} diff --git a/vender/github.com/astaxie/beego/migration/ddl.go b/vender/github.com/astaxie/beego/migration/ddl.go deleted file mode 100755 index c9c1c19..0000000 --- a/vender/github.com/astaxie/beego/migration/ddl.go +++ /dev/null @@ -1,395 +0,0 @@ -// 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 - -import ( - "fmt" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego" -) - -// Index struct defines the structure of Index Columns -type Index struct { - Name string -} - -// Unique struct defines a single unique key combination -type Unique struct { - Definition string - Columns []*Column -} - -//Column struct defines a single column of a table -type Column struct { - Name string - Inc string - Null string - Default string - Unsign string - DataType string - remove bool - Modify bool -} - -// Foreign struct defines a single foreign relationship -type Foreign struct { - ForeignTable string - ForeignColumn string - OnDelete string - OnUpdate string - Column -} - -// RenameColumn struct allows renaming of columns -type RenameColumn struct { - OldName string - OldNull string - OldDefault string - OldUnsign string - OldDataType string - NewName string - Column -} - -// CreateTable creates the table on system -func (m *Migration) CreateTable(tablename, engine, charset string, p ...func()) { - m.TableName = tablename - m.Engine = engine - m.Charset = charset - m.ModifyType = "create" -} - -// AlterTable set the ModifyType to alter -func (m *Migration) AlterTable(tablename string) { - m.TableName = tablename - m.ModifyType = "alter" -} - -// NewCol creates a new standard column and attaches it to m struct -func (m *Migration) NewCol(name string) *Column { - col := &Column{Name: name} - m.AddColumns(col) - return col -} - -//PriCol creates a new primary column and attaches it to m struct -func (m *Migration) PriCol(name string) *Column { - col := &Column{Name: name} - m.AddColumns(col) - m.AddPrimary(col) - return col -} - -//UniCol creates / appends columns to specified unique key and attaches it to m struct -func (m *Migration) UniCol(uni, name string) *Column { - col := &Column{Name: name} - m.AddColumns(col) - - uniqueOriginal := &Unique{} - - for _, unique := range m.Uniques { - if unique.Definition == uni { - unique.AddColumnsToUnique(col) - uniqueOriginal = unique - } - } - if uniqueOriginal.Definition == "" { - unique := &Unique{Definition: uni} - unique.AddColumnsToUnique(col) - m.AddUnique(unique) - } - - return col -} - -//ForeignCol creates a new foreign column and returns the instance of column -func (m *Migration) ForeignCol(colname, foreigncol, foreigntable string) (foreign *Foreign) { - - foreign = &Foreign{ForeignColumn: foreigncol, ForeignTable: foreigntable} - foreign.Name = colname - m.AddForeign(foreign) - return foreign -} - -//SetOnDelete sets the on delete of foreign -func (foreign *Foreign) SetOnDelete(del string) *Foreign { - foreign.OnDelete = "ON DELETE" + del - return foreign -} - -//SetOnUpdate sets the on update of foreign -func (foreign *Foreign) SetOnUpdate(update string) *Foreign { - foreign.OnUpdate = "ON UPDATE" + update - return foreign -} - -//Remove marks the columns to be removed. -//it allows reverse m to create the column. -func (c *Column) Remove() { - c.remove = true -} - -//SetAuto enables auto_increment of column (can be used once) -func (c *Column) SetAuto(inc bool) *Column { - if inc { - c.Inc = "auto_increment" - } - return c -} - -//SetNullable sets the column to be null -func (c *Column) SetNullable(null bool) *Column { - if null { - c.Null = "" - - } else { - c.Null = "NOT NULL" - } - return c -} - -//SetDefault sets the default value, prepend with "DEFAULT " -func (c *Column) SetDefault(def string) *Column { - c.Default = "DEFAULT " + def - return c -} - -//SetUnsigned sets the column to be unsigned int -func (c *Column) SetUnsigned(unsign bool) *Column { - if unsign { - c.Unsign = "UNSIGNED" - } - return c -} - -//SetDataType sets the dataType of the column -func (c *Column) SetDataType(dataType string) *Column { - c.DataType = dataType - return c -} - -//SetOldNullable allows reverting to previous nullable on reverse ms -func (c *RenameColumn) SetOldNullable(null bool) *RenameColumn { - if null { - c.OldNull = "" - - } else { - c.OldNull = "NOT NULL" - } - return c -} - -//SetOldDefault allows reverting to previous default on reverse ms -func (c *RenameColumn) SetOldDefault(def string) *RenameColumn { - c.OldDefault = def - return c -} - -//SetOldUnsigned allows reverting to previous unsgined on reverse ms -func (c *RenameColumn) SetOldUnsigned(unsign bool) *RenameColumn { - if unsign { - c.OldUnsign = "UNSIGNED" - } - return c -} - -//SetOldDataType allows reverting to previous datatype on reverse ms -func (c *RenameColumn) SetOldDataType(dataType string) *RenameColumn { - c.OldDataType = dataType - return c -} - -//SetPrimary adds the columns to the primary key (can only be used any number of times in only one m) -func (c *Column) SetPrimary(m *Migration) *Column { - m.Primary = append(m.Primary, c) - return c -} - -//AddColumnsToUnique adds the columns to Unique Struct -func (unique *Unique) AddColumnsToUnique(columns ...*Column) *Unique { - - unique.Columns = append(unique.Columns, columns...) - - return unique -} - -//AddColumns adds columns to m struct -func (m *Migration) AddColumns(columns ...*Column) *Migration { - - m.Columns = append(m.Columns, columns...) - - return m -} - -//AddPrimary adds the column to primary in m struct -func (m *Migration) AddPrimary(primary *Column) *Migration { - m.Primary = append(m.Primary, primary) - return m -} - -//AddUnique adds the column to unique in m struct -func (m *Migration) AddUnique(unique *Unique) *Migration { - m.Uniques = append(m.Uniques, unique) - return m -} - -//AddForeign adds the column to foreign in m struct -func (m *Migration) AddForeign(foreign *Foreign) *Migration { - m.Foreigns = append(m.Foreigns, foreign) - return m -} - -//AddIndex adds the column to index in m struct -func (m *Migration) AddIndex(index *Index) *Migration { - m.Indexes = append(m.Indexes, index) - return m -} - -//RenameColumn allows renaming of columns -func (m *Migration) RenameColumn(from, to string) *RenameColumn { - rename := &RenameColumn{OldName: from, NewName: to} - m.Renames = append(m.Renames, rename) - return rename -} - -//GetSQL returns the generated sql depending on ModifyType -func (m *Migration) GetSQL() (sql string) { - sql = "" - switch m.ModifyType { - case "create": - { - sql += fmt.Sprintf("CREATE TABLE `%s` (", m.TableName) - for index, column := range m.Columns { - sql += fmt.Sprintf("\n `%s` %s %s %s %s %s", column.Name, column.DataType, column.Unsign, column.Null, column.Inc, column.Default) - if len(m.Columns) > index+1 { - sql += "," - } - } - - if len(m.Primary) > 0 { - sql += fmt.Sprintf(",\n PRIMARY KEY( ") - } - for index, column := range m.Primary { - sql += fmt.Sprintf(" `%s`", column.Name) - if len(m.Primary) > index+1 { - sql += "," - } - - } - if len(m.Primary) > 0 { - sql += fmt.Sprintf(")") - } - - for _, unique := range m.Uniques { - sql += fmt.Sprintf(",\n UNIQUE KEY `%s`( ", unique.Definition) - for index, column := range unique.Columns { - sql += fmt.Sprintf(" `%s`", column.Name) - if len(unique.Columns) > index+1 { - sql += "," - } - } - sql += fmt.Sprintf(")") - } - for _, foreign := range m.Foreigns { - sql += fmt.Sprintf(",\n `%s` %s %s %s %s %s", foreign.Name, foreign.DataType, foreign.Unsign, foreign.Null, foreign.Inc, foreign.Default) - sql += fmt.Sprintf(",\n KEY `%s_%s_foreign`(`%s`),", m.TableName, foreign.Column.Name, foreign.Column.Name) - sql += fmt.Sprintf("\n CONSTRAINT `%s_%s_foreign` FOREIGN KEY (`%s`) REFERENCES `%s` (`%s`) %s %s", m.TableName, foreign.Column.Name, foreign.Column.Name, foreign.ForeignTable, foreign.ForeignColumn, foreign.OnDelete, foreign.OnUpdate) - - } - sql += fmt.Sprintf(")ENGINE=%s DEFAULT CHARSET=%s;", m.Engine, m.Charset) - break - } - case "alter": - { - sql += fmt.Sprintf("ALTER TABLE `%s` ", m.TableName) - for index, column := range m.Columns { - if !column.remove { - beego.BeeLogger.Info("col") - sql += fmt.Sprintf("\n ADD `%s` %s %s %s %s %s", column.Name, column.DataType, column.Unsign, column.Null, column.Inc, column.Default) - } else { - sql += fmt.Sprintf("\n DROP COLUMN `%s`", column.Name) - } - - if len(m.Columns) > index+1 { - sql += "," - } - } - for index, column := range m.Renames { - sql += fmt.Sprintf("CHANGE COLUMN `%s` `%s` %s %s %s %s %s", column.OldName, column.NewName, column.DataType, column.Unsign, column.Null, column.Inc, column.Default) - if len(m.Renames) > index+1 { - sql += "," - } - } - - for index, foreign := range m.Foreigns { - sql += fmt.Sprintf("ADD `%s` %s %s %s %s %s", foreign.Name, foreign.DataType, foreign.Unsign, foreign.Null, foreign.Inc, foreign.Default) - sql += fmt.Sprintf(",\n ADD KEY `%s_%s_foreign`(`%s`)", m.TableName, foreign.Column.Name, foreign.Column.Name) - sql += fmt.Sprintf(",\n ADD CONSTRAINT `%s_%s_foreign` FOREIGN KEY (`%s`) REFERENCES `%s` (`%s`) %s %s", m.TableName, foreign.Column.Name, foreign.Column.Name, foreign.ForeignTable, foreign.ForeignColumn, foreign.OnDelete, foreign.OnUpdate) - if len(m.Foreigns) > index+1 { - sql += "," - } - } - sql += ";" - - break - } - case "reverse": - { - - sql += fmt.Sprintf("ALTER TABLE `%s`", m.TableName) - for index, column := range m.Columns { - if column.remove { - sql += fmt.Sprintf("\n ADD `%s` %s %s %s %s %s", column.Name, column.DataType, column.Unsign, column.Null, column.Inc, column.Default) - } else { - sql += fmt.Sprintf("\n DROP COLUMN `%s`", column.Name) - } - if len(m.Columns) > index+1 { - sql += "," - } - } - - if len(m.Primary) > 0 { - sql += fmt.Sprintf("\n DROP PRIMARY KEY,") - } - - for index, unique := range m.Uniques { - sql += fmt.Sprintf("\n DROP KEY `%s`", unique.Definition) - if len(m.Uniques) > index+1 { - sql += "," - } - - } - for index, column := range m.Renames { - sql += fmt.Sprintf("\n CHANGE COLUMN `%s` `%s` %s %s %s %s", column.NewName, column.OldName, column.OldDataType, column.OldUnsign, column.OldNull, column.OldDefault) - if len(m.Renames) > index+1 { - sql += "," - } - } - - for _, foreign := range m.Foreigns { - sql += fmt.Sprintf("\n DROP KEY `%s_%s_foreign`", m.TableName, foreign.Column.Name) - sql += fmt.Sprintf(",\n DROP FOREIGN KEY `%s_%s_foreign`", m.TableName, foreign.Column.Name) - sql += fmt.Sprintf(",\n DROP COLUMN `%s`", foreign.Name) - } - sql += ";" - } - case "delete": - { - sql += fmt.Sprintf("DROP TABLE IF EXISTS `%s`;", m.TableName) - } - } - - return -} diff --git a/vender/github.com/astaxie/beego/migration/doc.go b/vender/github.com/astaxie/beego/migration/doc.go deleted file mode 100755 index 0c6564d..0000000 --- a/vender/github.com/astaxie/beego/migration/doc.go +++ /dev/null @@ -1,32 +0,0 @@ -// Package migration enables you to generate migrations back and forth. It generates both migrations. -// -// //Creates a table -// m.CreateTable("tablename","InnoDB","utf8"); -// -// //Alter a table -// m.AlterTable("tablename") -// -// Standard Column Methods -// * SetDataType -// * SetNullable -// * SetDefault -// * SetUnsigned (use only on integer types unless produces error) -// -// //Sets a primary column, multiple calls allowed, standard column methods available -// m.PriCol("id").SetAuto(true).SetNullable(false).SetDataType("INT(10)").SetUnsigned(true) -// -// //UniCol Can be used multiple times, allows standard Column methods. Use same "index" string to add to same index -// m.UniCol("index","column") -// -// //Standard Column Initialisation, can call .Remove() after NewCol("") on alter to remove -// m.NewCol("name").SetDataType("VARCHAR(255) COLLATE utf8_unicode_ci").SetNullable(false) -// m.NewCol("value").SetDataType("DOUBLE(8,2)").SetNullable(false) -// -// //Rename Columns , only use with Alter table, doesn't works with Create, prefix standard column methods with "Old" to -// //create a true reversible migration eg: SetOldDataType("DOUBLE(12,3)") -// m.RenameColumn("from","to")... -// -// //Foreign Columns, single columns are only supported, SetOnDelete & SetOnUpdate are available, call appropriately. -// //Supports standard column methods, automatic reverse. -// m.ForeignCol("local_col","foreign_col","foreign_table") -package migration diff --git a/vender/github.com/astaxie/beego/migration/migration.go b/vender/github.com/astaxie/beego/migration/migration.go deleted file mode 100755 index 03052c3..0000000 --- a/vender/github.com/astaxie/beego/migration/migration.go +++ /dev/null @@ -1,312 +0,0 @@ -// 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/cnlh/nps/vender/github.com/astaxie/beego/logs" - "github.com/cnlh/nps/vender/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 -} - -//Migration defines the migrations by either SQL or DDL -type Migration struct { - sqls []string - Created string - TableName string - Engine string - Charset string - ModifyType string - Columns []*Column - Indexes []*Index - Primary []*Column - Uniques []*Unique - Foreigns []*Foreign - Renames []*RenameColumn - RemoveColumns []*Column - RemoveIndexes []*Index - RemoveUniques []*Unique - RemoveForeigns []*Foreign -} - -var ( - migrationMap map[string]Migrationer -) - -func init() { - migrationMap = make(map[string]Migrationer) -} - -// Up implement in the Inheritance struct for upgrade -func (m *Migration) Up() { - - switch m.ModifyType { - case "reverse": - m.ModifyType = "alter" - case "delete": - m.ModifyType = "create" - } - m.sqls = append(m.sqls, m.GetSQL()) -} - -// Down implement in the Inheritance struct for down -func (m *Migration) Down() { - - switch m.ModifyType { - case "alter": - m.ModifyType = "reverse" - case "create": - m.ModifyType = "delete" - } - m.sqls = append(m.sqls, m.GetSQL()) -} - -//Migrate adds the SQL to the execution list -func (m *Migration) Migrate(migrationType string) { - m.ModifyType = migrationType - m.sqls = append(m.sqls, m.GetSQL()) -} - -// 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 upgrade 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 -} diff --git a/vender/github.com/astaxie/beego/mime.go b/vender/github.com/astaxie/beego/mime.go deleted file mode 100755 index ca2878a..0000000 --- a/vender/github.com/astaxie/beego/mime.go +++ /dev/null @@ -1,556 +0,0 @@ -// 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 - -var mimemaps = map[string]string{ - ".3dm": "x-world/x-3dmf", - ".3dmf": "x-world/x-3dmf", - ".7z": "application/x-7z-compressed", - ".a": "application/octet-stream", - ".aab": "application/x-authorware-bin", - ".aam": "application/x-authorware-map", - ".aas": "application/x-authorware-seg", - ".abc": "text/vndabc", - ".ace": "application/x-ace-compressed", - ".acgi": "text/html", - ".afl": "video/animaflex", - ".ai": "application/postscript", - ".aif": "audio/aiff", - ".aifc": "audio/aiff", - ".aiff": "audio/aiff", - ".aim": "application/x-aim", - ".aip": "text/x-audiosoft-intra", - ".alz": "application/x-alz-compressed", - ".ani": "application/x-navi-animation", - ".aos": "application/x-nokia-9000-communicator-add-on-software", - ".aps": "application/mime", - ".apk": "application/vnd.android.package-archive", - ".arc": "application/x-arc-compressed", - ".arj": "application/arj", - ".art": "image/x-jg", - ".asf": "video/x-ms-asf", - ".asm": "text/x-asm", - ".asp": "text/asp", - ".asx": "application/x-mplayer2", - ".au": "audio/basic", - ".avi": "video/x-msvideo", - ".avs": "video/avs-video", - ".bcpio": "application/x-bcpio", - ".bin": "application/mac-binary", - ".bmp": "image/bmp", - ".boo": "application/book", - ".book": "application/book", - ".boz": "application/x-bzip2", - ".bsh": "application/x-bsh", - ".bz2": "application/x-bzip2", - ".bz": "application/x-bzip", - ".c++": "text/plain", - ".c": "text/x-c", - ".cab": "application/vnd.ms-cab-compressed", - ".cat": "application/vndms-pkiseccat", - ".cc": "text/x-c", - ".ccad": "application/clariscad", - ".cco": "application/x-cocoa", - ".cdf": "application/cdf", - ".cer": "application/pkix-cert", - ".cha": "application/x-chat", - ".chat": "application/x-chat", - ".chrt": "application/vnd.kde.kchart", - ".class": "application/java", - ".com": "text/plain", - ".conf": "text/plain", - ".cpio": "application/x-cpio", - ".cpp": "text/x-c", - ".cpt": "application/mac-compactpro", - ".crl": "application/pkcs-crl", - ".crt": "application/pkix-cert", - ".crx": "application/x-chrome-extension", - ".csh": "text/x-scriptcsh", - ".css": "text/css", - ".csv": "text/csv", - ".cxx": "text/plain", - ".dar": "application/x-dar", - ".dcr": "application/x-director", - ".deb": "application/x-debian-package", - ".deepv": "application/x-deepv", - ".def": "text/plain", - ".der": "application/x-x509-ca-cert", - ".dif": "video/x-dv", - ".dir": "application/x-director", - ".divx": "video/divx", - ".dl": "video/dl", - ".dmg": "application/x-apple-diskimage", - ".doc": "application/msword", - ".dot": "application/msword", - ".dp": "application/commonground", - ".drw": "application/drafting", - ".dump": "application/octet-stream", - ".dv": "video/x-dv", - ".dvi": "application/x-dvi", - ".dwf": "drawing/x-dwf=(old)", - ".dwg": "application/acad", - ".dxf": "application/dxf", - ".dxr": "application/x-director", - ".el": "text/x-scriptelisp", - ".elc": "application/x-bytecodeelisp=(compiled=elisp)", - ".eml": "message/rfc822", - ".env": "application/x-envoy", - ".eps": "application/postscript", - ".es": "application/x-esrehber", - ".etx": "text/x-setext", - ".evy": "application/envoy", - ".exe": "application/octet-stream", - ".f77": "text/x-fortran", - ".f90": "text/x-fortran", - ".f": "text/x-fortran", - ".fdf": "application/vndfdf", - ".fif": "application/fractals", - ".fli": "video/fli", - ".flo": "image/florian", - ".flv": "video/x-flv", - ".flx": "text/vndfmiflexstor", - ".fmf": "video/x-atomic3d-feature", - ".for": "text/x-fortran", - ".fpx": "image/vndfpx", - ".frl": "application/freeloader", - ".funk": "audio/make", - ".g3": "image/g3fax", - ".g": "text/plain", - ".gif": "image/gif", - ".gl": "video/gl", - ".gsd": "audio/x-gsm", - ".gsm": "audio/x-gsm", - ".gsp": "application/x-gsp", - ".gss": "application/x-gss", - ".gtar": "application/x-gtar", - ".gz": "application/x-compressed", - ".gzip": "application/x-gzip", - ".h": "text/x-h", - ".hdf": "application/x-hdf", - ".help": "application/x-helpfile", - ".hgl": "application/vndhp-hpgl", - ".hh": "text/x-h", - ".hlb": "text/x-script", - ".hlp": "application/hlp", - ".hpg": "application/vndhp-hpgl", - ".hpgl": "application/vndhp-hpgl", - ".hqx": "application/binhex", - ".hta": "application/hta", - ".htc": "text/x-component", - ".htm": "text/html", - ".html": "text/html", - ".htmls": "text/html", - ".htt": "text/webviewhtml", - ".htx": "text/html", - ".ice": "x-conference/x-cooltalk", - ".ico": "image/x-icon", - ".ics": "text/calendar", - ".icz": "text/calendar", - ".idc": "text/plain", - ".ief": "image/ief", - ".iefs": "image/ief", - ".iges": "application/iges", - ".igs": "application/iges", - ".ima": "application/x-ima", - ".imap": "application/x-httpd-imap", - ".inf": "application/inf", - ".ins": "application/x-internett-signup", - ".ip": "application/x-ip2", - ".isu": "video/x-isvideo", - ".it": "audio/it", - ".iv": "application/x-inventor", - ".ivr": "i-world/i-vrml", - ".ivy": "application/x-livescreen", - ".jam": "audio/x-jam", - ".jav": "text/x-java-source", - ".java": "text/x-java-source", - ".jcm": "application/x-java-commerce", - ".jfif-tbnl": "image/jpeg", - ".jfif": "image/jpeg", - ".jnlp": "application/x-java-jnlp-file", - ".jpe": "image/jpeg", - ".jpeg": "image/jpeg", - ".jpg": "image/jpeg", - ".jps": "image/x-jps", - ".js": "application/javascript", - ".json": "application/json", - ".jut": "image/jutvision", - ".kar": "audio/midi", - ".karbon": "application/vnd.kde.karbon", - ".kfo": "application/vnd.kde.kformula", - ".flw": "application/vnd.kde.kivio", - ".kml": "application/vnd.google-earth.kml+xml", - ".kmz": "application/vnd.google-earth.kmz", - ".kon": "application/vnd.kde.kontour", - ".kpr": "application/vnd.kde.kpresenter", - ".kpt": "application/vnd.kde.kpresenter", - ".ksp": "application/vnd.kde.kspread", - ".kwd": "application/vnd.kde.kword", - ".kwt": "application/vnd.kde.kword", - ".ksh": "text/x-scriptksh", - ".la": "audio/nspaudio", - ".lam": "audio/x-liveaudio", - ".latex": "application/x-latex", - ".lha": "application/lha", - ".lhx": "application/octet-stream", - ".list": "text/plain", - ".lma": "audio/nspaudio", - ".log": "text/plain", - ".lsp": "text/x-scriptlisp", - ".lst": "text/plain", - ".lsx": "text/x-la-asf", - ".ltx": "application/x-latex", - ".lzh": "application/octet-stream", - ".lzx": "application/lzx", - ".m1v": "video/mpeg", - ".m2a": "audio/mpeg", - ".m2v": "video/mpeg", - ".m3u": "audio/x-mpegurl", - ".m": "text/x-m", - ".man": "application/x-troff-man", - ".manifest": "text/cache-manifest", - ".map": "application/x-navimap", - ".mar": "text/plain", - ".mbd": "application/mbedlet", - ".mc$": "application/x-magic-cap-package-10", - ".mcd": "application/mcad", - ".mcf": "text/mcf", - ".mcp": "application/netmc", - ".me": "application/x-troff-me", - ".mht": "message/rfc822", - ".mhtml": "message/rfc822", - ".mid": "application/x-midi", - ".midi": "application/x-midi", - ".mif": "application/x-frame", - ".mime": "message/rfc822", - ".mjf": "audio/x-vndaudioexplosionmjuicemediafile", - ".mjpg": "video/x-motion-jpeg", - ".mm": "application/base64", - ".mme": "application/base64", - ".mod": "audio/mod", - ".moov": "video/quicktime", - ".mov": "video/quicktime", - ".movie": "video/x-sgi-movie", - ".mp2": "audio/mpeg", - ".mp3": "audio/mpeg3", - ".mp4": "video/mp4", - ".mpa": "audio/mpeg", - ".mpc": "application/x-project", - ".mpe": "video/mpeg", - ".mpeg": "video/mpeg", - ".mpg": "video/mpeg", - ".mpga": "audio/mpeg", - ".mpp": "application/vndms-project", - ".mpt": "application/x-project", - ".mpv": "application/x-project", - ".mpx": "application/x-project", - ".mrc": "application/marc", - ".ms": "application/x-troff-ms", - ".mv": "video/x-sgi-movie", - ".my": "audio/make", - ".mzz": "application/x-vndaudioexplosionmzz", - ".nap": "image/naplps", - ".naplps": "image/naplps", - ".nc": "application/x-netcdf", - ".ncm": "application/vndnokiaconfiguration-message", - ".nif": "image/x-niff", - ".niff": "image/x-niff", - ".nix": "application/x-mix-transfer", - ".nsc": "application/x-conference", - ".nvd": "application/x-navidoc", - ".o": "application/octet-stream", - ".oda": "application/oda", - ".odb": "application/vnd.oasis.opendocument.database", - ".odc": "application/vnd.oasis.opendocument.chart", - ".odf": "application/vnd.oasis.opendocument.formula", - ".odg": "application/vnd.oasis.opendocument.graphics", - ".odi": "application/vnd.oasis.opendocument.image", - ".odm": "application/vnd.oasis.opendocument.text-master", - ".odp": "application/vnd.oasis.opendocument.presentation", - ".ods": "application/vnd.oasis.opendocument.spreadsheet", - ".odt": "application/vnd.oasis.opendocument.text", - ".oga": "audio/ogg", - ".ogg": "audio/ogg", - ".ogv": "video/ogg", - ".omc": "application/x-omc", - ".omcd": "application/x-omcdatamaker", - ".omcr": "application/x-omcregerator", - ".otc": "application/vnd.oasis.opendocument.chart-template", - ".otf": "application/vnd.oasis.opendocument.formula-template", - ".otg": "application/vnd.oasis.opendocument.graphics-template", - ".oth": "application/vnd.oasis.opendocument.text-web", - ".oti": "application/vnd.oasis.opendocument.image-template", - ".otm": "application/vnd.oasis.opendocument.text-master", - ".otp": "application/vnd.oasis.opendocument.presentation-template", - ".ots": "application/vnd.oasis.opendocument.spreadsheet-template", - ".ott": "application/vnd.oasis.opendocument.text-template", - ".p10": "application/pkcs10", - ".p12": "application/pkcs-12", - ".p7a": "application/x-pkcs7-signature", - ".p7c": "application/pkcs7-mime", - ".p7m": "application/pkcs7-mime", - ".p7r": "application/x-pkcs7-certreqresp", - ".p7s": "application/pkcs7-signature", - ".p": "text/x-pascal", - ".part": "application/pro_eng", - ".pas": "text/pascal", - ".pbm": "image/x-portable-bitmap", - ".pcl": "application/vndhp-pcl", - ".pct": "image/x-pict", - ".pcx": "image/x-pcx", - ".pdb": "chemical/x-pdb", - ".pdf": "application/pdf", - ".pfunk": "audio/make", - ".pgm": "image/x-portable-graymap", - ".pic": "image/pict", - ".pict": "image/pict", - ".pkg": "application/x-newton-compatible-pkg", - ".pko": "application/vndms-pkipko", - ".pl": "text/x-scriptperl", - ".plx": "application/x-pixclscript", - ".pm4": "application/x-pagemaker", - ".pm5": "application/x-pagemaker", - ".pm": "text/x-scriptperl-module", - ".png": "image/png", - ".pnm": "application/x-portable-anymap", - ".pot": "application/mspowerpoint", - ".pov": "model/x-pov", - ".ppa": "application/vndms-powerpoint", - ".ppm": "image/x-portable-pixmap", - ".pps": "application/mspowerpoint", - ".ppt": "application/mspowerpoint", - ".ppz": "application/mspowerpoint", - ".pre": "application/x-freelance", - ".prt": "application/pro_eng", - ".ps": "application/postscript", - ".psd": "application/octet-stream", - ".pvu": "paleovu/x-pv", - ".pwz": "application/vndms-powerpoint", - ".py": "text/x-scriptphyton", - ".pyc": "application/x-bytecodepython", - ".qcp": "audio/vndqcelp", - ".qd3": "x-world/x-3dmf", - ".qd3d": "x-world/x-3dmf", - ".qif": "image/x-quicktime", - ".qt": "video/quicktime", - ".qtc": "video/x-qtc", - ".qti": "image/x-quicktime", - ".qtif": "image/x-quicktime", - ".ra": "audio/x-pn-realaudio", - ".ram": "audio/x-pn-realaudio", - ".rar": "application/x-rar-compressed", - ".ras": "application/x-cmu-raster", - ".rast": "image/cmu-raster", - ".rexx": "text/x-scriptrexx", - ".rf": "image/vndrn-realflash", - ".rgb": "image/x-rgb", - ".rm": "application/vndrn-realmedia", - ".rmi": "audio/mid", - ".rmm": "audio/x-pn-realaudio", - ".rmp": "audio/x-pn-realaudio", - ".rng": "application/ringing-tones", - ".rnx": "application/vndrn-realplayer", - ".roff": "application/x-troff", - ".rp": "image/vndrn-realpix", - ".rpm": "audio/x-pn-realaudio-plugin", - ".rt": "text/vndrn-realtext", - ".rtf": "text/richtext", - ".rtx": "text/richtext", - ".rv": "video/vndrn-realvideo", - ".s": "text/x-asm", - ".s3m": "audio/s3m", - ".s7z": "application/x-7z-compressed", - ".saveme": "application/octet-stream", - ".sbk": "application/x-tbook", - ".scm": "text/x-scriptscheme", - ".sdml": "text/plain", - ".sdp": "application/sdp", - ".sdr": "application/sounder", - ".sea": "application/sea", - ".set": "application/set", - ".sgm": "text/x-sgml", - ".sgml": "text/x-sgml", - ".sh": "text/x-scriptsh", - ".shar": "application/x-bsh", - ".shtml": "text/x-server-parsed-html", - ".sid": "audio/x-psid", - ".skd": "application/x-koan", - ".skm": "application/x-koan", - ".skp": "application/x-koan", - ".skt": "application/x-koan", - ".sit": "application/x-stuffit", - ".sitx": "application/x-stuffitx", - ".sl": "application/x-seelogo", - ".smi": "application/smil", - ".smil": "application/smil", - ".snd": "audio/basic", - ".sol": "application/solids", - ".spc": "text/x-speech", - ".spl": "application/futuresplash", - ".spr": "application/x-sprite", - ".sprite": "application/x-sprite", - ".spx": "audio/ogg", - ".src": "application/x-wais-source", - ".ssi": "text/x-server-parsed-html", - ".ssm": "application/streamingmedia", - ".sst": "application/vndms-pkicertstore", - ".step": "application/step", - ".stl": "application/sla", - ".stp": "application/step", - ".sv4cpio": "application/x-sv4cpio", - ".sv4crc": "application/x-sv4crc", - ".svf": "image/vnddwg", - ".svg": "image/svg+xml", - ".svr": "application/x-world", - ".swf": "application/x-shockwave-flash", - ".t": "application/x-troff", - ".talk": "text/x-speech", - ".tar": "application/x-tar", - ".tbk": "application/toolbook", - ".tcl": "text/x-scripttcl", - ".tcsh": "text/x-scripttcsh", - ".tex": "application/x-tex", - ".texi": "application/x-texinfo", - ".texinfo": "application/x-texinfo", - ".text": "text/plain", - ".tgz": "application/gnutar", - ".tif": "image/tiff", - ".tiff": "image/tiff", - ".tr": "application/x-troff", - ".tsi": "audio/tsp-audio", - ".tsp": "application/dsptype", - ".tsv": "text/tab-separated-values", - ".turbot": "image/florian", - ".txt": "text/plain", - ".uil": "text/x-uil", - ".uni": "text/uri-list", - ".unis": "text/uri-list", - ".unv": "application/i-deas", - ".uri": "text/uri-list", - ".uris": "text/uri-list", - ".ustar": "application/x-ustar", - ".uu": "text/x-uuencode", - ".uue": "text/x-uuencode", - ".vcd": "application/x-cdlink", - ".vcf": "text/x-vcard", - ".vcard": "text/x-vcard", - ".vcs": "text/x-vcalendar", - ".vda": "application/vda", - ".vdo": "video/vdo", - ".vew": "application/groupwise", - ".viv": "video/vivo", - ".vivo": "video/vivo", - ".vmd": "application/vocaltec-media-desc", - ".vmf": "application/vocaltec-media-file", - ".voc": "audio/voc", - ".vos": "video/vosaic", - ".vox": "audio/voxware", - ".vqe": "audio/x-twinvq-plugin", - ".vqf": "audio/x-twinvq", - ".vql": "audio/x-twinvq-plugin", - ".vrml": "application/x-vrml", - ".vrt": "x-world/x-vrt", - ".vsd": "application/x-visio", - ".vst": "application/x-visio", - ".vsw": "application/x-visio", - ".w60": "application/wordperfect60", - ".w61": "application/wordperfect61", - ".w6w": "application/msword", - ".wav": "audio/wav", - ".wb1": "application/x-qpro", - ".wbmp": "image/vnd.wap.wbmp", - ".web": "application/vndxara", - ".wiz": "application/msword", - ".wk1": "application/x-123", - ".wmf": "windows/metafile", - ".wml": "text/vnd.wap.wml", - ".wmlc": "application/vnd.wap.wmlc", - ".wmls": "text/vnd.wap.wmlscript", - ".wmlsc": "application/vnd.wap.wmlscriptc", - ".word": "application/msword", - ".wp5": "application/wordperfect", - ".wp6": "application/wordperfect", - ".wp": "application/wordperfect", - ".wpd": "application/wordperfect", - ".wq1": "application/x-lotus", - ".wri": "application/mswrite", - ".wrl": "application/x-world", - ".wrz": "model/vrml", - ".wsc": "text/scriplet", - ".wsrc": "application/x-wais-source", - ".wtk": "application/x-wintalk", - ".x-png": "image/png", - ".xbm": "image/x-xbitmap", - ".xdr": "video/x-amt-demorun", - ".xgz": "xgl/drawing", - ".xif": "image/vndxiff", - ".xl": "application/excel", - ".xla": "application/excel", - ".xlb": "application/excel", - ".xlc": "application/excel", - ".xld": "application/excel", - ".xlk": "application/excel", - ".xll": "application/excel", - ".xlm": "application/excel", - ".xls": "application/excel", - ".xlt": "application/excel", - ".xlv": "application/excel", - ".xlw": "application/excel", - ".xm": "audio/xm", - ".xml": "text/xml", - ".xmz": "xgl/movie", - ".xpix": "application/x-vndls-xpix", - ".xpm": "image/x-xpixmap", - ".xsr": "video/x-amt-showrun", - ".xwd": "image/x-xwd", - ".xyz": "chemical/x-pdb", - ".z": "application/x-compress", - ".zip": "application/zip", - ".zoo": "application/octet-stream", - ".zsh": "text/x-scriptzsh", - ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", - ".docm": "application/vnd.ms-word.document.macroEnabled.12", - ".dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template", - ".dotm": "application/vnd.ms-word.template.macroEnabled.12", - ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ".xlsm": "application/vnd.ms-excel.sheet.macroEnabled.12", - ".xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template", - ".xltm": "application/vnd.ms-excel.template.macroEnabled.12", - ".xlsb": "application/vnd.ms-excel.sheet.binary.macroEnabled.12", - ".xlam": "application/vnd.ms-excel.addin.macroEnabled.12", - ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", - ".pptm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12", - ".ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow", - ".ppsm": "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", - ".potx": "application/vnd.openxmlformats-officedocument.presentationml.template", - ".potm": "application/vnd.ms-powerpoint.template.macroEnabled.12", - ".ppam": "application/vnd.ms-powerpoint.addin.macroEnabled.12", - ".sldx": "application/vnd.openxmlformats-officedocument.presentationml.slide", - ".sldm": "application/vnd.ms-powerpoint.slide.macroEnabled.12", - ".thmx": "application/vnd.ms-officetheme", - ".onetoc": "application/onenote", - ".onetoc2": "application/onenote", - ".onetmp": "application/onenote", - ".onepkg": "application/onenote", - ".key": "application/x-iwork-keynote-sffkey", - ".kth": "application/x-iwork-keynote-sffkth", - ".nmbtemplate": "application/x-iwork-numbers-sfftemplate", - ".numbers": "application/x-iwork-numbers-sffnumbers", - ".pages": "application/x-iwork-pages-sffpages", - ".template": "application/x-iwork-pages-sfftemplate", - ".xpi": "application/x-xpinstall", - ".oex": "application/x-opera-extension", - ".mustache": "text/html", -} diff --git a/vender/github.com/astaxie/beego/namespace.go b/vender/github.com/astaxie/beego/namespace.go deleted file mode 100755 index 48e1c13..0000000 --- a/vender/github.com/astaxie/beego/namespace.go +++ /dev/null @@ -1,396 +0,0 @@ -// 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" - "strings" - - beecontext "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" -) - -type namespaceCond func(*beecontext.Context) bool - -// LinkNamespace used as link action -type LinkNamespace func(*Namespace) - -// Namespace is store all the info -type Namespace struct { - prefix string - handlers *ControllerRegister -} - -// NewNamespace get new Namespace -func NewNamespace(prefix string, params ...LinkNamespace) *Namespace { - ns := &Namespace{ - prefix: prefix, - handlers: NewControllerRegister(), - } - for _, p := range params { - p(ns) - } - return ns -} - -// Cond set condition function -// if cond return true can run this namespace, else can't -// usage: -// ns.Cond(func (ctx *context.Context) bool{ -// if ctx.Input.Domain() == "api.beego.me" { -// return true -// } -// return false -// }) -// Cond as the first filter -func (n *Namespace) Cond(cond namespaceCond) *Namespace { - fn := func(ctx *beecontext.Context) { - if !cond(ctx) { - exception("405", ctx) - } - } - if v := n.handlers.filters[BeforeRouter]; len(v) > 0 { - mr := new(FilterRouter) - mr.tree = NewTree() - mr.pattern = "*" - mr.filterFunc = fn - mr.tree.AddRouter("*", true) - n.handlers.filters[BeforeRouter] = append([]*FilterRouter{mr}, v...) - } else { - n.handlers.InsertFilter("*", BeforeRouter, fn) - } - return n -} - -// Filter add filter in the Namespace -// action has before & after -// FilterFunc -// usage: -// Filter("before", func (ctx *context.Context){ -// _, ok := ctx.Input.Session("uid").(int) -// if !ok && ctx.Request.RequestURI != "/login" { -// ctx.Redirect(302, "/login") -// } -// }) -func (n *Namespace) Filter(action string, filter ...FilterFunc) *Namespace { - var a int - if action == "before" { - a = BeforeRouter - } else if action == "after" { - a = FinishRouter - } - for _, f := range filter { - n.handlers.InsertFilter("*", a, f) - } - return n -} - -// Router same as beego.Rourer -// refer: https://godoc.org/github.com/cnlh/nps/vender/github.com/astaxie/beego#Router -func (n *Namespace) Router(rootpath string, c ControllerInterface, mappingMethods ...string) *Namespace { - n.handlers.Add(rootpath, c, mappingMethods...) - return n -} - -// AutoRouter same as beego.AutoRouter -// refer: https://godoc.org/github.com/cnlh/nps/vender/github.com/astaxie/beego#AutoRouter -func (n *Namespace) AutoRouter(c ControllerInterface) *Namespace { - n.handlers.AddAuto(c) - return n -} - -// AutoPrefix same as beego.AutoPrefix -// refer: https://godoc.org/github.com/cnlh/nps/vender/github.com/astaxie/beego#AutoPrefix -func (n *Namespace) AutoPrefix(prefix string, c ControllerInterface) *Namespace { - n.handlers.AddAutoPrefix(prefix, c) - return n -} - -// Get same as beego.Get -// refer: https://godoc.org/github.com/cnlh/nps/vender/github.com/astaxie/beego#Get -func (n *Namespace) Get(rootpath string, f FilterFunc) *Namespace { - n.handlers.Get(rootpath, f) - return n -} - -// Post same as beego.Post -// refer: https://godoc.org/github.com/cnlh/nps/vender/github.com/astaxie/beego#Post -func (n *Namespace) Post(rootpath string, f FilterFunc) *Namespace { - n.handlers.Post(rootpath, f) - return n -} - -// Delete same as beego.Delete -// refer: https://godoc.org/github.com/cnlh/nps/vender/github.com/astaxie/beego#Delete -func (n *Namespace) Delete(rootpath string, f FilterFunc) *Namespace { - n.handlers.Delete(rootpath, f) - return n -} - -// Put same as beego.Put -// refer: https://godoc.org/github.com/cnlh/nps/vender/github.com/astaxie/beego#Put -func (n *Namespace) Put(rootpath string, f FilterFunc) *Namespace { - n.handlers.Put(rootpath, f) - return n -} - -// Head same as beego.Head -// refer: https://godoc.org/github.com/cnlh/nps/vender/github.com/astaxie/beego#Head -func (n *Namespace) Head(rootpath string, f FilterFunc) *Namespace { - n.handlers.Head(rootpath, f) - return n -} - -// Options same as beego.Options -// refer: https://godoc.org/github.com/cnlh/nps/vender/github.com/astaxie/beego#Options -func (n *Namespace) Options(rootpath string, f FilterFunc) *Namespace { - n.handlers.Options(rootpath, f) - return n -} - -// Patch same as beego.Patch -// refer: https://godoc.org/github.com/cnlh/nps/vender/github.com/astaxie/beego#Patch -func (n *Namespace) Patch(rootpath string, f FilterFunc) *Namespace { - n.handlers.Patch(rootpath, f) - return n -} - -// Any same as beego.Any -// refer: https://godoc.org/github.com/cnlh/nps/vender/github.com/astaxie/beego#Any -func (n *Namespace) Any(rootpath string, f FilterFunc) *Namespace { - n.handlers.Any(rootpath, f) - return n -} - -// Handler same as beego.Handler -// refer: https://godoc.org/github.com/cnlh/nps/vender/github.com/astaxie/beego#Handler -func (n *Namespace) Handler(rootpath string, h http.Handler) *Namespace { - n.handlers.Handler(rootpath, h) - return n -} - -// Include add include class -// refer: https://godoc.org/github.com/cnlh/nps/vender/github.com/astaxie/beego#Include -func (n *Namespace) Include(cList ...ControllerInterface) *Namespace { - n.handlers.Include(cList...) - return n -} - -// Namespace add nest Namespace -// usage: -//ns := beego.NewNamespace(“/v1”). -//Namespace( -// beego.NewNamespace("/shop"). -// Get("/:id", func(ctx *context.Context) { -// ctx.Output.Body([]byte("shopinfo")) -// }), -// beego.NewNamespace("/order"). -// Get("/:id", func(ctx *context.Context) { -// ctx.Output.Body([]byte("orderinfo")) -// }), -// beego.NewNamespace("/crm"). -// Get("/:id", func(ctx *context.Context) { -// ctx.Output.Body([]byte("crminfo")) -// }), -//) -func (n *Namespace) Namespace(ns ...*Namespace) *Namespace { - for _, ni := range ns { - for k, v := range ni.handlers.routers { - if t, ok := n.handlers.routers[k]; ok { - addPrefix(v, ni.prefix) - n.handlers.routers[k].AddTree(ni.prefix, v) - } else { - t = NewTree() - t.AddTree(ni.prefix, v) - addPrefix(t, ni.prefix) - n.handlers.routers[k] = t - } - } - if ni.handlers.enableFilter { - for pos, filterList := range ni.handlers.filters { - for _, mr := range filterList { - t := NewTree() - t.AddTree(ni.prefix, mr.tree) - mr.tree = t - n.handlers.insertFilterRouter(pos, mr) - } - } - } - } - return n -} - -// AddNamespace register Namespace into beego.Handler -// support multi Namespace -func AddNamespace(nl ...*Namespace) { - for _, n := range nl { - for k, v := range n.handlers.routers { - if t, ok := BeeApp.Handlers.routers[k]; ok { - addPrefix(v, n.prefix) - BeeApp.Handlers.routers[k].AddTree(n.prefix, v) - } else { - t = NewTree() - t.AddTree(n.prefix, v) - addPrefix(t, n.prefix) - BeeApp.Handlers.routers[k] = t - } - } - if n.handlers.enableFilter { - for pos, filterList := range n.handlers.filters { - for _, mr := range filterList { - t := NewTree() - t.AddTree(n.prefix, mr.tree) - mr.tree = t - BeeApp.Handlers.insertFilterRouter(pos, mr) - } - } - } - } -} - -func addPrefix(t *Tree, prefix string) { - for _, v := range t.fixrouters { - addPrefix(v, prefix) - } - if t.wildcard != nil { - addPrefix(t.wildcard, prefix) - } - for _, l := range t.leaves { - if c, ok := l.runObject.(*ControllerInfo); ok { - if !strings.HasPrefix(c.pattern, prefix) { - c.pattern = prefix + c.pattern - } - } - } -} - -// NSCond is Namespace Condition -func NSCond(cond namespaceCond) LinkNamespace { - return func(ns *Namespace) { - ns.Cond(cond) - } -} - -// NSBefore Namespace BeforeRouter filter -func NSBefore(filterList ...FilterFunc) LinkNamespace { - return func(ns *Namespace) { - ns.Filter("before", filterList...) - } -} - -// NSAfter add Namespace FinishRouter filter -func NSAfter(filterList ...FilterFunc) LinkNamespace { - return func(ns *Namespace) { - ns.Filter("after", filterList...) - } -} - -// NSInclude Namespace Include ControllerInterface -func NSInclude(cList ...ControllerInterface) LinkNamespace { - return func(ns *Namespace) { - ns.Include(cList...) - } -} - -// NSRouter call Namespace Router -func NSRouter(rootpath string, c ControllerInterface, mappingMethods ...string) LinkNamespace { - return func(ns *Namespace) { - ns.Router(rootpath, c, mappingMethods...) - } -} - -// NSGet call Namespace Get -func NSGet(rootpath string, f FilterFunc) LinkNamespace { - return func(ns *Namespace) { - ns.Get(rootpath, f) - } -} - -// NSPost call Namespace Post -func NSPost(rootpath string, f FilterFunc) LinkNamespace { - return func(ns *Namespace) { - ns.Post(rootpath, f) - } -} - -// NSHead call Namespace Head -func NSHead(rootpath string, f FilterFunc) LinkNamespace { - return func(ns *Namespace) { - ns.Head(rootpath, f) - } -} - -// NSPut call Namespace Put -func NSPut(rootpath string, f FilterFunc) LinkNamespace { - return func(ns *Namespace) { - ns.Put(rootpath, f) - } -} - -// NSDelete call Namespace Delete -func NSDelete(rootpath string, f FilterFunc) LinkNamespace { - return func(ns *Namespace) { - ns.Delete(rootpath, f) - } -} - -// NSAny call Namespace Any -func NSAny(rootpath string, f FilterFunc) LinkNamespace { - return func(ns *Namespace) { - ns.Any(rootpath, f) - } -} - -// NSOptions call Namespace Options -func NSOptions(rootpath string, f FilterFunc) LinkNamespace { - return func(ns *Namespace) { - ns.Options(rootpath, f) - } -} - -// NSPatch call Namespace Patch -func NSPatch(rootpath string, f FilterFunc) LinkNamespace { - return func(ns *Namespace) { - ns.Patch(rootpath, f) - } -} - -// NSAutoRouter call Namespace AutoRouter -func NSAutoRouter(c ControllerInterface) LinkNamespace { - return func(ns *Namespace) { - ns.AutoRouter(c) - } -} - -// NSAutoPrefix call Namespace AutoPrefix -func NSAutoPrefix(prefix string, c ControllerInterface) LinkNamespace { - return func(ns *Namespace) { - ns.AutoPrefix(prefix, c) - } -} - -// NSNamespace add sub Namespace -func NSNamespace(prefix string, params ...LinkNamespace) LinkNamespace { - return func(ns *Namespace) { - n := NewNamespace(prefix, params...) - ns.Namespace(n) - } -} - -// NSHandler add handler -func NSHandler(rootpath string, h http.Handler) LinkNamespace { - return func(ns *Namespace) { - ns.Handler(rootpath, h) - } -} diff --git a/vender/github.com/astaxie/beego/namespace_test.go b/vender/github.com/astaxie/beego/namespace_test.go deleted file mode 100755 index bfe862d..0000000 --- a/vender/github.com/astaxie/beego/namespace_test.go +++ /dev/null @@ -1,168 +0,0 @@ -// 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" - "strconv" - "testing" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" -) - -func TestNamespaceGet(t *testing.T) { - r, _ := http.NewRequest("GET", "/v1/user", nil) - w := httptest.NewRecorder() - - ns := NewNamespace("/v1") - ns.Get("/user", func(ctx *context.Context) { - ctx.Output.Body([]byte("v1_user")) - }) - AddNamespace(ns) - BeeApp.Handlers.ServeHTTP(w, r) - if w.Body.String() != "v1_user" { - t.Errorf("TestNamespaceGet can't run, get the response is " + w.Body.String()) - } -} - -func TestNamespacePost(t *testing.T) { - r, _ := http.NewRequest("POST", "/v1/user/123", nil) - w := httptest.NewRecorder() - - ns := NewNamespace("/v1") - ns.Post("/user/:id", func(ctx *context.Context) { - ctx.Output.Body([]byte(ctx.Input.Param(":id"))) - }) - AddNamespace(ns) - BeeApp.Handlers.ServeHTTP(w, r) - if w.Body.String() != "123" { - t.Errorf("TestNamespacePost can't run, get the response is " + w.Body.String()) - } -} - -func TestNamespaceNest(t *testing.T) { - r, _ := http.NewRequest("GET", "/v1/admin/order", nil) - w := httptest.NewRecorder() - - ns := NewNamespace("/v1") - ns.Namespace( - NewNamespace("/admin"). - Get("/order", func(ctx *context.Context) { - ctx.Output.Body([]byte("order")) - }), - ) - AddNamespace(ns) - BeeApp.Handlers.ServeHTTP(w, r) - if w.Body.String() != "order" { - t.Errorf("TestNamespaceNest can't run, get the response is " + w.Body.String()) - } -} - -func TestNamespaceNestParam(t *testing.T) { - r, _ := http.NewRequest("GET", "/v1/admin/order/123", nil) - w := httptest.NewRecorder() - - ns := NewNamespace("/v1") - ns.Namespace( - NewNamespace("/admin"). - Get("/order/:id", func(ctx *context.Context) { - ctx.Output.Body([]byte(ctx.Input.Param(":id"))) - }), - ) - AddNamespace(ns) - BeeApp.Handlers.ServeHTTP(w, r) - if w.Body.String() != "123" { - t.Errorf("TestNamespaceNestParam can't run, get the response is " + w.Body.String()) - } -} - -func TestNamespaceRouter(t *testing.T) { - r, _ := http.NewRequest("GET", "/v1/api/list", nil) - w := httptest.NewRecorder() - - ns := NewNamespace("/v1") - ns.Router("/api/list", &TestController{}, "*:List") - AddNamespace(ns) - BeeApp.Handlers.ServeHTTP(w, r) - if w.Body.String() != "i am list" { - t.Errorf("TestNamespaceRouter can't run, get the response is " + w.Body.String()) - } -} - -func TestNamespaceAutoFunc(t *testing.T) { - r, _ := http.NewRequest("GET", "/v1/test/list", nil) - w := httptest.NewRecorder() - - ns := NewNamespace("/v1") - ns.AutoRouter(&TestController{}) - AddNamespace(ns) - BeeApp.Handlers.ServeHTTP(w, r) - if w.Body.String() != "i am list" { - t.Errorf("user define func can't run") - } -} - -func TestNamespaceFilter(t *testing.T) { - r, _ := http.NewRequest("GET", "/v1/user/123", nil) - w := httptest.NewRecorder() - - ns := NewNamespace("/v1") - ns.Filter("before", func(ctx *context.Context) { - ctx.Output.Body([]byte("this is Filter")) - }). - Get("/user/:id", func(ctx *context.Context) { - ctx.Output.Body([]byte(ctx.Input.Param(":id"))) - }) - AddNamespace(ns) - BeeApp.Handlers.ServeHTTP(w, r) - if w.Body.String() != "this is Filter" { - t.Errorf("TestNamespaceFilter can't run, get the response is " + w.Body.String()) - } -} - -func TestNamespaceCond(t *testing.T) { - r, _ := http.NewRequest("GET", "/v2/test/list", nil) - w := httptest.NewRecorder() - - ns := NewNamespace("/v2") - ns.Cond(func(ctx *context.Context) bool { - return ctx.Input.Domain() == "beego.me" - }). - AutoRouter(&TestController{}) - AddNamespace(ns) - BeeApp.Handlers.ServeHTTP(w, r) - if w.Code != 405 { - t.Errorf("TestNamespaceCond can't run get the result " + strconv.Itoa(w.Code)) - } -} - -func TestNamespaceInside(t *testing.T) { - r, _ := http.NewRequest("GET", "/v3/shop/order/123", nil) - w := httptest.NewRecorder() - ns := NewNamespace("/v3", - NSAutoRouter(&TestController{}), - NSNamespace("/shop", - NSGet("/order/:id", func(ctx *context.Context) { - ctx.Output.Body([]byte(ctx.Input.Param(":id"))) - }), - ), - ) - AddNamespace(ns) - BeeApp.Handlers.ServeHTTP(w, r) - if w.Body.String() != "123" { - t.Errorf("TestNamespaceInside can't run, get the response is " + w.Body.String()) - } -} diff --git a/vender/github.com/astaxie/beego/parser.go b/vender/github.com/astaxie/beego/parser.go deleted file mode 100755 index c7cc5c5..0000000 --- a/vender/github.com/astaxie/beego/parser.go +++ /dev/null @@ -1,584 +0,0 @@ -// 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" - "errors" - "fmt" - "go/ast" - "go/parser" - "go/token" - "io/ioutil" - "os" - "path/filepath" - "regexp" - "sort" - "strconv" - "strings" - "unicode" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context/param" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/utils" -) - -var globalRouterTemplate = `package routers - -import ( - "github.com/cnlh/nps/vender/github.com/astaxie/beego" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context/param"{{.globalimport}} -) - -func init() { -{{.globalinfo}} -} -` - -var ( - lastupdateFilename = "lastupdate.tmp" - commentFilename string - pkgLastupdate map[string]int64 - genInfoList map[string][]ControllerComments - - routerHooks = map[string]int{ - "beego.BeforeStatic": BeforeStatic, - "beego.BeforeRouter": BeforeRouter, - "beego.BeforeExec": BeforeExec, - "beego.AfterExec": AfterExec, - "beego.FinishRouter": FinishRouter, - } - - routerHooksMapping = map[int]string{ - BeforeStatic: "beego.BeforeStatic", - BeforeRouter: "beego.BeforeRouter", - BeforeExec: "beego.BeforeExec", - AfterExec: "beego.AfterExec", - FinishRouter: "beego.FinishRouter", - } -) - -const commentPrefix = "commentsRouter_" - -func init() { - pkgLastupdate = make(map[string]int64) -} - -func parserPkg(pkgRealpath, pkgpath string) error { - rep := strings.NewReplacer("\\", "_", "/", "_", ".", "_") - commentFilename, _ = filepath.Rel(AppPath, pkgRealpath) - commentFilename = commentPrefix + rep.Replace(commentFilename) + ".go" - if !compareFile(pkgRealpath) { - logs.Info(pkgRealpath + " no changed") - return nil - } - genInfoList = make(map[string][]ControllerComments) - fileSet := token.NewFileSet() - astPkgs, err := parser.ParseDir(fileSet, pkgRealpath, func(info os.FileInfo) bool { - name := info.Name() - return !info.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") - }, parser.ParseComments) - - if err != nil { - return err - } - for _, pkg := range astPkgs { - for _, fl := range pkg.Files { - for _, d := range fl.Decls { - switch specDecl := d.(type) { - case *ast.FuncDecl: - if specDecl.Recv != nil { - exp, ok := specDecl.Recv.List[0].Type.(*ast.StarExpr) // Check that the type is correct first beforing throwing to parser - if ok { - parserComments(specDecl, fmt.Sprint(exp.X), pkgpath) - } - } - } - } - } - } - genRouterCode(pkgRealpath) - savetoFile(pkgRealpath) - return nil -} - -type parsedComment struct { - routerPath string - methods []string - params map[string]parsedParam - filters []parsedFilter - imports []parsedImport -} - -type parsedImport struct { - importPath string - importAlias string -} - -type parsedFilter struct { - pattern string - pos int - filter string - params []bool -} - -type parsedParam struct { - name string - datatype string - location string - defValue string - required bool -} - -func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error { - if f.Doc != nil { - parsedComments, err := parseComment(f.Doc.List) - if err != nil { - return err - } - for _, parsedComment := range parsedComments { - if parsedComment.routerPath != "" { - key := pkgpath + ":" + controllerName - cc := ControllerComments{} - cc.Method = f.Name.String() - cc.Router = parsedComment.routerPath - cc.AllowHTTPMethods = parsedComment.methods - cc.MethodParams = buildMethodParams(f.Type.Params.List, parsedComment) - cc.FilterComments = buildFilters(parsedComment.filters) - cc.ImportComments = buildImports(parsedComment.imports) - genInfoList[key] = append(genInfoList[key], cc) - } - } - } - return nil -} - -func buildImports(pis []parsedImport) []*ControllerImportComments { - var importComments []*ControllerImportComments - - for _, pi := range pis { - importComments = append(importComments, &ControllerImportComments{ - ImportPath: pi.importPath, - ImportAlias: pi.importAlias, - }) - } - - return importComments -} - -func buildFilters(pfs []parsedFilter) []*ControllerFilterComments { - var filterComments []*ControllerFilterComments - - for _, pf := range pfs { - var ( - returnOnOutput bool - resetParams bool - ) - - if len(pf.params) >= 1 { - returnOnOutput = pf.params[0] - } - - if len(pf.params) >= 2 { - resetParams = pf.params[1] - } - - filterComments = append(filterComments, &ControllerFilterComments{ - Filter: pf.filter, - Pattern: pf.pattern, - Pos: pf.pos, - ReturnOnOutput: returnOnOutput, - ResetParams: resetParams, - }) - } - - return filterComments -} - -func buildMethodParams(funcParams []*ast.Field, pc *parsedComment) []*param.MethodParam { - result := make([]*param.MethodParam, 0, len(funcParams)) - for _, fparam := range funcParams { - for _, pName := range fparam.Names { - methodParam := buildMethodParam(fparam, pName.Name, pc) - result = append(result, methodParam) - } - } - return result -} - -func buildMethodParam(fparam *ast.Field, name string, pc *parsedComment) *param.MethodParam { - options := []param.MethodParamOption{} - if cparam, ok := pc.params[name]; ok { - //Build param from comment info - name = cparam.name - if cparam.required { - options = append(options, param.IsRequired) - } - switch cparam.location { - case "body": - options = append(options, param.InBody) - case "header": - options = append(options, param.InHeader) - case "path": - options = append(options, param.InPath) - } - if cparam.defValue != "" { - options = append(options, param.Default(cparam.defValue)) - } - } else { - if paramInPath(name, pc.routerPath) { - options = append(options, param.InPath) - } - } - return param.New(name, options...) -} - -func paramInPath(name, route string) bool { - return strings.HasSuffix(route, ":"+name) || - strings.Contains(route, ":"+name+"/") -} - -var routeRegex = regexp.MustCompile(`@router\s+(\S+)(?:\s+\[(\S+)\])?`) - -func parseComment(lines []*ast.Comment) (pcs []*parsedComment, err error) { - pcs = []*parsedComment{} - params := map[string]parsedParam{} - filters := []parsedFilter{} - imports := []parsedImport{} - - for _, c := range lines { - t := strings.TrimSpace(strings.TrimLeft(c.Text, "//")) - if strings.HasPrefix(t, "@Param") { - pv := getparams(strings.TrimSpace(strings.TrimLeft(t, "@Param"))) - if len(pv) < 4 { - logs.Error("Invalid @Param format. Needs at least 4 parameters") - } - p := parsedParam{} - names := strings.SplitN(pv[0], "=>", 2) - p.name = names[0] - funcParamName := p.name - if len(names) > 1 { - funcParamName = names[1] - } - p.location = pv[1] - p.datatype = pv[2] - switch len(pv) { - case 5: - p.required, _ = strconv.ParseBool(pv[3]) - case 6: - p.defValue = pv[3] - p.required, _ = strconv.ParseBool(pv[4]) - } - params[funcParamName] = p - } - } - - for _, c := range lines { - t := strings.TrimSpace(strings.TrimLeft(c.Text, "//")) - if strings.HasPrefix(t, "@Import") { - iv := getparams(strings.TrimSpace(strings.TrimLeft(t, "@Import"))) - if len(iv) == 0 || len(iv) > 2 { - logs.Error("Invalid @Import format. Only accepts 1 or 2 parameters") - continue - } - - p := parsedImport{} - p.importPath = iv[0] - - if len(iv) == 2 { - p.importAlias = iv[1] - } - - imports = append(imports, p) - } - } - -filterLoop: - for _, c := range lines { - t := strings.TrimSpace(strings.TrimLeft(c.Text, "//")) - if strings.HasPrefix(t, "@Filter") { - fv := getparams(strings.TrimSpace(strings.TrimLeft(t, "@Filter"))) - if len(fv) < 3 { - logs.Error("Invalid @Filter format. Needs at least 3 parameters") - continue filterLoop - } - - p := parsedFilter{} - p.pattern = fv[0] - posName := fv[1] - if pos, exists := routerHooks[posName]; exists { - p.pos = pos - } else { - logs.Error("Invalid @Filter pos: ", posName) - continue filterLoop - } - - p.filter = fv[2] - fvParams := fv[3:] - for _, fvParam := range fvParams { - switch fvParam { - case "true": - p.params = append(p.params, true) - case "false": - p.params = append(p.params, false) - default: - logs.Error("Invalid @Filter param: ", fvParam) - continue filterLoop - } - } - - filters = append(filters, p) - } - } - - for _, c := range lines { - var pc = &parsedComment{} - pc.params = params - pc.filters = filters - pc.imports = imports - - t := strings.TrimSpace(strings.TrimLeft(c.Text, "//")) - if strings.HasPrefix(t, "@router") { - t := strings.TrimSpace(strings.TrimLeft(c.Text, "//")) - matches := routeRegex.FindStringSubmatch(t) - if len(matches) == 3 { - pc.routerPath = matches[1] - methods := matches[2] - if methods == "" { - pc.methods = []string{"get"} - //pc.hasGet = true - } else { - pc.methods = strings.Split(methods, ",") - //pc.hasGet = strings.Contains(methods, "get") - } - pcs = append(pcs, pc) - } else { - return nil, errors.New("Router information is missing") - } - } - } - return -} - -// direct copy from bee\g_docs.go -// analysis params return []string -// @Param query form string true "The email for login" -// [query form string true "The email for login"] -func getparams(str string) []string { - var s []rune - var j int - var start bool - var r []string - var quoted int8 - for _, c := range str { - if unicode.IsSpace(c) && quoted == 0 { - if !start { - continue - } else { - start = false - j++ - r = append(r, string(s)) - s = make([]rune, 0) - continue - } - } - - start = true - if c == '"' { - quoted ^= 1 - continue - } - s = append(s, c) - } - if len(s) > 0 { - r = append(r, string(s)) - } - return r -} - -func genRouterCode(pkgRealpath string) { - os.Mkdir(getRouterDir(pkgRealpath), 0755) - logs.Info("generate router from comments") - var ( - globalinfo string - globalimport string - sortKey []string - ) - for k := range genInfoList { - sortKey = append(sortKey, k) - } - sort.Strings(sortKey) - for _, k := range sortKey { - cList := genInfoList[k] - sort.Sort(ControllerCommentsSlice(cList)) - for _, c := range cList { - allmethod := "nil" - if len(c.AllowHTTPMethods) > 0 { - allmethod = "[]string{" - for _, m := range c.AllowHTTPMethods { - allmethod += `"` + m + `",` - } - allmethod = strings.TrimRight(allmethod, ",") + "}" - } - - params := "nil" - if len(c.Params) > 0 { - params = "[]map[string]string{" - for _, p := range c.Params { - for k, v := range p { - params = params + `map[string]string{` + k + `:"` + v + `"},` - } - } - params = strings.TrimRight(params, ",") + "}" - } - - methodParams := "param.Make(" - if len(c.MethodParams) > 0 { - lines := make([]string, 0, len(c.MethodParams)) - for _, m := range c.MethodParams { - lines = append(lines, fmt.Sprint(m)) - } - methodParams += "\n " + - strings.Join(lines, ",\n ") + - ",\n " - } - methodParams += ")" - - imports := "" - if len(c.ImportComments) > 0 { - for _, i := range c.ImportComments { - if i.ImportAlias != "" { - imports += fmt.Sprintf(` - %s "%s"`, i.ImportAlias, i.ImportPath) - } else { - imports += fmt.Sprintf(` - "%s"`, i.ImportPath) - } - } - } - - filters := "" - if len(c.FilterComments) > 0 { - for _, f := range c.FilterComments { - filters += fmt.Sprintf(` &beego.ControllerFilter{ - Pattern: "%s", - Pos: %s, - Filter: %s, - ReturnOnOutput: %v, - ResetParams: %v, - },`, f.Pattern, routerHooksMapping[f.Pos], f.Filter, f.ReturnOnOutput, f.ResetParams) - } - } - - if filters == "" { - filters = "nil" - } else { - filters = fmt.Sprintf(`[]*beego.ControllerFilter{ -%s - }`, filters) - } - - globalimport = imports - - globalinfo = globalinfo + ` - beego.GlobalControllerRouter["` + k + `"] = append(beego.GlobalControllerRouter["` + k + `"], - beego.ControllerComments{ - Method: "` + strings.TrimSpace(c.Method) + `", - ` + "Router: `" + c.Router + "`" + `, - AllowHTTPMethods: ` + allmethod + `, - MethodParams: ` + methodParams + `, - Filters: ` + filters + `, - Params: ` + params + `}) -` - } - } - - if globalinfo != "" { - f, err := os.Create(filepath.Join(getRouterDir(pkgRealpath), commentFilename)) - if err != nil { - panic(err) - } - defer f.Close() - - content := strings.Replace(globalRouterTemplate, "{{.globalinfo}}", globalinfo, -1) - content = strings.Replace(content, "{{.globalimport}}", globalimport, -1) - f.WriteString(content) - } -} - -func compareFile(pkgRealpath string) bool { - if !utils.FileExists(filepath.Join(getRouterDir(pkgRealpath), commentFilename)) { - return true - } - if utils.FileExists(lastupdateFilename) { - content, err := ioutil.ReadFile(lastupdateFilename) - if err != nil { - return true - } - json.Unmarshal(content, &pkgLastupdate) - lastupdate, err := getpathTime(pkgRealpath) - if err != nil { - return true - } - if v, ok := pkgLastupdate[pkgRealpath]; ok { - if lastupdate <= v { - return false - } - } - } - return true -} - -func savetoFile(pkgRealpath string) { - lastupdate, err := getpathTime(pkgRealpath) - if err != nil { - return - } - pkgLastupdate[pkgRealpath] = lastupdate - d, err := json.Marshal(pkgLastupdate) - if err != nil { - return - } - ioutil.WriteFile(lastupdateFilename, d, os.ModePerm) -} - -func getpathTime(pkgRealpath string) (lastupdate int64, err error) { - fl, err := ioutil.ReadDir(pkgRealpath) - if err != nil { - return lastupdate, err - } - for _, f := range fl { - if lastupdate < f.ModTime().UnixNano() { - lastupdate = f.ModTime().UnixNano() - } - } - return lastupdate, nil -} - -func getRouterDir(pkgRealpath string) string { - dir := filepath.Dir(pkgRealpath) - for { - d := filepath.Join(dir, "routers") - if utils.FileExists(d) { - return d - } - - if r, _ := filepath.Rel(dir, AppPath); r == "." { - return d - } - // Parent dir. - dir = filepath.Dir(dir) - } -} diff --git a/vender/github.com/astaxie/beego/plugins/apiauth/apiauth.go b/vender/github.com/astaxie/beego/plugins/apiauth/apiauth.go deleted file mode 100755 index b56d992..0000000 --- a/vender/github.com/astaxie/beego/plugins/apiauth/apiauth.go +++ /dev/null @@ -1,160 +0,0 @@ -// 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 apiauth provides handlers to enable apiauth support. -// -// Simple Usage: -// import( -// "github.com/cnlh/nps/vender/github.com/astaxie/beego" -// "github.com/cnlh/nps/vender/github.com/astaxie/beego/plugins/apiauth" -// ) -// -// func main(){ -// // apiauth every request -// beego.InsertFilter("*", beego.BeforeRouter,apiauth.APIBaiscAuth("appid","appkey")) -// beego.Run() -// } -// -// Advanced Usage: -// -// func getAppSecret(appid string) string { -// // get appsecret by appid -// // maybe store in configure, maybe in database -// } -// -// beego.InsertFilter("*", beego.BeforeRouter,apiauth.APISecretAuth(getAppSecret, 360)) -// -// Information: -// -// In the request user should include these params in the query -// -// 1. appid -// -// appid is assigned to the application -// -// 2. signature -// -// get the signature use apiauth.Signature() -// -// when you send to server remember use url.QueryEscape() -// -// 3. timestamp: -// -// send the request time, the format is yyyy-mm-dd HH:ii:ss -// -package apiauth - -import ( - "bytes" - "crypto/hmac" - "crypto/sha256" - "encoding/base64" - "fmt" - "net/url" - "sort" - "time" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" -) - -// AppIDToAppSecret is used to get appsecret throw appid -type AppIDToAppSecret func(string) string - -// APIBaiscAuth use the basic appid/appkey as the AppIdToAppSecret -func APIBaiscAuth(appid, appkey string) beego.FilterFunc { - ft := func(aid string) string { - if aid == appid { - return appkey - } - return "" - } - return APISecretAuth(ft, 300) -} - -// APISecretAuth use AppIdToAppSecret verify and -func APISecretAuth(f AppIDToAppSecret, timeout int) beego.FilterFunc { - return func(ctx *context.Context) { - if ctx.Input.Query("appid") == "" { - ctx.ResponseWriter.WriteHeader(403) - ctx.WriteString("miss query param: appid") - return - } - appsecret := f(ctx.Input.Query("appid")) - if appsecret == "" { - ctx.ResponseWriter.WriteHeader(403) - ctx.WriteString("not exist this appid") - return - } - if ctx.Input.Query("signature") == "" { - ctx.ResponseWriter.WriteHeader(403) - ctx.WriteString("miss query param: signature") - return - } - if ctx.Input.Query("timestamp") == "" { - ctx.ResponseWriter.WriteHeader(403) - ctx.WriteString("miss query param: timestamp") - return - } - u, err := time.Parse("2006-01-02 15:04:05", ctx.Input.Query("timestamp")) - if err != nil { - ctx.ResponseWriter.WriteHeader(403) - ctx.WriteString("timestamp format is error, should 2006-01-02 15:04:05") - return - } - t := time.Now() - if t.Sub(u).Seconds() > float64(timeout) { - ctx.ResponseWriter.WriteHeader(403) - ctx.WriteString("timeout! the request time is long ago, please try again") - return - } - if ctx.Input.Query("signature") != - Signature(appsecret, ctx.Input.Method(), ctx.Request.Form, ctx.Input.URL()) { - ctx.ResponseWriter.WriteHeader(403) - ctx.WriteString("auth failed") - } - } -} - -// Signature used to generate signature with the appsecret/method/params/RequestURI -func Signature(appsecret, method string, params url.Values, RequestURL string) (result string) { - var b bytes.Buffer - keys := make([]string, len(params)) - pa := make(map[string]string) - for k, v := range params { - pa[k] = v[0] - keys = append(keys, k) - } - - sort.Strings(keys) - - for _, key := range keys { - if key == "signature" { - continue - } - - val := pa[key] - if key != "" && val != "" { - b.WriteString(key) - b.WriteString(val) - } - } - - stringToSign := fmt.Sprintf("%v\n%v\n%v\n", method, b.String(), RequestURL) - - sha256 := sha256.New - hash := hmac.New(sha256, []byte(appsecret)) - hash.Write([]byte(stringToSign)) - return base64.StdEncoding.EncodeToString(hash.Sum(nil)) -} diff --git a/vender/github.com/astaxie/beego/plugins/apiauth/apiauth_test.go b/vender/github.com/astaxie/beego/plugins/apiauth/apiauth_test.go deleted file mode 100755 index 1f56cb0..0000000 --- a/vender/github.com/astaxie/beego/plugins/apiauth/apiauth_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package apiauth - -import ( - "net/url" - "testing" -) - -func TestSignature(t *testing.T) { - appsecret := "beego secret" - method := "GET" - RequestURL := "http://localhost/test/url" - params := make(url.Values) - params.Add("arg1", "hello") - params.Add("arg2", "beego") - - signature := "mFdpvLh48ca4mDVEItE9++AKKQ/IVca7O/ZyyB8hR58=" - if Signature(appsecret, method, params, RequestURL) != signature { - t.Error("Signature error") - } -} diff --git a/vender/github.com/astaxie/beego/plugins/auth/basic.go b/vender/github.com/astaxie/beego/plugins/auth/basic.go deleted file mode 100755 index 019163c..0000000 --- a/vender/github.com/astaxie/beego/plugins/auth/basic.go +++ /dev/null @@ -1,107 +0,0 @@ -// 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 auth provides handlers to enable basic auth support. -// Simple Usage: -// import( -// "github.com/cnlh/nps/vender/github.com/astaxie/beego" -// "github.com/cnlh/nps/vender/github.com/astaxie/beego/plugins/auth" -// ) -// -// func main(){ -// // authenticate every request -// beego.InsertFilter("*", beego.BeforeRouter,auth.Basic("username","secretpassword")) -// beego.Run() -// } -// -// -// Advanced Usage: -// -// func SecretAuth(username, password string) bool { -// return username == "astaxie" && password == "helloBeego" -// } -// authPlugin := auth.NewBasicAuthenticator(SecretAuth, "Authorization Required") -// beego.InsertFilter("*", beego.BeforeRouter,authPlugin) -package auth - -import ( - "encoding/base64" - "net/http" - "strings" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" -) - -var defaultRealm = "Authorization Required" - -// Basic is the http basic auth -func Basic(username string, password string) beego.FilterFunc { - secrets := func(user, pass string) bool { - return user == username && pass == password - } - return NewBasicAuthenticator(secrets, defaultRealm) -} - -// NewBasicAuthenticator return the BasicAuth -func NewBasicAuthenticator(secrets SecretProvider, Realm string) beego.FilterFunc { - return func(ctx *context.Context) { - a := &BasicAuth{Secrets: secrets, Realm: Realm} - if username := a.CheckAuth(ctx.Request); username == "" { - a.RequireAuth(ctx.ResponseWriter, ctx.Request) - } - } -} - -// SecretProvider is the SecretProvider function -type SecretProvider func(user, pass string) bool - -// BasicAuth store the SecretProvider and Realm -type BasicAuth struct { - Secrets SecretProvider - Realm string -} - -// CheckAuth Checks the username/password combination from the request. Returns -// either an empty string (authentication failed) or the name of the -// authenticated user. -// Supports MD5 and SHA1 password entries -func (a *BasicAuth) CheckAuth(r *http.Request) string { - s := strings.SplitN(r.Header.Get("Authorization"), " ", 2) - if len(s) != 2 || s[0] != "Basic" { - return "" - } - - b, err := base64.StdEncoding.DecodeString(s[1]) - if err != nil { - return "" - } - pair := strings.SplitN(string(b), ":", 2) - if len(pair) != 2 { - return "" - } - - if a.Secrets(pair[0], pair[1]) { - return pair[0] - } - return "" -} - -// RequireAuth http.Handler for BasicAuth which initiates the authentication process -// (or requires reauthentication). -func (a *BasicAuth) RequireAuth(w http.ResponseWriter, r *http.Request) { - w.Header().Set("WWW-Authenticate", `Basic realm="`+a.Realm+`"`) - w.WriteHeader(401) - w.Write([]byte("401 Unauthorized\n")) -} diff --git a/vender/github.com/astaxie/beego/plugins/authz/authz.go b/vender/github.com/astaxie/beego/plugins/authz/authz.go deleted file mode 100755 index 0504e14..0000000 --- a/vender/github.com/astaxie/beego/plugins/authz/authz.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2014 beego Author. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package authz provides handlers to enable ACL, RBAC, ABAC authorization support. -// Simple Usage: -// import( -// "github.com/cnlh/nps/vender/github.com/astaxie/beego" -// "github.com/cnlh/nps/vender/github.com/astaxie/beego/plugins/authz" -// "github.com/casbin/casbin" -// ) -// -// func main(){ -// // mediate the access for every request -// beego.InsertFilter("*", beego.BeforeRouter, authz.NewAuthorizer(casbin.NewEnforcer("authz_model.conf", "authz_policy.csv"))) -// beego.Run() -// } -// -// -// Advanced Usage: -// -// func main(){ -// e := casbin.NewEnforcer("authz_model.conf", "") -// e.AddRoleForUser("alice", "admin") -// e.AddPolicy(...) -// -// beego.InsertFilter("*", beego.BeforeRouter, authz.NewAuthorizer(e)) -// beego.Run() -// } -package authz - -import ( - "github.com/casbin/casbin" - "github.com/cnlh/nps/vender/github.com/astaxie/beego" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" - "net/http" -) - -// NewAuthorizer returns the authorizer. -// Use a casbin enforcer as input -func NewAuthorizer(e *casbin.Enforcer) beego.FilterFunc { - return func(ctx *context.Context) { - a := &BasicAuthorizer{enforcer: e} - - if !a.CheckPermission(ctx.Request) { - a.RequirePermission(ctx.ResponseWriter) - } - } -} - -// BasicAuthorizer stores the casbin handler -type BasicAuthorizer struct { - enforcer *casbin.Enforcer -} - -// GetUserName gets the user name from the request. -// Currently, only HTTP basic authentication is supported -func (a *BasicAuthorizer) GetUserName(r *http.Request) string { - username, _, _ := r.BasicAuth() - return username -} - -// CheckPermission checks the user/method/path combination from the request. -// Returns true (permission granted) or false (permission forbidden) -func (a *BasicAuthorizer) CheckPermission(r *http.Request) bool { - user := a.GetUserName(r) - method := r.Method - path := r.URL.Path - return a.enforcer.Enforce(user, path, method) -} - -// RequirePermission returns the 403 Forbidden to the client -func (a *BasicAuthorizer) RequirePermission(w http.ResponseWriter) { - w.WriteHeader(403) - w.Write([]byte("403 Forbidden\n")) -} diff --git a/vender/github.com/astaxie/beego/plugins/authz/authz_model.conf b/vender/github.com/astaxie/beego/plugins/authz/authz_model.conf deleted file mode 100755 index d1b3dbd..0000000 --- a/vender/github.com/astaxie/beego/plugins/authz/authz_model.conf +++ /dev/null @@ -1,14 +0,0 @@ -[request_definition] -r = sub, obj, act - -[policy_definition] -p = sub, obj, act - -[role_definition] -g = _, _ - -[policy_effect] -e = some(where (p.eft == allow)) - -[matchers] -m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*") \ No newline at end of file diff --git a/vender/github.com/astaxie/beego/plugins/authz/authz_policy.csv b/vender/github.com/astaxie/beego/plugins/authz/authz_policy.csv deleted file mode 100755 index c062dd3..0000000 --- a/vender/github.com/astaxie/beego/plugins/authz/authz_policy.csv +++ /dev/null @@ -1,7 +0,0 @@ -p, alice, /dataset1/*, GET -p, alice, /dataset1/resource1, POST -p, bob, /dataset2/resource1, * -p, bob, /dataset2/resource2, GET -p, bob, /dataset2/folder1/*, POST -p, dataset1_admin, /dataset1/*, * -g, cathy, dataset1_admin \ No newline at end of file diff --git a/vender/github.com/astaxie/beego/plugins/authz/authz_test.go b/vender/github.com/astaxie/beego/plugins/authz/authz_test.go deleted file mode 100755 index c4048e9..0000000 --- a/vender/github.com/astaxie/beego/plugins/authz/authz_test.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2014 beego Author. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package authz - -import ( - "github.com/casbin/casbin" - "github.com/cnlh/nps/vender/github.com/astaxie/beego" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/plugins/auth" - "net/http" - "net/http/httptest" - "testing" -) - -func testRequest(t *testing.T, handler *beego.ControllerRegister, user string, path string, method string, code int) { - r, _ := http.NewRequest(method, path, nil) - r.SetBasicAuth(user, "123") - w := httptest.NewRecorder() - handler.ServeHTTP(w, r) - - if w.Code != code { - t.Errorf("%s, %s, %s: %d, supposed to be %d", user, path, method, w.Code, code) - } -} - -func TestBasic(t *testing.T) { - handler := beego.NewControllerRegister() - - handler.InsertFilter("*", beego.BeforeRouter, auth.Basic("alice", "123")) - handler.InsertFilter("*", beego.BeforeRouter, NewAuthorizer(casbin.NewEnforcer("authz_model.conf", "authz_policy.csv"))) - - handler.Any("*", func(ctx *context.Context) { - ctx.Output.SetStatus(200) - }) - - testRequest(t, handler, "alice", "/dataset1/resource1", "GET", 200) - testRequest(t, handler, "alice", "/dataset1/resource1", "POST", 200) - testRequest(t, handler, "alice", "/dataset1/resource2", "GET", 200) - testRequest(t, handler, "alice", "/dataset1/resource2", "POST", 403) -} - -func TestPathWildcard(t *testing.T) { - handler := beego.NewControllerRegister() - - handler.InsertFilter("*", beego.BeforeRouter, auth.Basic("bob", "123")) - handler.InsertFilter("*", beego.BeforeRouter, NewAuthorizer(casbin.NewEnforcer("authz_model.conf", "authz_policy.csv"))) - - handler.Any("*", func(ctx *context.Context) { - ctx.Output.SetStatus(200) - }) - - testRequest(t, handler, "bob", "/dataset2/resource1", "GET", 200) - testRequest(t, handler, "bob", "/dataset2/resource1", "POST", 200) - testRequest(t, handler, "bob", "/dataset2/resource1", "DELETE", 200) - testRequest(t, handler, "bob", "/dataset2/resource2", "GET", 200) - testRequest(t, handler, "bob", "/dataset2/resource2", "POST", 403) - testRequest(t, handler, "bob", "/dataset2/resource2", "DELETE", 403) - - testRequest(t, handler, "bob", "/dataset2/folder1/item1", "GET", 403) - testRequest(t, handler, "bob", "/dataset2/folder1/item1", "POST", 200) - testRequest(t, handler, "bob", "/dataset2/folder1/item1", "DELETE", 403) - testRequest(t, handler, "bob", "/dataset2/folder1/item2", "GET", 403) - testRequest(t, handler, "bob", "/dataset2/folder1/item2", "POST", 200) - testRequest(t, handler, "bob", "/dataset2/folder1/item2", "DELETE", 403) -} - -func TestRBAC(t *testing.T) { - handler := beego.NewControllerRegister() - - handler.InsertFilter("*", beego.BeforeRouter, auth.Basic("cathy", "123")) - e := casbin.NewEnforcer("authz_model.conf", "authz_policy.csv") - handler.InsertFilter("*", beego.BeforeRouter, NewAuthorizer(e)) - - handler.Any("*", func(ctx *context.Context) { - ctx.Output.SetStatus(200) - }) - - // cathy can access all /dataset1/* resources via all methods because it has the dataset1_admin role. - testRequest(t, handler, "cathy", "/dataset1/item", "GET", 200) - testRequest(t, handler, "cathy", "/dataset1/item", "POST", 200) - testRequest(t, handler, "cathy", "/dataset1/item", "DELETE", 200) - testRequest(t, handler, "cathy", "/dataset2/item", "GET", 403) - testRequest(t, handler, "cathy", "/dataset2/item", "POST", 403) - testRequest(t, handler, "cathy", "/dataset2/item", "DELETE", 403) - - // delete all roles on user cathy, so cathy cannot access any resources now. - e.DeleteRolesForUser("cathy") - - testRequest(t, handler, "cathy", "/dataset1/item", "GET", 403) - testRequest(t, handler, "cathy", "/dataset1/item", "POST", 403) - testRequest(t, handler, "cathy", "/dataset1/item", "DELETE", 403) - testRequest(t, handler, "cathy", "/dataset2/item", "GET", 403) - testRequest(t, handler, "cathy", "/dataset2/item", "POST", 403) - testRequest(t, handler, "cathy", "/dataset2/item", "DELETE", 403) -} diff --git a/vender/github.com/astaxie/beego/plugins/cors/cors.go b/vender/github.com/astaxie/beego/plugins/cors/cors.go deleted file mode 100755 index cc12c1f..0000000 --- a/vender/github.com/astaxie/beego/plugins/cors/cors.go +++ /dev/null @@ -1,228 +0,0 @@ -// 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 cors provides handlers to enable CORS support. -// Usage -// import ( -// "github.com/cnlh/nps/vender/github.com/astaxie/beego" -// "github.com/cnlh/nps/vender/github.com/astaxie/beego/plugins/cors" -// ) -// -// func main() { -// // CORS for https://foo.* origins, allowing: -// // - PUT and PATCH methods -// // - Origin header -// // - Credentials share -// beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{ -// AllowOrigins: []string{"https://*.foo.com"}, -// AllowMethods: []string{"PUT", "PATCH"}, -// AllowHeaders: []string{"Origin"}, -// ExposeHeaders: []string{"Content-Length"}, -// AllowCredentials: true, -// })) -// beego.Run() -// } -package cors - -import ( - "net/http" - "regexp" - "strconv" - "strings" - "time" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" -) - -const ( - headerAllowOrigin = "Access-Control-Allow-Origin" - headerAllowCredentials = "Access-Control-Allow-Credentials" - headerAllowHeaders = "Access-Control-Allow-Headers" - headerAllowMethods = "Access-Control-Allow-Methods" - headerExposeHeaders = "Access-Control-Expose-Headers" - headerMaxAge = "Access-Control-Max-Age" - - headerOrigin = "Origin" - headerRequestMethod = "Access-Control-Request-Method" - headerRequestHeaders = "Access-Control-Request-Headers" -) - -var ( - defaultAllowHeaders = []string{"Origin", "Accept", "Content-Type", "Authorization"} - // Regex patterns are generated from AllowOrigins. These are used and generated internally. - allowOriginPatterns = []string{} -) - -// Options represents Access Control options. -type Options struct { - // If set, all origins are allowed. - AllowAllOrigins bool - // A list of allowed origins. Wild cards and FQDNs are supported. - AllowOrigins []string - // If set, allows to share auth credentials such as cookies. - AllowCredentials bool - // A list of allowed HTTP methods. - AllowMethods []string - // A list of allowed HTTP headers. - AllowHeaders []string - // A list of exposed HTTP headers. - ExposeHeaders []string - // Max age of the CORS headers. - MaxAge time.Duration -} - -// Header converts options into CORS headers. -func (o *Options) Header(origin string) (headers map[string]string) { - headers = make(map[string]string) - // if origin is not allowed, don't extend the headers - // with CORS headers. - if !o.AllowAllOrigins && !o.IsOriginAllowed(origin) { - return - } - - // add allow origin - if o.AllowAllOrigins { - headers[headerAllowOrigin] = "*" - } else { - headers[headerAllowOrigin] = origin - } - - // add allow credentials - headers[headerAllowCredentials] = strconv.FormatBool(o.AllowCredentials) - - // add allow methods - if len(o.AllowMethods) > 0 { - headers[headerAllowMethods] = strings.Join(o.AllowMethods, ",") - } - - // add allow headers - if len(o.AllowHeaders) > 0 { - headers[headerAllowHeaders] = strings.Join(o.AllowHeaders, ",") - } - - // add exposed header - if len(o.ExposeHeaders) > 0 { - headers[headerExposeHeaders] = strings.Join(o.ExposeHeaders, ",") - } - // add a max age header - if o.MaxAge > time.Duration(0) { - headers[headerMaxAge] = strconv.FormatInt(int64(o.MaxAge/time.Second), 10) - } - return -} - -// PreflightHeader converts options into CORS headers for a preflight response. -func (o *Options) PreflightHeader(origin, rMethod, rHeaders string) (headers map[string]string) { - headers = make(map[string]string) - if !o.AllowAllOrigins && !o.IsOriginAllowed(origin) { - return - } - // verify if requested method is allowed - for _, method := range o.AllowMethods { - if method == rMethod { - headers[headerAllowMethods] = strings.Join(o.AllowMethods, ",") - break - } - } - - // verify if requested headers are allowed - var allowed []string - for _, rHeader := range strings.Split(rHeaders, ",") { - rHeader = strings.TrimSpace(rHeader) - lookupLoop: - for _, allowedHeader := range o.AllowHeaders { - if strings.ToLower(rHeader) == strings.ToLower(allowedHeader) { - allowed = append(allowed, rHeader) - break lookupLoop - } - } - } - - headers[headerAllowCredentials] = strconv.FormatBool(o.AllowCredentials) - // add allow origin - if o.AllowAllOrigins { - headers[headerAllowOrigin] = "*" - } else { - headers[headerAllowOrigin] = origin - } - - // add allowed headers - if len(allowed) > 0 { - headers[headerAllowHeaders] = strings.Join(allowed, ",") - } - - // add exposed headers - if len(o.ExposeHeaders) > 0 { - headers[headerExposeHeaders] = strings.Join(o.ExposeHeaders, ",") - } - // add a max age header - if o.MaxAge > time.Duration(0) { - headers[headerMaxAge] = strconv.FormatInt(int64(o.MaxAge/time.Second), 10) - } - return -} - -// IsOriginAllowed looks up if the origin matches one of the patterns -// generated from Options.AllowOrigins patterns. -func (o *Options) IsOriginAllowed(origin string) (allowed bool) { - for _, pattern := range allowOriginPatterns { - allowed, _ = regexp.MatchString(pattern, origin) - if allowed { - return - } - } - return -} - -// Allow enables CORS for requests those match the provided options. -func Allow(opts *Options) beego.FilterFunc { - // Allow default headers if nothing is specified. - if len(opts.AllowHeaders) == 0 { - opts.AllowHeaders = defaultAllowHeaders - } - - for _, origin := range opts.AllowOrigins { - pattern := regexp.QuoteMeta(origin) - pattern = strings.Replace(pattern, "\\*", ".*", -1) - pattern = strings.Replace(pattern, "\\?", ".", -1) - allowOriginPatterns = append(allowOriginPatterns, "^"+pattern+"$") - } - - return func(ctx *context.Context) { - var ( - origin = ctx.Input.Header(headerOrigin) - requestedMethod = ctx.Input.Header(headerRequestMethod) - requestedHeaders = ctx.Input.Header(headerRequestHeaders) - // additional headers to be added - // to the response. - headers map[string]string - ) - - if ctx.Input.Method() == "OPTIONS" && - (requestedMethod != "" || requestedHeaders != "") { - headers = opts.PreflightHeader(origin, requestedMethod, requestedHeaders) - for key, value := range headers { - ctx.Output.Header(key, value) - } - ctx.ResponseWriter.WriteHeader(http.StatusOK) - return - } - headers = opts.Header(origin) - - for key, value := range headers { - ctx.Output.Header(key, value) - } - } -} diff --git a/vender/github.com/astaxie/beego/plugins/cors/cors_test.go b/vender/github.com/astaxie/beego/plugins/cors/cors_test.go deleted file mode 100755 index 49fbc4d..0000000 --- a/vender/github.com/astaxie/beego/plugins/cors/cors_test.go +++ /dev/null @@ -1,253 +0,0 @@ -// 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 cors - -import ( - "net/http" - "net/http/httptest" - "strings" - "testing" - "time" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" -) - -// HTTPHeaderGuardRecorder is httptest.ResponseRecorder with own http.Header -type HTTPHeaderGuardRecorder struct { - *httptest.ResponseRecorder - savedHeaderMap http.Header -} - -// NewRecorder return HttpHeaderGuardRecorder -func NewRecorder() *HTTPHeaderGuardRecorder { - return &HTTPHeaderGuardRecorder{httptest.NewRecorder(), nil} -} - -func (gr *HTTPHeaderGuardRecorder) WriteHeader(code int) { - gr.ResponseRecorder.WriteHeader(code) - gr.savedHeaderMap = gr.ResponseRecorder.Header() -} - -func (gr *HTTPHeaderGuardRecorder) Header() http.Header { - if gr.savedHeaderMap != nil { - // headers were written. clone so we don't get updates - clone := make(http.Header) - for k, v := range gr.savedHeaderMap { - clone[k] = v - } - return clone - } - return gr.ResponseRecorder.Header() -} - -func Test_AllowAll(t *testing.T) { - recorder := httptest.NewRecorder() - handler := beego.NewControllerRegister() - handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{ - AllowAllOrigins: true, - })) - handler.Any("/foo", func(ctx *context.Context) { - ctx.Output.SetStatus(500) - }) - r, _ := http.NewRequest("PUT", "/foo", nil) - handler.ServeHTTP(recorder, r) - - if recorder.HeaderMap.Get(headerAllowOrigin) != "*" { - t.Errorf("Allow-Origin header should be *") - } -} - -func Test_AllowRegexMatch(t *testing.T) { - recorder := httptest.NewRecorder() - handler := beego.NewControllerRegister() - handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{ - AllowOrigins: []string{"https://aaa.com", "https://*.foo.com"}, - })) - handler.Any("/foo", func(ctx *context.Context) { - ctx.Output.SetStatus(500) - }) - origin := "https://bar.foo.com" - r, _ := http.NewRequest("PUT", "/foo", nil) - r.Header.Add("Origin", origin) - handler.ServeHTTP(recorder, r) - - headerValue := recorder.HeaderMap.Get(headerAllowOrigin) - if headerValue != origin { - t.Errorf("Allow-Origin header should be %v, found %v", origin, headerValue) - } -} - -func Test_AllowRegexNoMatch(t *testing.T) { - recorder := httptest.NewRecorder() - handler := beego.NewControllerRegister() - handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{ - AllowOrigins: []string{"https://*.foo.com"}, - })) - handler.Any("/foo", func(ctx *context.Context) { - ctx.Output.SetStatus(500) - }) - origin := "https://ww.foo.com.evil.com" - r, _ := http.NewRequest("PUT", "/foo", nil) - r.Header.Add("Origin", origin) - handler.ServeHTTP(recorder, r) - - headerValue := recorder.HeaderMap.Get(headerAllowOrigin) - if headerValue != "" { - t.Errorf("Allow-Origin header should not exist, found %v", headerValue) - } -} - -func Test_OtherHeaders(t *testing.T) { - recorder := httptest.NewRecorder() - handler := beego.NewControllerRegister() - handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{ - AllowAllOrigins: true, - AllowCredentials: true, - AllowMethods: []string{"PATCH", "GET"}, - AllowHeaders: []string{"Origin", "X-whatever"}, - ExposeHeaders: []string{"Content-Length", "Hello"}, - MaxAge: 5 * time.Minute, - })) - handler.Any("/foo", func(ctx *context.Context) { - ctx.Output.SetStatus(500) - }) - r, _ := http.NewRequest("PUT", "/foo", nil) - handler.ServeHTTP(recorder, r) - - credentialsVal := recorder.HeaderMap.Get(headerAllowCredentials) - methodsVal := recorder.HeaderMap.Get(headerAllowMethods) - headersVal := recorder.HeaderMap.Get(headerAllowHeaders) - exposedHeadersVal := recorder.HeaderMap.Get(headerExposeHeaders) - maxAgeVal := recorder.HeaderMap.Get(headerMaxAge) - - if credentialsVal != "true" { - t.Errorf("Allow-Credentials is expected to be true, found %v", credentialsVal) - } - - if methodsVal != "PATCH,GET" { - t.Errorf("Allow-Methods is expected to be PATCH,GET; found %v", methodsVal) - } - - if headersVal != "Origin,X-whatever" { - t.Errorf("Allow-Headers is expected to be Origin,X-whatever; found %v", headersVal) - } - - if exposedHeadersVal != "Content-Length,Hello" { - t.Errorf("Expose-Headers are expected to be Content-Length,Hello. Found %v", exposedHeadersVal) - } - - if maxAgeVal != "300" { - t.Errorf("Max-Age is expected to be 300, found %v", maxAgeVal) - } -} - -func Test_DefaultAllowHeaders(t *testing.T) { - recorder := httptest.NewRecorder() - handler := beego.NewControllerRegister() - handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{ - AllowAllOrigins: true, - })) - handler.Any("/foo", func(ctx *context.Context) { - ctx.Output.SetStatus(500) - }) - - r, _ := http.NewRequest("PUT", "/foo", nil) - handler.ServeHTTP(recorder, r) - - headersVal := recorder.HeaderMap.Get(headerAllowHeaders) - if headersVal != "Origin,Accept,Content-Type,Authorization" { - t.Errorf("Allow-Headers is expected to be Origin,Accept,Content-Type,Authorization; found %v", headersVal) - } -} - -func Test_Preflight(t *testing.T) { - recorder := NewRecorder() - handler := beego.NewControllerRegister() - handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{ - AllowAllOrigins: true, - AllowMethods: []string{"PUT", "PATCH"}, - AllowHeaders: []string{"Origin", "X-whatever", "X-CaseSensitive"}, - })) - - handler.Any("/foo", func(ctx *context.Context) { - ctx.Output.SetStatus(200) - }) - - r, _ := http.NewRequest("OPTIONS", "/foo", nil) - r.Header.Add(headerRequestMethod, "PUT") - r.Header.Add(headerRequestHeaders, "X-whatever, x-casesensitive") - handler.ServeHTTP(recorder, r) - - headers := recorder.Header() - methodsVal := headers.Get(headerAllowMethods) - headersVal := headers.Get(headerAllowHeaders) - originVal := headers.Get(headerAllowOrigin) - - if methodsVal != "PUT,PATCH" { - t.Errorf("Allow-Methods is expected to be PUT,PATCH, found %v", methodsVal) - } - - if !strings.Contains(headersVal, "X-whatever") { - t.Errorf("Allow-Headers is expected to contain X-whatever, found %v", headersVal) - } - - if !strings.Contains(headersVal, "x-casesensitive") { - t.Errorf("Allow-Headers is expected to contain x-casesensitive, found %v", headersVal) - } - - if originVal != "*" { - t.Errorf("Allow-Origin is expected to be *, found %v", originVal) - } - - if recorder.Code != http.StatusOK { - t.Errorf("Status code is expected to be 200, found %d", recorder.Code) - } -} - -func Benchmark_WithoutCORS(b *testing.B) { - recorder := httptest.NewRecorder() - handler := beego.NewControllerRegister() - beego.BConfig.RunMode = beego.PROD - handler.Any("/foo", func(ctx *context.Context) { - ctx.Output.SetStatus(500) - }) - b.ResetTimer() - r, _ := http.NewRequest("PUT", "/foo", nil) - for i := 0; i < b.N; i++ { - handler.ServeHTTP(recorder, r) - } -} - -func Benchmark_WithCORS(b *testing.B) { - recorder := httptest.NewRecorder() - handler := beego.NewControllerRegister() - beego.BConfig.RunMode = beego.PROD - handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{ - AllowAllOrigins: true, - AllowCredentials: true, - AllowMethods: []string{"PATCH", "GET"}, - AllowHeaders: []string{"Origin", "X-whatever"}, - MaxAge: 5 * time.Minute, - })) - handler.Any("/foo", func(ctx *context.Context) { - ctx.Output.SetStatus(500) - }) - b.ResetTimer() - r, _ := http.NewRequest("PUT", "/foo", nil) - for i := 0; i < b.N; i++ { - handler.ServeHTTP(recorder, r) - } -} diff --git a/vender/github.com/astaxie/beego/policy.go b/vender/github.com/astaxie/beego/policy.go deleted file mode 100755 index 70bcbbf..0000000 --- a/vender/github.com/astaxie/beego/policy.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2016 beego authors. 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/cnlh/nps/vender/github.com/astaxie/beego/context" -) - -// PolicyFunc defines a policy function which is invoked before the controller handler is executed. -type PolicyFunc func(*context.Context) - -// FindPolicy Find Router info for URL -func (p *ControllerRegister) FindPolicy(cont *context.Context) []PolicyFunc { - var urlPath = cont.Input.URL() - if !BConfig.RouterCaseSensitive { - urlPath = strings.ToLower(urlPath) - } - httpMethod := cont.Input.Method() - isWildcard := false - // Find policy for current method - t, ok := p.policies[httpMethod] - // If not found - find policy for whole controller - if !ok { - t, ok = p.policies["*"] - isWildcard = true - } - if ok { - runObjects := t.Match(urlPath, cont) - if r, ok := runObjects.([]PolicyFunc); ok { - return r - } else if !isWildcard { - // If no policies found and we checked not for "*" method - try to find it - t, ok = p.policies["*"] - if ok { - runObjects = t.Match(urlPath, cont) - if r, ok = runObjects.([]PolicyFunc); ok { - return r - } - } - } - } - return nil -} - -func (p *ControllerRegister) addToPolicy(method, pattern string, r ...PolicyFunc) { - method = strings.ToUpper(method) - p.enablePolicy = true - if !BConfig.RouterCaseSensitive { - pattern = strings.ToLower(pattern) - } - if t, ok := p.policies[method]; ok { - t.AddRouter(pattern, r) - } else { - t := NewTree() - t.AddRouter(pattern, r) - p.policies[method] = t - } -} - -// Policy Register new policy in beego -func Policy(pattern, method string, policy ...PolicyFunc) { - BeeApp.Handlers.addToPolicy(method, pattern, policy...) -} - -// Find policies and execute if were found -func (p *ControllerRegister) execPolicy(cont *context.Context, urlPath string) (started bool) { - if !p.enablePolicy { - return false - } - // Find Policy for method - policyList := p.FindPolicy(cont) - if len(policyList) > 0 { - // Run policies - for _, runPolicy := range policyList { - runPolicy(cont) - if cont.ResponseWriter.Started { - return true - } - } - return false - } - return false -} diff --git a/vender/github.com/astaxie/beego/router.go b/vender/github.com/astaxie/beego/router.go deleted file mode 100755 index cdbfd6e..0000000 --- a/vender/github.com/astaxie/beego/router.go +++ /dev/null @@ -1,1015 +0,0 @@ -// 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/http" - "path" - "path/filepath" - "reflect" - "runtime" - "strconv" - "strings" - "sync" - "time" - - beecontext "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context/param" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/toolbox" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/utils" -) - -// default filter execution points -const ( - BeforeStatic = iota - BeforeRouter - BeforeExec - AfterExec - FinishRouter -) - -const ( - routerTypeBeego = iota - routerTypeRESTFul - routerTypeHandler -) - -var ( - // HTTPMETHOD list the supported http methods. - HTTPMETHOD = map[string]bool{ - "GET": true, - "POST": true, - "PUT": true, - "DELETE": true, - "PATCH": true, - "OPTIONS": true, - "HEAD": true, - "TRACE": true, - "CONNECT": true, - "MKCOL": true, - "COPY": true, - "MOVE": true, - "PROPFIND": true, - "PROPPATCH": true, - "LOCK": true, - "UNLOCK": true, - } - // these beego.Controller's methods shouldn't reflect to AutoRouter - exceptMethod = []string{"Init", "Prepare", "Finish", "Render", "RenderString", - "RenderBytes", "Redirect", "Abort", "StopRun", "UrlFor", "ServeJSON", "ServeJSONP", - "ServeYAML", "ServeXML", "Input", "ParseForm", "GetString", "GetStrings", "GetInt", "GetBool", - "GetFloat", "GetFile", "SaveToFile", "StartSession", "SetSession", "GetSession", - "DelSession", "SessionRegenerateID", "DestroySession", "IsAjax", "GetSecureCookie", - "SetSecureCookie", "XsrfToken", "CheckXsrfCookie", "XsrfFormHtml", - "GetControllerAndAction", "ServeFormatted"} - - urlPlaceholder = "{{placeholder}}" - // DefaultAccessLogFilter will skip the accesslog if return true - DefaultAccessLogFilter FilterHandler = &logFilter{} -) - -// FilterHandler is an interface for -type FilterHandler interface { - Filter(*beecontext.Context) bool -} - -// default log filter static file will not show -type logFilter struct { -} - -func (l *logFilter) Filter(ctx *beecontext.Context) bool { - requestPath := path.Clean(ctx.Request.URL.Path) - if requestPath == "/favicon.ico" || requestPath == "/robots.txt" { - return true - } - for prefix := range BConfig.WebConfig.StaticDir { - if strings.HasPrefix(requestPath, prefix) { - return true - } - } - return false -} - -// ExceptMethodAppend to append a slice's value into "exceptMethod", for controller's methods shouldn't reflect to AutoRouter -func ExceptMethodAppend(action string) { - exceptMethod = append(exceptMethod, action) -} - -// ControllerInfo holds information about the controller. -type ControllerInfo struct { - pattern string - controllerType reflect.Type - methods map[string]string - handler http.Handler - runFunction FilterFunc - routerType int - initialize func() ControllerInterface - methodParams []*param.MethodParam -} - -// ControllerRegister containers registered router rules, controller handlers and filters. -type ControllerRegister struct { - routers map[string]*Tree - enablePolicy bool - policies map[string]*Tree - enableFilter bool - filters [FinishRouter + 1][]*FilterRouter - pool sync.Pool -} - -// NewControllerRegister returns a new ControllerRegister. -func NewControllerRegister() *ControllerRegister { - cr := &ControllerRegister{ - routers: make(map[string]*Tree), - policies: make(map[string]*Tree), - } - cr.pool.New = func() interface{} { - return beecontext.NewContext() - } - return cr -} - -// Add controller handler and pattern rules to ControllerRegister. -// usage: -// default methods is the same name as method -// Add("/user",&UserController{}) -// Add("/api/list",&RestController{},"*:ListFood") -// Add("/api/create",&RestController{},"post:CreateFood") -// Add("/api/update",&RestController{},"put:UpdateFood") -// Add("/api/delete",&RestController{},"delete:DeleteFood") -// Add("/api",&RestController{},"get,post:ApiFunc" -// Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc") -func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingMethods ...string) { - p.addWithMethodParams(pattern, c, nil, mappingMethods...) -} - -func (p *ControllerRegister) addWithMethodParams(pattern string, c ControllerInterface, methodParams []*param.MethodParam, mappingMethods ...string) { - reflectVal := reflect.ValueOf(c) - t := reflect.Indirect(reflectVal).Type() - methods := make(map[string]string) - if len(mappingMethods) > 0 { - semi := strings.Split(mappingMethods[0], ";") - for _, v := range semi { - colon := strings.Split(v, ":") - if len(colon) != 2 { - panic("method mapping format is invalid") - } - comma := strings.Split(colon[0], ",") - for _, m := range comma { - if m == "*" || HTTPMETHOD[strings.ToUpper(m)] { - if val := reflectVal.MethodByName(colon[1]); val.IsValid() { - methods[strings.ToUpper(m)] = colon[1] - } else { - panic("'" + colon[1] + "' method doesn't exist in the controller " + t.Name()) - } - } else { - panic(v + " is an invalid method mapping. Method doesn't exist " + m) - } - } - } - } - - route := &ControllerInfo{} - route.pattern = pattern - route.methods = methods - route.routerType = routerTypeBeego - route.controllerType = t - route.initialize = func() ControllerInterface { - vc := reflect.New(route.controllerType) - execController, ok := vc.Interface().(ControllerInterface) - if !ok { - panic("controller is not ControllerInterface") - } - - elemVal := reflect.ValueOf(c).Elem() - elemType := reflect.TypeOf(c).Elem() - execElem := reflect.ValueOf(execController).Elem() - - numOfFields := elemVal.NumField() - for i := 0; i < numOfFields; i++ { - fieldType := elemType.Field(i) - elemField := execElem.FieldByName(fieldType.Name) - if elemField.CanSet() { - fieldVal := elemVal.Field(i) - elemField.Set(fieldVal) - } - } - - return execController - } - - route.methodParams = methodParams - if len(methods) == 0 { - for m := range HTTPMETHOD { - p.addToRouter(m, pattern, route) - } - } else { - for k := range methods { - if k == "*" { - for m := range HTTPMETHOD { - p.addToRouter(m, pattern, route) - } - } else { - p.addToRouter(k, pattern, route) - } - } - } -} - -func (p *ControllerRegister) addToRouter(method, pattern string, r *ControllerInfo) { - if !BConfig.RouterCaseSensitive { - pattern = strings.ToLower(pattern) - } - if t, ok := p.routers[method]; ok { - t.AddRouter(pattern, r) - } else { - t := NewTree() - t.AddRouter(pattern, r) - p.routers[method] = t - } -} - -// Include only when the Runmode is dev will generate router file in the router/auto.go from the controller -// Include(&BankAccount{}, &OrderController{},&RefundController{},&ReceiptController{}) -func (p *ControllerRegister) Include(cList ...ControllerInterface) { - if BConfig.RunMode == DEV { - skip := make(map[string]bool, 10) - for _, c := range cList { - reflectVal := reflect.ValueOf(c) - t := reflect.Indirect(reflectVal).Type() - wgopath := utils.GetGOPATHs() - if len(wgopath) == 0 { - panic("you are in dev mode. So please set gopath") - } - pkgpath := "" - for _, wg := range wgopath { - wg, _ = filepath.EvalSymlinks(filepath.Join(wg, "src", t.PkgPath())) - if utils.FileExists(wg) { - pkgpath = wg - break - } - } - if pkgpath != "" { - if _, ok := skip[pkgpath]; !ok { - skip[pkgpath] = true - parserPkg(pkgpath, t.PkgPath()) - } - } - } - } - for _, c := range cList { - reflectVal := reflect.ValueOf(c) - t := reflect.Indirect(reflectVal).Type() - key := t.PkgPath() + ":" + t.Name() - if comm, ok := GlobalControllerRouter[key]; ok { - for _, a := range comm { - for _, f := range a.Filters { - p.InsertFilter(f.Pattern, f.Pos, f.Filter, f.ReturnOnOutput, f.ResetParams) - } - - p.addWithMethodParams(a.Router, c, a.MethodParams, strings.Join(a.AllowHTTPMethods, ",")+":"+a.Method) - } - } - } -} - -// Get add get method -// usage: -// Get("/", func(ctx *context.Context){ -// ctx.Output.Body("hello world") -// }) -func (p *ControllerRegister) Get(pattern string, f FilterFunc) { - p.AddMethod("get", pattern, f) -} - -// Post add post method -// usage: -// Post("/api", func(ctx *context.Context){ -// ctx.Output.Body("hello world") -// }) -func (p *ControllerRegister) Post(pattern string, f FilterFunc) { - p.AddMethod("post", pattern, f) -} - -// Put add put method -// usage: -// Put("/api/:id", func(ctx *context.Context){ -// ctx.Output.Body("hello world") -// }) -func (p *ControllerRegister) Put(pattern string, f FilterFunc) { - p.AddMethod("put", pattern, f) -} - -// Delete add delete method -// usage: -// Delete("/api/:id", func(ctx *context.Context){ -// ctx.Output.Body("hello world") -// }) -func (p *ControllerRegister) Delete(pattern string, f FilterFunc) { - p.AddMethod("delete", pattern, f) -} - -// Head add head method -// usage: -// Head("/api/:id", func(ctx *context.Context){ -// ctx.Output.Body("hello world") -// }) -func (p *ControllerRegister) Head(pattern string, f FilterFunc) { - p.AddMethod("head", pattern, f) -} - -// Patch add patch method -// usage: -// Patch("/api/:id", func(ctx *context.Context){ -// ctx.Output.Body("hello world") -// }) -func (p *ControllerRegister) Patch(pattern string, f FilterFunc) { - p.AddMethod("patch", pattern, f) -} - -// Options add options method -// usage: -// Options("/api/:id", func(ctx *context.Context){ -// ctx.Output.Body("hello world") -// }) -func (p *ControllerRegister) Options(pattern string, f FilterFunc) { - p.AddMethod("options", pattern, f) -} - -// Any add all method -// usage: -// Any("/api/:id", func(ctx *context.Context){ -// ctx.Output.Body("hello world") -// }) -func (p *ControllerRegister) Any(pattern string, f FilterFunc) { - p.AddMethod("*", pattern, f) -} - -// AddMethod add http method router -// usage: -// AddMethod("get","/api/:id", func(ctx *context.Context){ -// ctx.Output.Body("hello world") -// }) -func (p *ControllerRegister) AddMethod(method, pattern string, f FilterFunc) { - method = strings.ToUpper(method) - if method != "*" && !HTTPMETHOD[method] { - panic("not support http method: " + method) - } - route := &ControllerInfo{} - route.pattern = pattern - route.routerType = routerTypeRESTFul - route.runFunction = f - methods := make(map[string]string) - if method == "*" { - for val := range HTTPMETHOD { - methods[val] = val - } - } else { - methods[method] = method - } - route.methods = methods - for k := range methods { - if k == "*" { - for m := range HTTPMETHOD { - p.addToRouter(m, pattern, route) - } - } else { - p.addToRouter(k, pattern, route) - } - } -} - -// Handler add user defined Handler -func (p *ControllerRegister) Handler(pattern string, h http.Handler, options ...interface{}) { - route := &ControllerInfo{} - route.pattern = pattern - route.routerType = routerTypeHandler - route.handler = h - if len(options) > 0 { - if _, ok := options[0].(bool); ok { - pattern = path.Join(pattern, "?:all(.*)") - } - } - for m := range HTTPMETHOD { - p.addToRouter(m, pattern, route) - } -} - -// AddAuto router to ControllerRegister. -// example beego.AddAuto(&MainContorlller{}), -// MainController has method List and Page. -// visit the url /main/list to execute List function -// /main/page to execute Page function. -func (p *ControllerRegister) AddAuto(c ControllerInterface) { - p.AddAutoPrefix("/", c) -} - -// AddAutoPrefix Add auto router to ControllerRegister with prefix. -// example beego.AddAutoPrefix("/admin",&MainContorlller{}), -// MainController has method List and Page. -// visit the url /admin/main/list to execute List function -// /admin/main/page to execute Page function. -func (p *ControllerRegister) AddAutoPrefix(prefix string, c ControllerInterface) { - reflectVal := reflect.ValueOf(c) - rt := reflectVal.Type() - ct := reflect.Indirect(reflectVal).Type() - controllerName := strings.TrimSuffix(ct.Name(), "Controller") - for i := 0; i < rt.NumMethod(); i++ { - if !utils.InSlice(rt.Method(i).Name, exceptMethod) { - route := &ControllerInfo{} - route.routerType = routerTypeBeego - route.methods = map[string]string{"*": rt.Method(i).Name} - route.controllerType = ct - pattern := path.Join(prefix, strings.ToLower(controllerName), strings.ToLower(rt.Method(i).Name), "*") - patternInit := path.Join(prefix, controllerName, rt.Method(i).Name, "*") - patternFix := path.Join(prefix, strings.ToLower(controllerName), strings.ToLower(rt.Method(i).Name)) - patternFixInit := path.Join(prefix, controllerName, rt.Method(i).Name) - route.pattern = pattern - for m := range HTTPMETHOD { - p.addToRouter(m, pattern, route) - p.addToRouter(m, patternInit, route) - p.addToRouter(m, patternFix, route) - p.addToRouter(m, patternFixInit, route) - } - } - } -} - -// InsertFilter Add a FilterFunc with pattern rule and action constant. -// params is for: -// 1. setting the returnOnOutput value (false allows multiple filters to execute) -// 2. determining whether or not params need to be reset. -func (p *ControllerRegister) InsertFilter(pattern string, pos int, filter FilterFunc, params ...bool) error { - mr := &FilterRouter{ - tree: NewTree(), - pattern: pattern, - filterFunc: filter, - returnOnOutput: true, - } - if !BConfig.RouterCaseSensitive { - mr.pattern = strings.ToLower(pattern) - } - - paramsLen := len(params) - if paramsLen > 0 { - mr.returnOnOutput = params[0] - } - if paramsLen > 1 { - mr.resetParams = params[1] - } - mr.tree.AddRouter(pattern, true) - return p.insertFilterRouter(pos, mr) -} - -// add Filter into -func (p *ControllerRegister) insertFilterRouter(pos int, mr *FilterRouter) (err error) { - if pos < BeforeStatic || pos > FinishRouter { - err = fmt.Errorf("can not find your filter position") - return - } - p.enableFilter = true - p.filters[pos] = append(p.filters[pos], mr) - return nil -} - -// URLFor does another controller handler in this request function. -// it can access any controller method. -func (p *ControllerRegister) URLFor(endpoint string, values ...interface{}) string { - paths := strings.Split(endpoint, ".") - if len(paths) <= 1 { - logs.Warn("urlfor endpoint must like path.controller.method") - return "" - } - if len(values)%2 != 0 { - logs.Warn("urlfor params must key-value pair") - return "" - } - params := make(map[string]string) - if len(values) > 0 { - key := "" - for k, v := range values { - if k%2 == 0 { - key = fmt.Sprint(v) - } else { - params[key] = fmt.Sprint(v) - } - } - } - controllName := strings.Join(paths[:len(paths)-1], "/") - methodName := paths[len(paths)-1] - for m, t := range p.routers { - ok, url := p.geturl(t, "/", controllName, methodName, params, m) - if ok { - return url - } - } - return "" -} - -func (p *ControllerRegister) geturl(t *Tree, url, controllName, methodName string, params map[string]string, httpMethod string) (bool, string) { - for _, subtree := range t.fixrouters { - u := path.Join(url, subtree.prefix) - ok, u := p.geturl(subtree, u, controllName, methodName, params, httpMethod) - if ok { - return ok, u - } - } - if t.wildcard != nil { - u := path.Join(url, urlPlaceholder) - ok, u := p.geturl(t.wildcard, u, controllName, methodName, params, httpMethod) - if ok { - return ok, u - } - } - for _, l := range t.leaves { - if c, ok := l.runObject.(*ControllerInfo); ok { - if c.routerType == routerTypeBeego && - strings.HasSuffix(path.Join(c.controllerType.PkgPath(), c.controllerType.Name()), controllName) { - find := false - if HTTPMETHOD[strings.ToUpper(methodName)] { - if len(c.methods) == 0 { - find = true - } else if m, ok := c.methods[strings.ToUpper(methodName)]; ok && m == strings.ToUpper(methodName) { - find = true - } else if m, ok = c.methods["*"]; ok && m == methodName { - find = true - } - } - if !find { - for m, md := range c.methods { - if (m == "*" || m == httpMethod) && md == methodName { - find = true - } - } - } - if find { - if l.regexps == nil { - if len(l.wildcards) == 0 { - return true, strings.Replace(url, "/"+urlPlaceholder, "", 1) + toURL(params) - } - if len(l.wildcards) == 1 { - if v, ok := params[l.wildcards[0]]; ok { - delete(params, l.wildcards[0]) - return true, strings.Replace(url, urlPlaceholder, v, 1) + toURL(params) - } - return false, "" - } - if len(l.wildcards) == 3 && l.wildcards[0] == "." { - if p, ok := params[":path"]; ok { - if e, isok := params[":ext"]; isok { - delete(params, ":path") - delete(params, ":ext") - return true, strings.Replace(url, urlPlaceholder, p+"."+e, -1) + toURL(params) - } - } - } - canskip := false - for _, v := range l.wildcards { - if v == ":" { - canskip = true - continue - } - if u, ok := params[v]; ok { - delete(params, v) - url = strings.Replace(url, urlPlaceholder, u, 1) - } else { - if canskip { - canskip = false - continue - } - return false, "" - } - } - return true, url + toURL(params) - } - var i int - var startreg bool - regurl := "" - for _, v := range strings.Trim(l.regexps.String(), "^$") { - if v == '(' { - startreg = true - continue - } else if v == ')' { - startreg = false - if v, ok := params[l.wildcards[i]]; ok { - delete(params, l.wildcards[i]) - regurl = regurl + v - i++ - } else { - break - } - } else if !startreg { - regurl = string(append([]rune(regurl), v)) - } - } - if l.regexps.MatchString(regurl) { - ps := strings.Split(regurl, "/") - for _, p := range ps { - url = strings.Replace(url, urlPlaceholder, p, 1) - } - return true, url + toURL(params) - } - } - } - } - } - - return false, "" -} - -func (p *ControllerRegister) execFilter(context *beecontext.Context, urlPath string, pos int) (started bool) { - var preFilterParams map[string]string - for _, filterR := range p.filters[pos] { - if filterR.returnOnOutput && context.ResponseWriter.Started { - return true - } - if filterR.resetParams { - preFilterParams = context.Input.Params() - } - if ok := filterR.ValidRouter(urlPath, context); ok { - filterR.filterFunc(context) - if filterR.resetParams { - context.Input.ResetParams() - for k, v := range preFilterParams { - context.Input.SetParam(k, v) - } - } - } - if filterR.returnOnOutput && context.ResponseWriter.Started { - return true - } - } - return false -} - -// Implement http.Handler interface. -func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) { - startTime := time.Now() - var ( - runRouter reflect.Type - findRouter bool - runMethod string - methodParams []*param.MethodParam - routerInfo *ControllerInfo - isRunnable bool - ) - context := p.pool.Get().(*beecontext.Context) - context.Reset(rw, r) - - defer p.pool.Put(context) - if BConfig.RecoverFunc != nil { - defer BConfig.RecoverFunc(context) - } - - context.Output.EnableGzip = BConfig.EnableGzip - - if BConfig.RunMode == DEV { - context.Output.Header("Server", BConfig.ServerName) - } - - var urlPath = r.URL.Path - - if !BConfig.RouterCaseSensitive { - urlPath = strings.ToLower(urlPath) - } - - // filter wrong http method - if !HTTPMETHOD[r.Method] { - http.Error(rw, "Method Not Allowed", 405) - goto Admin - } - - // filter for static file - if len(p.filters[BeforeStatic]) > 0 && p.execFilter(context, urlPath, BeforeStatic) { - goto Admin - } - - serverStaticRouter(context) - - if context.ResponseWriter.Started { - findRouter = true - goto Admin - } - - if r.Method != http.MethodGet && r.Method != http.MethodHead { - if BConfig.CopyRequestBody && !context.Input.IsUpload() { - context.Input.CopyBody(BConfig.MaxMemory) - } - context.Input.ParseFormOrMulitForm(BConfig.MaxMemory) - } - - // session init - if BConfig.WebConfig.Session.SessionOn { - var err error - context.Input.CruSession, err = GlobalSessions.SessionStart(rw, r) - if err != nil { - logs.Error(err) - exception("503", context) - goto Admin - } - defer func() { - if context.Input.CruSession != nil { - context.Input.CruSession.SessionRelease(rw) - } - }() - } - if len(p.filters[BeforeRouter]) > 0 && p.execFilter(context, urlPath, BeforeRouter) { - goto Admin - } - // User can define RunController and RunMethod in filter - if context.Input.RunController != nil && context.Input.RunMethod != "" { - findRouter = true - runMethod = context.Input.RunMethod - runRouter = context.Input.RunController - } else { - routerInfo, findRouter = p.FindRouter(context) - } - - //if no matches to url, throw a not found exception - if !findRouter { - exception("404", context) - goto Admin - } - if splat := context.Input.Param(":splat"); splat != "" { - for k, v := range strings.Split(splat, "/") { - context.Input.SetParam(strconv.Itoa(k), v) - } - } - - //execute middleware filters - if len(p.filters[BeforeExec]) > 0 && p.execFilter(context, urlPath, BeforeExec) { - goto Admin - } - - //check policies - if p.execPolicy(context, urlPath) { - goto Admin - } - - if routerInfo != nil { - //store router pattern into context - context.Input.SetData("RouterPattern", routerInfo.pattern) - if routerInfo.routerType == routerTypeRESTFul { - if _, ok := routerInfo.methods[r.Method]; ok { - isRunnable = true - routerInfo.runFunction(context) - } else { - exception("405", context) - goto Admin - } - } else if routerInfo.routerType == routerTypeHandler { - isRunnable = true - routerInfo.handler.ServeHTTP(rw, r) - } else { - runRouter = routerInfo.controllerType - methodParams = routerInfo.methodParams - method := r.Method - if r.Method == http.MethodPost && context.Input.Query("_method") == http.MethodPost { - method = http.MethodPut - } - if r.Method == http.MethodPost && context.Input.Query("_method") == http.MethodDelete { - method = http.MethodDelete - } - if m, ok := routerInfo.methods[method]; ok { - runMethod = m - } else if m, ok = routerInfo.methods["*"]; ok { - runMethod = m - } else { - runMethod = method - } - } - } - - // also defined runRouter & runMethod from filter - if !isRunnable { - //Invoke the request handler - var execController ControllerInterface - if routerInfo.initialize != nil { - execController = routerInfo.initialize() - } else { - vc := reflect.New(runRouter) - var ok bool - execController, ok = vc.Interface().(ControllerInterface) - if !ok { - panic("controller is not ControllerInterface") - } - } - - //call the controller init function - execController.Init(context, runRouter.Name(), runMethod, execController) - - //call prepare function - execController.Prepare() - - //if XSRF is Enable then check cookie where there has any cookie in the request's cookie _csrf - if BConfig.WebConfig.EnableXSRF { - execController.XSRFToken() - if r.Method == http.MethodPost || r.Method == http.MethodDelete || r.Method == http.MethodPut || - (r.Method == http.MethodPost && (context.Input.Query("_method") == http.MethodDelete || context.Input.Query("_method") == http.MethodPut)) { - execController.CheckXSRFCookie() - } - } - - execController.URLMapping() - - if !context.ResponseWriter.Started { - //exec main logic - switch runMethod { - case http.MethodGet: - execController.Get() - case http.MethodPost: - execController.Post() - case http.MethodDelete: - execController.Delete() - case http.MethodPut: - execController.Put() - case http.MethodHead: - execController.Head() - case http.MethodPatch: - execController.Patch() - case http.MethodOptions: - execController.Options() - default: - if !execController.HandlerFunc(runMethod) { - vc := reflect.ValueOf(execController) - method := vc.MethodByName(runMethod) - in := param.ConvertParams(methodParams, method.Type(), context) - out := method.Call(in) - - //For backward compatibility we only handle response if we had incoming methodParams - if methodParams != nil { - p.handleParamResponse(context, execController, out) - } - } - } - - //render template - if !context.ResponseWriter.Started && context.Output.Status == 0 { - if BConfig.WebConfig.AutoRender { - if err := execController.Render(); err != nil { - logs.Error(err) - } - } - } - } - - // finish all runRouter. release resource - execController.Finish() - } - - //execute middleware filters - if len(p.filters[AfterExec]) > 0 && p.execFilter(context, urlPath, AfterExec) { - goto Admin - } - - if len(p.filters[FinishRouter]) > 0 && p.execFilter(context, urlPath, FinishRouter) { - goto Admin - } - -Admin: - //admin module record QPS - - statusCode := context.ResponseWriter.Status - if statusCode == 0 { - statusCode = 200 - } - - logAccess(context, &startTime, statusCode) - - if BConfig.Listen.EnableAdmin { - timeDur := time.Since(startTime) - pattern := "" - if routerInfo != nil { - pattern = routerInfo.pattern - } - - if FilterMonitorFunc(r.Method, r.URL.Path, timeDur, pattern, statusCode) { - if runRouter != nil { - go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, runRouter.Name(), timeDur) - } else { - go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, "", timeDur) - } - } - } - - if BConfig.RunMode == DEV && !BConfig.Log.AccessLogs { - var devInfo string - timeDur := time.Since(startTime) - iswin := (runtime.GOOS == "windows") - statusColor := logs.ColorByStatus(iswin, statusCode) - methodColor := logs.ColorByMethod(iswin, r.Method) - resetColor := logs.ColorByMethod(iswin, "") - if findRouter { - if routerInfo != nil { - devInfo = fmt.Sprintf("|%15s|%s %3d %s|%13s|%8s|%s %-7s %s %-3s r:%s", context.Input.IP(), statusColor, statusCode, - resetColor, timeDur.String(), "match", methodColor, r.Method, resetColor, r.URL.Path, - routerInfo.pattern) - } else { - devInfo = fmt.Sprintf("|%15s|%s %3d %s|%13s|%8s|%s %-7s %s %-3s", context.Input.IP(), statusColor, statusCode, resetColor, - timeDur.String(), "match", methodColor, r.Method, resetColor, r.URL.Path) - } - } else { - devInfo = fmt.Sprintf("|%15s|%s %3d %s|%13s|%8s|%s %-7s %s %-3s", context.Input.IP(), statusColor, statusCode, resetColor, - timeDur.String(), "nomatch", methodColor, r.Method, resetColor, r.URL.Path) - } - if iswin { - logs.W32Debug(devInfo) - } else { - logs.Debug(devInfo) - } - } - // Call WriteHeader if status code has been set changed - if context.Output.Status != 0 { - context.ResponseWriter.WriteHeader(context.Output.Status) - } -} - -func (p *ControllerRegister) handleParamResponse(context *beecontext.Context, execController ControllerInterface, results []reflect.Value) { - //looping in reverse order for the case when both error and value are returned and error sets the response status code - for i := len(results) - 1; i >= 0; i-- { - result := results[i] - if result.Kind() != reflect.Interface || !result.IsNil() { - resultValue := result.Interface() - context.RenderMethodResult(resultValue) - } - } - if !context.ResponseWriter.Started && len(results) > 0 && context.Output.Status == 0 { - context.Output.SetStatus(200) - } -} - -// FindRouter Find Router info for URL -func (p *ControllerRegister) FindRouter(context *beecontext.Context) (routerInfo *ControllerInfo, isFind bool) { - var urlPath = context.Input.URL() - if !BConfig.RouterCaseSensitive { - urlPath = strings.ToLower(urlPath) - } - httpMethod := context.Input.Method() - if t, ok := p.routers[httpMethod]; ok { - runObject := t.Match(urlPath, context) - if r, ok := runObject.(*ControllerInfo); ok { - return r, true - } - } - return -} - -func toURL(params map[string]string) string { - if len(params) == 0 { - return "" - } - u := "?" - for k, v := range params { - u += k + "=" + v + "&" - } - return strings.TrimRight(u, "&") -} - -func logAccess(ctx *beecontext.Context, startTime *time.Time, statusCode int) { - //Skip logging if AccessLogs config is false - if !BConfig.Log.AccessLogs { - return - } - //Skip logging static requests unless EnableStaticLogs config is true - if !BConfig.Log.EnableStaticLogs && DefaultAccessLogFilter.Filter(ctx) { - return - } - var ( - requestTime time.Time - elapsedTime time.Duration - r = ctx.Request - ) - if startTime != nil { - requestTime = *startTime - elapsedTime = time.Since(*startTime) - } - record := &logs.AccessLogRecord{ - RemoteAddr: ctx.Input.IP(), - RequestTime: requestTime, - RequestMethod: r.Method, - Request: fmt.Sprintf("%s %s %s", r.Method, r.RequestURI, r.Proto), - ServerProtocol: r.Proto, - Host: r.Host, - Status: statusCode, - ElapsedTime: elapsedTime, - HTTPReferrer: r.Header.Get("Referer"), - HTTPUserAgent: r.Header.Get("User-Agent"), - RemoteUser: r.Header.Get("Remote-User"), - BodyBytesSent: 0, //@todo this one is missing! - } - logs.AccessLog(record, BConfig.Log.AccessLogsFormat) -} diff --git a/vender/github.com/astaxie/beego/router_test.go b/vender/github.com/astaxie/beego/router_test.go deleted file mode 100755 index 338ac28..0000000 --- a/vender/github.com/astaxie/beego/router_test.go +++ /dev/null @@ -1,724 +0,0 @@ -// 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" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" -) - -type TestController struct { - Controller -} - -func (tc *TestController) Get() { - tc.Data["Username"] = "astaxie" - tc.Ctx.Output.Body([]byte("ok")) -} - -func (tc *TestController) Post() { - tc.Ctx.Output.Body([]byte(tc.Ctx.Input.Query(":name"))) -} - -func (tc *TestController) Param() { - tc.Ctx.Output.Body([]byte(tc.Ctx.Input.Query(":name"))) -} - -func (tc *TestController) List() { - tc.Ctx.Output.Body([]byte("i am list")) -} - -func (tc *TestController) Params() { - tc.Ctx.Output.Body([]byte(tc.Ctx.Input.Param("0") + tc.Ctx.Input.Param("1") + tc.Ctx.Input.Param("2"))) -} - -func (tc *TestController) Myext() { - tc.Ctx.Output.Body([]byte(tc.Ctx.Input.Param(":ext"))) -} - -func (tc *TestController) GetURL() { - tc.Ctx.Output.Body([]byte(tc.URLFor(".Myext"))) -} - -func (tc *TestController) GetParams() { - tc.Ctx.WriteString(tc.Ctx.Input.Query(":last") + "+" + - tc.Ctx.Input.Query(":first") + "+" + tc.Ctx.Input.Query("learn")) -} - -func (tc *TestController) GetManyRouter() { - tc.Ctx.WriteString(tc.Ctx.Input.Query(":id") + tc.Ctx.Input.Query(":page")) -} - -func (tc *TestController) GetEmptyBody() { - var res []byte - tc.Ctx.Output.Body(res) -} - -type ResStatus struct { - Code int - Msg string -} - -type JSONController struct { - Controller -} - -func (jc *JSONController) Prepare() { - jc.Data["json"] = "prepare" - jc.ServeJSON(true) -} - -func (jc *JSONController) Get() { - jc.Data["Username"] = "astaxie" - jc.Ctx.Output.Body([]byte("ok")) -} - -func TestUrlFor(t *testing.T) { - handler := NewControllerRegister() - handler.Add("/api/list", &TestController{}, "*:List") - handler.Add("/person/:last/:first", &TestController{}, "*:Param") - if a := handler.URLFor("TestController.List"); a != "/api/list" { - logs.Info(a) - t.Errorf("TestController.List must equal to /api/list") - } - if a := handler.URLFor("TestController.Param", ":last", "xie", ":first", "asta"); a != "/person/xie/asta" { - t.Errorf("TestController.Param must equal to /person/xie/asta, but get " + a) - } -} - -func TestUrlFor3(t *testing.T) { - handler := NewControllerRegister() - handler.AddAuto(&TestController{}) - if a := handler.URLFor("TestController.Myext"); a != "/test/myext" && a != "/Test/Myext" { - t.Errorf("TestController.Myext must equal to /test/myext, but get " + a) - } - if a := handler.URLFor("TestController.GetURL"); a != "/test/geturl" && a != "/Test/GetURL" { - t.Errorf("TestController.GetURL must equal to /test/geturl, but get " + a) - } -} - -func TestUrlFor2(t *testing.T) { - handler := NewControllerRegister() - handler.Add("/v1/:v/cms_:id(.+)_:page(.+).html", &TestController{}, "*:List") - handler.Add("/v1/:username/edit", &TestController{}, "get:GetURL") - handler.Add("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", &TestController{}, "*:Param") - handler.Add("/:year:int/:month:int/:title/:entid", &TestController{}) - if handler.URLFor("TestController.GetURL", ":username", "astaxie") != "/v1/astaxie/edit" { - logs.Info(handler.URLFor("TestController.GetURL")) - t.Errorf("TestController.List must equal to /v1/astaxie/edit") - } - - if handler.URLFor("TestController.List", ":v", "za", ":id", "12", ":page", "123") != - "/v1/za/cms_12_123.html" { - logs.Info(handler.URLFor("TestController.List")) - t.Errorf("TestController.List must equal to /v1/za/cms_12_123.html") - } - if handler.URLFor("TestController.Param", ":v", "za", ":id", "12", ":page", "123") != - "/v1/za_cms/ttt_12_123.html" { - logs.Info(handler.URLFor("TestController.Param")) - t.Errorf("TestController.List must equal to /v1/za_cms/ttt_12_123.html") - } - if handler.URLFor("TestController.Get", ":year", "1111", ":month", "11", - ":title", "aaaa", ":entid", "aaaa") != - "/1111/11/aaaa/aaaa" { - logs.Info(handler.URLFor("TestController.Get")) - t.Errorf("TestController.Get must equal to /1111/11/aaaa/aaaa") - } -} - -func TestUserFunc(t *testing.T) { - r, _ := http.NewRequest("GET", "/api/list", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.Add("/api/list", &TestController{}, "*:List") - handler.ServeHTTP(w, r) - if w.Body.String() != "i am list" { - t.Errorf("user define func can't run") - } -} - -func TestPostFunc(t *testing.T) { - r, _ := http.NewRequest("POST", "/astaxie", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.Add("/:name", &TestController{}) - handler.ServeHTTP(w, r) - if w.Body.String() != "astaxie" { - t.Errorf("post func should astaxie") - } -} - -func TestAutoFunc(t *testing.T) { - r, _ := http.NewRequest("GET", "/test/list", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.AddAuto(&TestController{}) - handler.ServeHTTP(w, r) - if w.Body.String() != "i am list" { - t.Errorf("user define func can't run") - } -} - -func TestAutoFunc2(t *testing.T) { - r, _ := http.NewRequest("GET", "/Test/List", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.AddAuto(&TestController{}) - handler.ServeHTTP(w, r) - if w.Body.String() != "i am list" { - t.Errorf("user define func can't run") - } -} - -func TestAutoFuncParams(t *testing.T) { - r, _ := http.NewRequest("GET", "/test/params/2009/11/12", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.AddAuto(&TestController{}) - handler.ServeHTTP(w, r) - if w.Body.String() != "20091112" { - t.Errorf("user define func can't run") - } -} - -func TestAutoExtFunc(t *testing.T) { - r, _ := http.NewRequest("GET", "/test/myext.json", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.AddAuto(&TestController{}) - handler.ServeHTTP(w, r) - if w.Body.String() != "json" { - t.Errorf("user define func can't run") - } -} - -func TestRouteOk(t *testing.T) { - - r, _ := http.NewRequest("GET", "/person/anderson/thomas?learn=kungfu", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.Add("/person/:last/:first", &TestController{}, "get:GetParams") - handler.ServeHTTP(w, r) - body := w.Body.String() - if body != "anderson+thomas+kungfu" { - t.Errorf("url param set to [%s];", body) - } -} - -func TestManyRoute(t *testing.T) { - - r, _ := http.NewRequest("GET", "/beego32-12.html", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.Add("/beego:id([0-9]+)-:page([0-9]+).html", &TestController{}, "get:GetManyRouter") - handler.ServeHTTP(w, r) - - body := w.Body.String() - - if body != "3212" { - t.Errorf("url param set to [%s];", body) - } -} - -// Test for issue #1669 -func TestEmptyResponse(t *testing.T) { - - r, _ := http.NewRequest("GET", "/beego-empty.html", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.Add("/beego-empty.html", &TestController{}, "get:GetEmptyBody") - handler.ServeHTTP(w, r) - - if body := w.Body.String(); body != "" { - t.Error("want empty body") - } -} - -func TestNotFound(t *testing.T) { - r, _ := http.NewRequest("GET", "/", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.ServeHTTP(w, r) - - if w.Code != http.StatusNotFound { - t.Errorf("Code set to [%v]; want [%v]", w.Code, http.StatusNotFound) - } -} - -// TestStatic tests the ability to serve static -// content from the filesystem -func TestStatic(t *testing.T) { - r, _ := http.NewRequest("GET", "/static/js/jquery.js", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.ServeHTTP(w, r) - - if w.Code != 404 { - t.Errorf("handler.Static failed to serve file") - } -} - -func TestPrepare(t *testing.T) { - r, _ := http.NewRequest("GET", "/json/list", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.Add("/json/list", &JSONController{}) - handler.ServeHTTP(w, r) - if w.Body.String() != `"prepare"` { - t.Errorf(w.Body.String() + "user define func can't run") - } -} - -func TestAutoPrefix(t *testing.T) { - r, _ := http.NewRequest("GET", "/admin/test/list", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.AddAutoPrefix("/admin", &TestController{}) - handler.ServeHTTP(w, r) - if w.Body.String() != "i am list" { - t.Errorf("TestAutoPrefix can't run") - } -} - -func TestRouterGet(t *testing.T) { - r, _ := http.NewRequest("GET", "/user", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.Get("/user", func(ctx *context.Context) { - ctx.Output.Body([]byte("Get userlist")) - }) - handler.ServeHTTP(w, r) - if w.Body.String() != "Get userlist" { - t.Errorf("TestRouterGet can't run") - } -} - -func TestRouterPost(t *testing.T) { - r, _ := http.NewRequest("POST", "/user/123", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.Post("/user/:id", func(ctx *context.Context) { - ctx.Output.Body([]byte(ctx.Input.Param(":id"))) - }) - handler.ServeHTTP(w, r) - if w.Body.String() != "123" { - t.Errorf("TestRouterPost can't run") - } -} - -func sayhello(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("sayhello")) -} - -func TestRouterHandler(t *testing.T) { - r, _ := http.NewRequest("POST", "/sayhi", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.Handler("/sayhi", http.HandlerFunc(sayhello)) - handler.ServeHTTP(w, r) - if w.Body.String() != "sayhello" { - t.Errorf("TestRouterHandler can't run") - } -} - -func TestRouterHandlerAll(t *testing.T) { - r, _ := http.NewRequest("POST", "/sayhi/a/b/c", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.Handler("/sayhi", http.HandlerFunc(sayhello), true) - handler.ServeHTTP(w, r) - if w.Body.String() != "sayhello" { - t.Errorf("TestRouterHandler can't run") - } -} - -// -// Benchmarks NewApp: -// - -func beegoFilterFunc(ctx *context.Context) { - ctx.WriteString("hello") -} - -type AdminController struct { - Controller -} - -func (a *AdminController) Get() { - a.Ctx.WriteString("hello") -} - -func TestRouterFunc(t *testing.T) { - mux := NewControllerRegister() - mux.Get("/action", beegoFilterFunc) - mux.Post("/action", beegoFilterFunc) - rw, r := testRequest("GET", "/action") - mux.ServeHTTP(rw, r) - if rw.Body.String() != "hello" { - t.Errorf("TestRouterFunc can't run") - } -} - -func BenchmarkFunc(b *testing.B) { - mux := NewControllerRegister() - mux.Get("/action", beegoFilterFunc) - rw, r := testRequest("GET", "/action") - b.ResetTimer() - for i := 0; i < b.N; i++ { - mux.ServeHTTP(rw, r) - } -} - -func BenchmarkController(b *testing.B) { - mux := NewControllerRegister() - mux.Add("/action", &AdminController{}) - rw, r := testRequest("GET", "/action") - b.ResetTimer() - for i := 0; i < b.N; i++ { - mux.ServeHTTP(rw, r) - } -} - -func testRequest(method, path string) (*httptest.ResponseRecorder, *http.Request) { - request, _ := http.NewRequest(method, path, nil) - recorder := httptest.NewRecorder() - - return recorder, request -} - -// Expectation: A Filter with the correct configuration should be created given -// specific parameters. -func TestInsertFilter(t *testing.T) { - testName := "TestInsertFilter" - - mux := NewControllerRegister() - mux.InsertFilter("*", BeforeRouter, func(*context.Context) {}) - if !mux.filters[BeforeRouter][0].returnOnOutput { - t.Errorf( - "%s: passing no variadic params should set returnOnOutput to true", - testName) - } - if mux.filters[BeforeRouter][0].resetParams { - t.Errorf( - "%s: passing no variadic params should set resetParams to false", - testName) - } - - mux = NewControllerRegister() - mux.InsertFilter("*", BeforeRouter, func(*context.Context) {}, false) - if mux.filters[BeforeRouter][0].returnOnOutput { - t.Errorf( - "%s: passing false as 1st variadic param should set returnOnOutput to false", - testName) - } - - mux = NewControllerRegister() - mux.InsertFilter("*", BeforeRouter, func(*context.Context) {}, true, true) - if !mux.filters[BeforeRouter][0].resetParams { - t.Errorf( - "%s: passing true as 2nd variadic param should set resetParams to true", - testName) - } -} - -// Expectation: the second variadic arg should cause the execution of the filter -// to preserve the parameters from before its execution. -func TestParamResetFilter(t *testing.T) { - testName := "TestParamResetFilter" - route := "/beego/*" // splat - path := "/beego/routes/routes" - - mux := NewControllerRegister() - - mux.InsertFilter("*", BeforeExec, beegoResetParams, true, true) - - mux.Get(route, beegoHandleResetParams) - - rw, r := testRequest("GET", path) - mux.ServeHTTP(rw, r) - - // The two functions, `beegoResetParams` and `beegoHandleResetParams` add - // a response header of `Splat`. The expectation here is that that Header - // value should match what the _request's_ router set, not the filter's. - - headers := rw.HeaderMap - if len(headers["Splat"]) != 1 { - t.Errorf( - "%s: There was an error in the test. Splat param not set in Header", - testName) - } - if headers["Splat"][0] != "routes/routes" { - t.Errorf( - "%s: expected `:splat` param to be [routes/routes] but it was [%s]", - testName, headers["Splat"][0]) - } -} - -// Execution point: BeforeRouter -// expectation: only BeforeRouter function is executed, notmatch output as router doesn't handle -func TestFilterBeforeRouter(t *testing.T) { - testName := "TestFilterBeforeRouter" - url := "/beforeRouter" - - mux := NewControllerRegister() - mux.InsertFilter(url, BeforeRouter, beegoBeforeRouter1) - - mux.Get(url, beegoFilterFunc) - - rw, r := testRequest("GET", url) - mux.ServeHTTP(rw, r) - - if !strings.Contains(rw.Body.String(), "BeforeRouter1") { - t.Errorf(testName + " BeforeRouter did not run") - } - if strings.Contains(rw.Body.String(), "hello") { - t.Errorf(testName + " BeforeRouter did not return properly") - } -} - -// Execution point: BeforeExec -// expectation: only BeforeExec function is executed, match as router determines route only -func TestFilterBeforeExec(t *testing.T) { - testName := "TestFilterBeforeExec" - url := "/beforeExec" - - mux := NewControllerRegister() - mux.InsertFilter(url, BeforeRouter, beegoFilterNoOutput) - mux.InsertFilter(url, BeforeExec, beegoBeforeExec1) - - mux.Get(url, beegoFilterFunc) - - rw, r := testRequest("GET", url) - mux.ServeHTTP(rw, r) - - if !strings.Contains(rw.Body.String(), "BeforeExec1") { - t.Errorf(testName + " BeforeExec did not run") - } - if strings.Contains(rw.Body.String(), "hello") { - t.Errorf(testName + " BeforeExec did not return properly") - } - if strings.Contains(rw.Body.String(), "BeforeRouter") { - t.Errorf(testName + " BeforeRouter ran in error") - } -} - -// Execution point: AfterExec -// expectation: only AfterExec function is executed, match as router handles -func TestFilterAfterExec(t *testing.T) { - testName := "TestFilterAfterExec" - url := "/afterExec" - - mux := NewControllerRegister() - mux.InsertFilter(url, BeforeRouter, beegoFilterNoOutput) - mux.InsertFilter(url, BeforeExec, beegoFilterNoOutput) - mux.InsertFilter(url, AfterExec, beegoAfterExec1, false) - - mux.Get(url, beegoFilterFunc) - - rw, r := testRequest("GET", url) - mux.ServeHTTP(rw, r) - - if !strings.Contains(rw.Body.String(), "AfterExec1") { - t.Errorf(testName + " AfterExec did not run") - } - if !strings.Contains(rw.Body.String(), "hello") { - t.Errorf(testName + " handler did not run properly") - } - if strings.Contains(rw.Body.String(), "BeforeRouter") { - t.Errorf(testName + " BeforeRouter ran in error") - } - if strings.Contains(rw.Body.String(), "BeforeExec") { - t.Errorf(testName + " BeforeExec ran in error") - } -} - -// Execution point: FinishRouter -// expectation: only FinishRouter function is executed, match as router handles -func TestFilterFinishRouter(t *testing.T) { - testName := "TestFilterFinishRouter" - url := "/finishRouter" - - mux := NewControllerRegister() - mux.InsertFilter(url, BeforeRouter, beegoFilterNoOutput) - mux.InsertFilter(url, BeforeExec, beegoFilterNoOutput) - mux.InsertFilter(url, AfterExec, beegoFilterNoOutput) - mux.InsertFilter(url, FinishRouter, beegoFinishRouter1) - - mux.Get(url, beegoFilterFunc) - - rw, r := testRequest("GET", url) - mux.ServeHTTP(rw, r) - - if strings.Contains(rw.Body.String(), "FinishRouter1") { - t.Errorf(testName + " FinishRouter did not run") - } - if !strings.Contains(rw.Body.String(), "hello") { - t.Errorf(testName + " handler did not run properly") - } - if strings.Contains(rw.Body.String(), "AfterExec1") { - t.Errorf(testName + " AfterExec ran in error") - } - if strings.Contains(rw.Body.String(), "BeforeRouter") { - t.Errorf(testName + " BeforeRouter ran in error") - } - if strings.Contains(rw.Body.String(), "BeforeExec") { - t.Errorf(testName + " BeforeExec ran in error") - } -} - -// Execution point: FinishRouter -// expectation: only first FinishRouter function is executed, match as router handles -func TestFilterFinishRouterMultiFirstOnly(t *testing.T) { - testName := "TestFilterFinishRouterMultiFirstOnly" - url := "/finishRouterMultiFirstOnly" - - mux := NewControllerRegister() - mux.InsertFilter(url, FinishRouter, beegoFinishRouter1, false) - mux.InsertFilter(url, FinishRouter, beegoFinishRouter2) - - mux.Get(url, beegoFilterFunc) - - rw, r := testRequest("GET", url) - mux.ServeHTTP(rw, r) - - if !strings.Contains(rw.Body.String(), "FinishRouter1") { - t.Errorf(testName + " FinishRouter1 did not run") - } - if !strings.Contains(rw.Body.String(), "hello") { - t.Errorf(testName + " handler did not run properly") - } - // not expected in body - if strings.Contains(rw.Body.String(), "FinishRouter2") { - t.Errorf(testName + " FinishRouter2 did run") - } -} - -// Execution point: FinishRouter -// expectation: both FinishRouter functions execute, match as router handles -func TestFilterFinishRouterMulti(t *testing.T) { - testName := "TestFilterFinishRouterMulti" - url := "/finishRouterMulti" - - mux := NewControllerRegister() - mux.InsertFilter(url, FinishRouter, beegoFinishRouter1, false) - mux.InsertFilter(url, FinishRouter, beegoFinishRouter2, false) - - mux.Get(url, beegoFilterFunc) - - rw, r := testRequest("GET", url) - mux.ServeHTTP(rw, r) - - if !strings.Contains(rw.Body.String(), "FinishRouter1") { - t.Errorf(testName + " FinishRouter1 did not run") - } - if !strings.Contains(rw.Body.String(), "hello") { - t.Errorf(testName + " handler did not run properly") - } - if !strings.Contains(rw.Body.String(), "FinishRouter2") { - t.Errorf(testName + " FinishRouter2 did not run properly") - } -} - -func beegoFilterNoOutput(ctx *context.Context) { -} - -func beegoBeforeRouter1(ctx *context.Context) { - ctx.WriteString("|BeforeRouter1") -} - -func beegoBeforeRouter2(ctx *context.Context) { - ctx.WriteString("|BeforeRouter2") -} - -func beegoBeforeExec1(ctx *context.Context) { - ctx.WriteString("|BeforeExec1") -} - -func beegoBeforeExec2(ctx *context.Context) { - ctx.WriteString("|BeforeExec2") -} - -func beegoAfterExec1(ctx *context.Context) { - ctx.WriteString("|AfterExec1") -} - -func beegoAfterExec2(ctx *context.Context) { - ctx.WriteString("|AfterExec2") -} - -func beegoFinishRouter1(ctx *context.Context) { - ctx.WriteString("|FinishRouter1") -} - -func beegoFinishRouter2(ctx *context.Context) { - ctx.WriteString("|FinishRouter2") -} - -func beegoResetParams(ctx *context.Context) { - ctx.ResponseWriter.Header().Set("splat", ctx.Input.Param(":splat")) -} - -func beegoHandleResetParams(ctx *context.Context) { - ctx.ResponseWriter.Header().Set("splat", ctx.Input.Param(":splat")) -} - -// YAML -type YAMLController struct { - Controller -} - -func (jc *YAMLController) Prepare() { - jc.Data["yaml"] = "prepare" - jc.ServeYAML() -} - -func (jc *YAMLController) Get() { - jc.Data["Username"] = "astaxie" - jc.Ctx.Output.Body([]byte("ok")) -} - -func TestYAMLPrepare(t *testing.T) { - r, _ := http.NewRequest("GET", "/yaml/list", nil) - w := httptest.NewRecorder() - - handler := NewControllerRegister() - handler.Add("/yaml/list", &YAMLController{}) - handler.ServeHTTP(w, r) - if strings.TrimSpace(w.Body.String()) != "prepare" { - t.Errorf(w.Body.String()) - } -} diff --git a/vender/github.com/astaxie/beego/session/README.md b/vender/github.com/astaxie/beego/session/README.md deleted file mode 100755 index 3e548e0..0000000 --- a/vender/github.com/astaxie/beego/session/README.md +++ /dev/null @@ -1,114 +0,0 @@ -session -============== - -session is a Go session manager. It can use many session providers. Just like the `database/sql` and `database/sql/driver`. - -## How to install? - - go get github.com/cnlh/nps/vender/github.com/astaxie/beego/session - - -## What providers are supported? - -As of now this session manager support memory, file, Redis and MySQL. - - -## How to use it? - -First you must import it - - import ( - "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" - ) - -Then in you web app init the global session manager - - var globalSessions *session.Manager - -* Use **memory** as provider: - - func init() { - globalSessions, _ = session.NewManager("memory", `{"cookieName":"gosessionid","gclifetime":3600}`) - go globalSessions.GC() - } - -* Use **file** as provider, the last param is the path where you want file to be stored: - - func init() { - globalSessions, _ = session.NewManager("file",`{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"./tmp"}`) - go globalSessions.GC() - } - -* Use **Redis** as provider, the last param is the Redis conn address,poolsize,password: - - func init() { - globalSessions, _ = session.NewManager("redis", `{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:6379,100,astaxie"}`) - go globalSessions.GC() - } - -* Use **MySQL** as provider, the last param is the DSN, learn more from [mysql](https://github.com/go-sql-driver/mysql#dsn-data-source-name): - - func init() { - globalSessions, _ = session.NewManager( - "mysql", `{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"username:password@protocol(address)/dbname?param=value"}`) - go globalSessions.GC() - } - -* Use **Cookie** as provider: - - func init() { - globalSessions, _ = session.NewManager( - "cookie", `{"cookieName":"gosessionid","enableSetCookie":false,"gclifetime":3600,"ProviderConfig":"{\"cookieName\":\"gosessionid\",\"securityKey\":\"beegocookiehashkey\"}"}`) - go globalSessions.GC() - } - - -Finally in the handlerfunc you can use it like this - - func login(w http.ResponseWriter, r *http.Request) { - sess := globalSessions.SessionStart(w, r) - defer sess.SessionRelease(w) - username := sess.Get("username") - fmt.Println(username) - if r.Method == "GET" { - t, _ := template.ParseFiles("login.gtpl") - t.Execute(w, nil) - } else { - fmt.Println("username:", r.Form["username"]) - sess.Set("username", r.Form["username"]) - fmt.Println("password:", r.Form["password"]) - } - } - - -## How to write own provider? - -When you develop a web app, maybe you want to write own provider because you must meet the requirements. - -Writing a provider is easy. You only need to define two struct types -(Session and Provider), which satisfy the interface definition. -Maybe you will find the **memory** provider is a good example. - - type SessionStore interface { - Set(key, value interface{}) error //set session value - Get(key interface{}) interface{} //get session value - Delete(key interface{}) error //delete session value - SessionID() string //back current sessionID - SessionRelease(w http.ResponseWriter) // release the resource & save data to provider & return the data - Flush() error //delete all data - } - - type Provider interface { - SessionInit(gclifetime int64, config string) error - SessionRead(sid string) (SessionStore, error) - SessionExist(sid string) bool - SessionRegenerate(oldsid, sid string) (SessionStore, error) - SessionDestroy(sid string) error - SessionAll() int //get all active session - SessionGC() - } - - -## LICENSE - -BSD License http://creativecommons.org/licenses/BSD/ diff --git a/vender/github.com/astaxie/beego/session/couchbase/sess_couchbase.go b/vender/github.com/astaxie/beego/session/couchbase/sess_couchbase.go deleted file mode 100755 index 1fc75e2..0000000 --- a/vender/github.com/astaxie/beego/session/couchbase/sess_couchbase.go +++ /dev/null @@ -1,247 +0,0 @@ -// 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 couchbase for session provider -// -// depend on github.com/couchbaselabs/go-couchbasee -// -// go install github.com/couchbaselabs/go-couchbase -// -// Usage: -// import( -// _ "github.com/cnlh/nps/vender/github.com/astaxie/beego/session/couchbase" -// "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" -// ) -// -// func init() { -// globalSessions, _ = session.NewManager("couchbase", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"http://host:port/, Pool, Bucket"}``) -// go globalSessions.GC() -// } -// -// more docs: http://beego.me/docs/module/session.md -package couchbase - -import ( - "net/http" - "strings" - "sync" - - couchbase "github.com/couchbase/go-couchbase" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" -) - -var couchbpder = &Provider{} - -// SessionStore store each session -type SessionStore struct { - b *couchbase.Bucket - sid string - lock sync.RWMutex - values map[interface{}]interface{} - maxlifetime int64 -} - -// Provider couchabse provided -type Provider struct { - maxlifetime int64 - savePath string - pool string - bucket string - b *couchbase.Bucket -} - -// Set value to couchabse session -func (cs *SessionStore) Set(key, value interface{}) error { - cs.lock.Lock() - defer cs.lock.Unlock() - cs.values[key] = value - return nil -} - -// Get value from couchabse session -func (cs *SessionStore) Get(key interface{}) interface{} { - cs.lock.RLock() - defer cs.lock.RUnlock() - if v, ok := cs.values[key]; ok { - return v - } - return nil -} - -// Delete value in couchbase session by given key -func (cs *SessionStore) Delete(key interface{}) error { - cs.lock.Lock() - defer cs.lock.Unlock() - delete(cs.values, key) - return nil -} - -// Flush Clean all values in couchbase session -func (cs *SessionStore) Flush() error { - cs.lock.Lock() - defer cs.lock.Unlock() - cs.values = make(map[interface{}]interface{}) - return nil -} - -// SessionID Get couchbase session store id -func (cs *SessionStore) SessionID() string { - return cs.sid -} - -// SessionRelease Write couchbase session with Gob string -func (cs *SessionStore) SessionRelease(w http.ResponseWriter) { - defer cs.b.Close() - - bo, err := session.EncodeGob(cs.values) - if err != nil { - return - } - - cs.b.Set(cs.sid, int(cs.maxlifetime), bo) -} - -func (cp *Provider) getBucket() *couchbase.Bucket { - c, err := couchbase.Connect(cp.savePath) - if err != nil { - return nil - } - - pool, err := c.GetPool(cp.pool) - if err != nil { - return nil - } - - bucket, err := pool.GetBucket(cp.bucket) - if err != nil { - return nil - } - - return bucket -} - -// SessionInit init couchbase session -// savepath like couchbase server REST/JSON URL -// e.g. http://host:port/, Pool, Bucket -func (cp *Provider) SessionInit(maxlifetime int64, savePath string) error { - cp.maxlifetime = maxlifetime - configs := strings.Split(savePath, ",") - if len(configs) > 0 { - cp.savePath = configs[0] - } - if len(configs) > 1 { - cp.pool = configs[1] - } - if len(configs) > 2 { - cp.bucket = configs[2] - } - - return nil -} - -// SessionRead read couchbase session by sid -func (cp *Provider) SessionRead(sid string) (session.Store, error) { - cp.b = cp.getBucket() - - var ( - kv map[interface{}]interface{} - err error - doc []byte - ) - - err = cp.b.Get(sid, &doc) - if err != nil { - return nil, err - } else if doc == nil { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(doc) - if err != nil { - return nil, err - } - } - - cs := &SessionStore{b: cp.b, sid: sid, values: kv, maxlifetime: cp.maxlifetime} - return cs, nil -} - -// SessionExist Check couchbase session exist. -// it checkes sid exist or not. -func (cp *Provider) SessionExist(sid string) bool { - cp.b = cp.getBucket() - defer cp.b.Close() - - var doc []byte - - if err := cp.b.Get(sid, &doc); err != nil || doc == nil { - return false - } - return true -} - -// SessionRegenerate remove oldsid and use sid to generate new session -func (cp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) { - cp.b = cp.getBucket() - - var doc []byte - if err := cp.b.Get(oldsid, &doc); err != nil || doc == nil { - cp.b.Set(sid, int(cp.maxlifetime), "") - } else { - err := cp.b.Delete(oldsid) - if err != nil { - return nil, err - } - _, _ = cp.b.Add(sid, int(cp.maxlifetime), doc) - } - - err := cp.b.Get(sid, &doc) - if err != nil { - return nil, err - } - var kv map[interface{}]interface{} - if doc == nil { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(doc) - if err != nil { - return nil, err - } - } - - cs := &SessionStore{b: cp.b, sid: sid, values: kv, maxlifetime: cp.maxlifetime} - return cs, nil -} - -// SessionDestroy Remove bucket in this couchbase -func (cp *Provider) SessionDestroy(sid string) error { - cp.b = cp.getBucket() - defer cp.b.Close() - - cp.b.Delete(sid) - return nil -} - -// SessionGC Recycle -func (cp *Provider) SessionGC() { -} - -// SessionAll return all active session -func (cp *Provider) SessionAll() int { - return 0 -} - -func init() { - session.Register("couchbase", couchbpder) -} diff --git a/vender/github.com/astaxie/beego/session/ledis/ledis_session.go b/vender/github.com/astaxie/beego/session/ledis/ledis_session.go deleted file mode 100755 index 01f99e1..0000000 --- a/vender/github.com/astaxie/beego/session/ledis/ledis_session.go +++ /dev/null @@ -1,172 +0,0 @@ -// Package ledis provide session Provider -package ledis - -import ( - "net/http" - "strconv" - "strings" - "sync" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" - "github.com/siddontang/ledisdb/config" - "github.com/siddontang/ledisdb/ledis" -) - -var ( - ledispder = &Provider{} - c *ledis.DB -) - -// SessionStore ledis session store -type SessionStore struct { - sid string - lock sync.RWMutex - values map[interface{}]interface{} - maxlifetime int64 -} - -// Set value in ledis session -func (ls *SessionStore) Set(key, value interface{}) error { - ls.lock.Lock() - defer ls.lock.Unlock() - ls.values[key] = value - return nil -} - -// Get value in ledis session -func (ls *SessionStore) Get(key interface{}) interface{} { - ls.lock.RLock() - defer ls.lock.RUnlock() - if v, ok := ls.values[key]; ok { - return v - } - return nil -} - -// Delete value in ledis session -func (ls *SessionStore) Delete(key interface{}) error { - ls.lock.Lock() - defer ls.lock.Unlock() - delete(ls.values, key) - return nil -} - -// Flush clear all values in ledis session -func (ls *SessionStore) Flush() error { - ls.lock.Lock() - defer ls.lock.Unlock() - ls.values = make(map[interface{}]interface{}) - return nil -} - -// SessionID get ledis session id -func (ls *SessionStore) SessionID() string { - return ls.sid -} - -// SessionRelease save session values to ledis -func (ls *SessionStore) SessionRelease(w http.ResponseWriter) { - b, err := session.EncodeGob(ls.values) - if err != nil { - return - } - c.Set([]byte(ls.sid), b) - c.Expire([]byte(ls.sid), ls.maxlifetime) -} - -// Provider ledis session provider -type Provider struct { - maxlifetime int64 - savePath string - db int -} - -// SessionInit init ledis session -// savepath like ledis server saveDataPath,pool size -// e.g. 127.0.0.1:6379,100,astaxie -func (lp *Provider) SessionInit(maxlifetime int64, savePath string) error { - var err error - lp.maxlifetime = maxlifetime - configs := strings.Split(savePath, ",") - if len(configs) == 1 { - lp.savePath = configs[0] - } else if len(configs) == 2 { - lp.savePath = configs[0] - lp.db, err = strconv.Atoi(configs[1]) - if err != nil { - return err - } - } - cfg := new(config.Config) - cfg.DataDir = lp.savePath - - var ledisInstance *ledis.Ledis - ledisInstance, err = ledis.Open(cfg) - if err != nil { - return err - } - c, err = ledisInstance.Select(lp.db) - return err -} - -// SessionRead read ledis session by sid -func (lp *Provider) SessionRead(sid string) (session.Store, error) { - var ( - kv map[interface{}]interface{} - err error - ) - - kvs, _ := c.Get([]byte(sid)) - - if len(kvs) == 0 { - kv = make(map[interface{}]interface{}) - } else { - if kv, err = session.DecodeGob(kvs); err != nil { - return nil, err - } - } - - ls := &SessionStore{sid: sid, values: kv, maxlifetime: lp.maxlifetime} - return ls, nil -} - -// SessionExist check ledis session exist by sid -func (lp *Provider) SessionExist(sid string) bool { - count, _ := c.Exists([]byte(sid)) - return !(count == 0) -} - -// SessionRegenerate generate new sid for ledis session -func (lp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) { - count, _ := c.Exists([]byte(sid)) - if count == 0 { - // oldsid doesn't exists, set the new sid directly - // ignore error here, since if it return error - // the existed value will be 0 - c.Set([]byte(sid), []byte("")) - c.Expire([]byte(sid), lp.maxlifetime) - } else { - data, _ := c.Get([]byte(oldsid)) - c.Set([]byte(sid), data) - c.Expire([]byte(sid), lp.maxlifetime) - } - return lp.SessionRead(sid) -} - -// SessionDestroy delete ledis session by id -func (lp *Provider) SessionDestroy(sid string) error { - c.Del([]byte(sid)) - return nil -} - -// SessionGC Impelment method, no used. -func (lp *Provider) SessionGC() { -} - -// SessionAll return all active session -func (lp *Provider) SessionAll() int { - return 0 -} -func init() { - session.Register("ledis", ledispder) -} diff --git a/vender/github.com/astaxie/beego/session/memcache/sess_memcache.go b/vender/github.com/astaxie/beego/session/memcache/sess_memcache.go deleted file mode 100755 index c2c0dd7..0000000 --- a/vender/github.com/astaxie/beego/session/memcache/sess_memcache.go +++ /dev/null @@ -1,227 +0,0 @@ -// 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 session provider -// -// depend on github.com/bradfitz/gomemcache/memcache -// -// go install github.com/bradfitz/gomemcache/memcache -// -// Usage: -// import( -// _ "github.com/cnlh/nps/vender/github.com/astaxie/beego/session/memcache" -// "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" -// ) -// -// func init() { -// globalSessions, _ = session.NewManager("memcache", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:11211"}``) -// go globalSessions.GC() -// } -// -// more docs: http://beego.me/docs/module/session.md -package memcache - -import ( - "net/http" - "strings" - "sync" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" - - "github.com/bradfitz/gomemcache/memcache" -) - -var mempder = &MemProvider{} -var client *memcache.Client - -// SessionStore memcache session store -type SessionStore struct { - sid string - lock sync.RWMutex - values map[interface{}]interface{} - maxlifetime int64 -} - -// Set value in memcache session -func (rs *SessionStore) Set(key, value interface{}) error { - rs.lock.Lock() - defer rs.lock.Unlock() - rs.values[key] = value - return nil -} - -// Get value in memcache session -func (rs *SessionStore) Get(key interface{}) interface{} { - rs.lock.RLock() - defer rs.lock.RUnlock() - if v, ok := rs.values[key]; ok { - return v - } - return nil -} - -// Delete value in memcache session -func (rs *SessionStore) Delete(key interface{}) error { - rs.lock.Lock() - defer rs.lock.Unlock() - delete(rs.values, key) - return nil -} - -// Flush clear all values in memcache session -func (rs *SessionStore) Flush() error { - rs.lock.Lock() - defer rs.lock.Unlock() - rs.values = make(map[interface{}]interface{}) - return nil -} - -// SessionID get memcache session id -func (rs *SessionStore) SessionID() string { - return rs.sid -} - -// SessionRelease save session values to memcache -func (rs *SessionStore) SessionRelease(w http.ResponseWriter) { - b, err := session.EncodeGob(rs.values) - if err != nil { - return - } - item := memcache.Item{Key: rs.sid, Value: b, Expiration: int32(rs.maxlifetime)} - client.Set(&item) -} - -// MemProvider memcache session provider -type MemProvider struct { - maxlifetime int64 - conninfo []string - poolsize int - password string -} - -// SessionInit init memcache session -// savepath like -// e.g. 127.0.0.1:9090 -func (rp *MemProvider) SessionInit(maxlifetime int64, savePath string) error { - rp.maxlifetime = maxlifetime - rp.conninfo = strings.Split(savePath, ";") - client = memcache.New(rp.conninfo...) - return nil -} - -// SessionRead read memcache session by sid -func (rp *MemProvider) SessionRead(sid string) (session.Store, error) { - if client == nil { - if err := rp.connectInit(); err != nil { - return nil, err - } - } - item, err := client.Get(sid) - if err != nil && err == memcache.ErrCacheMiss { - rs := &SessionStore{sid: sid, values: make(map[interface{}]interface{}), maxlifetime: rp.maxlifetime} - return rs, nil - } - var kv map[interface{}]interface{} - if len(item.Value) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(item.Value) - if err != nil { - return nil, err - } - } - rs := &SessionStore{sid: sid, values: kv, maxlifetime: rp.maxlifetime} - return rs, nil -} - -// SessionExist check memcache session exist by sid -func (rp *MemProvider) SessionExist(sid string) bool { - if client == nil { - if err := rp.connectInit(); err != nil { - return false - } - } - if item, err := client.Get(sid); err != nil || len(item.Value) == 0 { - return false - } - return true -} - -// SessionRegenerate generate new sid for memcache session -func (rp *MemProvider) SessionRegenerate(oldsid, sid string) (session.Store, error) { - if client == nil { - if err := rp.connectInit(); err != nil { - return nil, err - } - } - var contain []byte - if item, err := client.Get(sid); err != nil || len(item.Value) == 0 { - // oldsid doesn't exists, set the new sid directly - // ignore error here, since if it return error - // the existed value will be 0 - item.Key = sid - item.Value = []byte("") - item.Expiration = int32(rp.maxlifetime) - client.Set(item) - } else { - client.Delete(oldsid) - item.Key = sid - item.Expiration = int32(rp.maxlifetime) - client.Set(item) - contain = item.Value - } - - var kv map[interface{}]interface{} - if len(contain) == 0 { - kv = make(map[interface{}]interface{}) - } else { - var err error - kv, err = session.DecodeGob(contain) - if err != nil { - return nil, err - } - } - - rs := &SessionStore{sid: sid, values: kv, maxlifetime: rp.maxlifetime} - return rs, nil -} - -// SessionDestroy delete memcache session by id -func (rp *MemProvider) SessionDestroy(sid string) error { - if client == nil { - if err := rp.connectInit(); err != nil { - return err - } - } - - return client.Delete(sid) -} - -func (rp *MemProvider) connectInit() error { - client = memcache.New(rp.conninfo...) - return nil -} - -// SessionGC Impelment method, no used. -func (rp *MemProvider) SessionGC() { -} - -// SessionAll return all activeSession -func (rp *MemProvider) SessionAll() int { - return 0 -} - -func init() { - session.Register("memcache", mempder) -} diff --git a/vender/github.com/astaxie/beego/session/mysql/sess_mysql.go b/vender/github.com/astaxie/beego/session/mysql/sess_mysql.go deleted file mode 100755 index fd02c8a..0000000 --- a/vender/github.com/astaxie/beego/session/mysql/sess_mysql.go +++ /dev/null @@ -1,228 +0,0 @@ -// 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 mysql for session provider -// -// depends on github.com/go-sql-driver/mysql: -// -// go install github.com/go-sql-driver/mysql -// -// mysql session support need create table as sql: -// CREATE TABLE `session` ( -// `session_key` char(64) NOT NULL, -// `session_data` blob, -// `session_expiry` int(11) unsigned NOT NULL, -// PRIMARY KEY (`session_key`) -// ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -// -// Usage: -// import( -// _ "github.com/cnlh/nps/vender/github.com/astaxie/beego/session/mysql" -// "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" -// ) -// -// func init() { -// globalSessions, _ = session.NewManager("mysql", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN]"}``) -// go globalSessions.GC() -// } -// -// more docs: http://beego.me/docs/module/session.md -package mysql - -import ( - "database/sql" - "net/http" - "sync" - "time" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" - // import mysql driver - _ "github.com/go-sql-driver/mysql" -) - -var ( - // TableName store the session in MySQL - TableName = "session" - mysqlpder = &Provider{} -) - -// SessionStore mysql session store -type SessionStore struct { - c *sql.DB - sid string - lock sync.RWMutex - values map[interface{}]interface{} -} - -// Set value in mysql session. -// it is temp value in map. -func (st *SessionStore) Set(key, value interface{}) error { - st.lock.Lock() - defer st.lock.Unlock() - st.values[key] = value - return nil -} - -// Get value from mysql session -func (st *SessionStore) Get(key interface{}) interface{} { - st.lock.RLock() - defer st.lock.RUnlock() - if v, ok := st.values[key]; ok { - return v - } - return nil -} - -// Delete value in mysql session -func (st *SessionStore) Delete(key interface{}) error { - st.lock.Lock() - defer st.lock.Unlock() - delete(st.values, key) - return nil -} - -// Flush clear all values in mysql session -func (st *SessionStore) Flush() error { - st.lock.Lock() - defer st.lock.Unlock() - st.values = make(map[interface{}]interface{}) - return nil -} - -// SessionID get session id of this mysql session store -func (st *SessionStore) SessionID() string { - return st.sid -} - -// SessionRelease save mysql session values to database. -// must call this method to save values to database. -func (st *SessionStore) SessionRelease(w http.ResponseWriter) { - defer st.c.Close() - b, err := session.EncodeGob(st.values) - if err != nil { - return - } - st.c.Exec("UPDATE "+TableName+" set `session_data`=?, `session_expiry`=? where session_key=?", - b, time.Now().Unix(), st.sid) -} - -// Provider mysql session provider -type Provider struct { - maxlifetime int64 - savePath string -} - -// connect to mysql -func (mp *Provider) connectInit() *sql.DB { - db, e := sql.Open("mysql", mp.savePath) - if e != nil { - return nil - } - return db -} - -// SessionInit init mysql session. -// savepath is the connection string of mysql. -func (mp *Provider) SessionInit(maxlifetime int64, savePath string) error { - mp.maxlifetime = maxlifetime - mp.savePath = savePath - return nil -} - -// SessionRead get mysql session by sid -func (mp *Provider) SessionRead(sid string) (session.Store, error) { - c := mp.connectInit() - row := c.QueryRow("select session_data from "+TableName+" where session_key=?", sid) - var sessiondata []byte - err := row.Scan(&sessiondata) - if err == sql.ErrNoRows { - c.Exec("insert into "+TableName+"(`session_key`,`session_data`,`session_expiry`) values(?,?,?)", - sid, "", time.Now().Unix()) - } - var kv map[interface{}]interface{} - if len(sessiondata) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(sessiondata) - if err != nil { - return nil, err - } - } - rs := &SessionStore{c: c, sid: sid, values: kv} - return rs, nil -} - -// SessionExist check mysql session exist -func (mp *Provider) SessionExist(sid string) bool { - c := mp.connectInit() - defer c.Close() - row := c.QueryRow("select session_data from "+TableName+" where session_key=?", sid) - var sessiondata []byte - err := row.Scan(&sessiondata) - return !(err == sql.ErrNoRows) -} - -// SessionRegenerate generate new sid for mysql session -func (mp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) { - c := mp.connectInit() - row := c.QueryRow("select session_data from "+TableName+" where session_key=?", oldsid) - var sessiondata []byte - err := row.Scan(&sessiondata) - if err == sql.ErrNoRows { - c.Exec("insert into "+TableName+"(`session_key`,`session_data`,`session_expiry`) values(?,?,?)", oldsid, "", time.Now().Unix()) - } - c.Exec("update "+TableName+" set `session_key`=? where session_key=?", sid, oldsid) - var kv map[interface{}]interface{} - if len(sessiondata) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(sessiondata) - if err != nil { - return nil, err - } - } - rs := &SessionStore{c: c, sid: sid, values: kv} - return rs, nil -} - -// SessionDestroy delete mysql session by sid -func (mp *Provider) SessionDestroy(sid string) error { - c := mp.connectInit() - c.Exec("DELETE FROM "+TableName+" where session_key=?", sid) - c.Close() - return nil -} - -// SessionGC delete expired values in mysql session -func (mp *Provider) SessionGC() { - c := mp.connectInit() - c.Exec("DELETE from "+TableName+" where session_expiry < ?", time.Now().Unix()-mp.maxlifetime) - c.Close() -} - -// SessionAll count values in mysql session -func (mp *Provider) SessionAll() int { - c := mp.connectInit() - defer c.Close() - var total int - err := c.QueryRow("SELECT count(*) as num from " + TableName).Scan(&total) - if err != nil { - return 0 - } - return total -} - -func init() { - session.Register("mysql", mysqlpder) -} diff --git a/vender/github.com/astaxie/beego/session/postgres/sess_postgresql.go b/vender/github.com/astaxie/beego/session/postgres/sess_postgresql.go deleted file mode 100755 index 15780f1..0000000 --- a/vender/github.com/astaxie/beego/session/postgres/sess_postgresql.go +++ /dev/null @@ -1,243 +0,0 @@ -// 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 postgres for session provider -// -// depends on github.com/lib/pq: -// -// go install github.com/lib/pq -// -// -// needs this table in your database: -// -// CREATE TABLE session ( -// session_key char(64) NOT NULL, -// session_data bytea, -// session_expiry timestamp NOT NULL, -// CONSTRAINT session_key PRIMARY KEY(session_key) -// ); -// -// will be activated with these settings in app.conf: -// -// SessionOn = true -// SessionProvider = postgresql -// SessionSavePath = "user=a password=b dbname=c sslmode=disable" -// SessionName = session -// -// -// Usage: -// import( -// _ "github.com/cnlh/nps/vender/github.com/astaxie/beego/session/postgresql" -// "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" -// ) -// -// func init() { -// globalSessions, _ = session.NewManager("postgresql", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"user=pqgotest dbname=pqgotest sslmode=verify-full"}``) -// go globalSessions.GC() -// } -// -// more docs: http://beego.me/docs/module/session.md -package postgres - -import ( - "database/sql" - "net/http" - "sync" - "time" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" - // import postgresql Driver - _ "github.com/lib/pq" -) - -var postgresqlpder = &Provider{} - -// SessionStore postgresql session store -type SessionStore struct { - c *sql.DB - sid string - lock sync.RWMutex - values map[interface{}]interface{} -} - -// Set value in postgresql session. -// it is temp value in map. -func (st *SessionStore) Set(key, value interface{}) error { - st.lock.Lock() - defer st.lock.Unlock() - st.values[key] = value - return nil -} - -// Get value from postgresql session -func (st *SessionStore) Get(key interface{}) interface{} { - st.lock.RLock() - defer st.lock.RUnlock() - if v, ok := st.values[key]; ok { - return v - } - return nil -} - -// Delete value in postgresql session -func (st *SessionStore) Delete(key interface{}) error { - st.lock.Lock() - defer st.lock.Unlock() - delete(st.values, key) - return nil -} - -// Flush clear all values in postgresql session -func (st *SessionStore) Flush() error { - st.lock.Lock() - defer st.lock.Unlock() - st.values = make(map[interface{}]interface{}) - return nil -} - -// SessionID get session id of this postgresql session store -func (st *SessionStore) SessionID() string { - return st.sid -} - -// SessionRelease save postgresql session values to database. -// must call this method to save values to database. -func (st *SessionStore) SessionRelease(w http.ResponseWriter) { - defer st.c.Close() - b, err := session.EncodeGob(st.values) - if err != nil { - return - } - st.c.Exec("UPDATE session set session_data=$1, session_expiry=$2 where session_key=$3", - b, time.Now().Format(time.RFC3339), st.sid) - -} - -// Provider postgresql session provider -type Provider struct { - maxlifetime int64 - savePath string -} - -// connect to postgresql -func (mp *Provider) connectInit() *sql.DB { - db, e := sql.Open("postgres", mp.savePath) - if e != nil { - return nil - } - return db -} - -// SessionInit init postgresql session. -// savepath is the connection string of postgresql. -func (mp *Provider) SessionInit(maxlifetime int64, savePath string) error { - mp.maxlifetime = maxlifetime - mp.savePath = savePath - return nil -} - -// SessionRead get postgresql session by sid -func (mp *Provider) SessionRead(sid string) (session.Store, error) { - c := mp.connectInit() - row := c.QueryRow("select session_data from session where session_key=$1", sid) - var sessiondata []byte - err := row.Scan(&sessiondata) - if err == sql.ErrNoRows { - _, err = c.Exec("insert into session(session_key,session_data,session_expiry) values($1,$2,$3)", - sid, "", time.Now().Format(time.RFC3339)) - - if err != nil { - return nil, err - } - } else if err != nil { - return nil, err - } - - var kv map[interface{}]interface{} - if len(sessiondata) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(sessiondata) - if err != nil { - return nil, err - } - } - rs := &SessionStore{c: c, sid: sid, values: kv} - return rs, nil -} - -// SessionExist check postgresql session exist -func (mp *Provider) SessionExist(sid string) bool { - c := mp.connectInit() - defer c.Close() - row := c.QueryRow("select session_data from session where session_key=$1", sid) - var sessiondata []byte - err := row.Scan(&sessiondata) - return !(err == sql.ErrNoRows) -} - -// SessionRegenerate generate new sid for postgresql session -func (mp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) { - c := mp.connectInit() - row := c.QueryRow("select session_data from session where session_key=$1", oldsid) - var sessiondata []byte - err := row.Scan(&sessiondata) - if err == sql.ErrNoRows { - c.Exec("insert into session(session_key,session_data,session_expiry) values($1,$2,$3)", - oldsid, "", time.Now().Format(time.RFC3339)) - } - c.Exec("update session set session_key=$1 where session_key=$2", sid, oldsid) - var kv map[interface{}]interface{} - if len(sessiondata) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(sessiondata) - if err != nil { - return nil, err - } - } - rs := &SessionStore{c: c, sid: sid, values: kv} - return rs, nil -} - -// SessionDestroy delete postgresql session by sid -func (mp *Provider) SessionDestroy(sid string) error { - c := mp.connectInit() - c.Exec("DELETE FROM session where session_key=$1", sid) - c.Close() - return nil -} - -// SessionGC delete expired values in postgresql session -func (mp *Provider) SessionGC() { - c := mp.connectInit() - c.Exec("DELETE from session where EXTRACT(EPOCH FROM (current_timestamp - session_expiry)) > $1", mp.maxlifetime) - c.Close() -} - -// SessionAll count values in postgresql session -func (mp *Provider) SessionAll() int { - c := mp.connectInit() - defer c.Close() - var total int - err := c.QueryRow("SELECT count(*) as num from session").Scan(&total) - if err != nil { - return 0 - } - return total -} - -func init() { - session.Register("postgresql", postgresqlpder) -} diff --git a/vender/github.com/astaxie/beego/session/redis/sess_redis.go b/vender/github.com/astaxie/beego/session/redis/sess_redis.go deleted file mode 100755 index e28b03b..0000000 --- a/vender/github.com/astaxie/beego/session/redis/sess_redis.go +++ /dev/null @@ -1,261 +0,0 @@ -// 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 session provider -// -// depend on github.com/gomodule/redigo/redis -// -// go install github.com/gomodule/redigo/redis -// -// Usage: -// import( -// _ "github.com/cnlh/nps/vender/github.com/astaxie/beego/session/redis" -// "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" -// ) -// -// func init() { -// globalSessions, _ = session.NewManager("redis", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:7070"}``) -// go globalSessions.GC() -// } -// -// more docs: http://beego.me/docs/module/session.md -package redis - -import ( - "net/http" - "strconv" - "strings" - "sync" - "time" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" - - "github.com/gomodule/redigo/redis" -) - -var redispder = &Provider{} - -// MaxPoolSize redis max pool size -var MaxPoolSize = 100 - -// SessionStore redis session store -type SessionStore struct { - p *redis.Pool - sid string - lock sync.RWMutex - values map[interface{}]interface{} - maxlifetime int64 -} - -// Set value in redis session -func (rs *SessionStore) Set(key, value interface{}) error { - rs.lock.Lock() - defer rs.lock.Unlock() - rs.values[key] = value - return nil -} - -// Get value in redis session -func (rs *SessionStore) Get(key interface{}) interface{} { - rs.lock.RLock() - defer rs.lock.RUnlock() - if v, ok := rs.values[key]; ok { - return v - } - return nil -} - -// Delete value in redis session -func (rs *SessionStore) Delete(key interface{}) error { - rs.lock.Lock() - defer rs.lock.Unlock() - delete(rs.values, key) - return nil -} - -// Flush clear all values in redis session -func (rs *SessionStore) Flush() error { - rs.lock.Lock() - defer rs.lock.Unlock() - rs.values = make(map[interface{}]interface{}) - return nil -} - -// SessionID get redis session id -func (rs *SessionStore) SessionID() string { - return rs.sid -} - -// SessionRelease save session values to redis -func (rs *SessionStore) SessionRelease(w http.ResponseWriter) { - b, err := session.EncodeGob(rs.values) - if err != nil { - return - } - c := rs.p.Get() - defer c.Close() - c.Do("SETEX", rs.sid, rs.maxlifetime, string(b)) -} - -// Provider redis session provider -type Provider struct { - maxlifetime int64 - savePath string - poolsize int - password string - dbNum int - poollist *redis.Pool -} - -// SessionInit init redis session -// savepath like redis server addr,pool size,password,dbnum,IdleTimeout second -// e.g. 127.0.0.1:6379,100,astaxie,0,30 -func (rp *Provider) SessionInit(maxlifetime int64, savePath string) error { - rp.maxlifetime = maxlifetime - configs := strings.Split(savePath, ",") - if len(configs) > 0 { - rp.savePath = configs[0] - } - if len(configs) > 1 { - poolsize, err := strconv.Atoi(configs[1]) - if err != nil || poolsize < 0 { - rp.poolsize = MaxPoolSize - } else { - rp.poolsize = poolsize - } - } else { - rp.poolsize = MaxPoolSize - } - if len(configs) > 2 { - rp.password = configs[2] - } - if len(configs) > 3 { - dbnum, err := strconv.Atoi(configs[3]) - if err != nil || dbnum < 0 { - rp.dbNum = 0 - } else { - rp.dbNum = dbnum - } - } else { - rp.dbNum = 0 - } - var idleTimeout time.Duration = 0 - if len(configs) > 4 { - timeout, err := strconv.Atoi(configs[4]) - if err == nil && timeout > 0 { - idleTimeout = time.Duration(timeout) * time.Second - } - } - rp.poollist = &redis.Pool{ - Dial: func() (redis.Conn, error) { - c, err := redis.Dial("tcp", rp.savePath) - if err != nil { - return nil, err - } - if rp.password != "" { - if _, err = c.Do("AUTH", rp.password); err != nil { - c.Close() - return nil, err - } - } - // some redis proxy such as twemproxy is not support select command - if rp.dbNum > 0 { - _, err = c.Do("SELECT", rp.dbNum) - if err != nil { - c.Close() - return nil, err - } - } - return c, err - }, - MaxIdle: rp.poolsize, - } - - rp.poollist.IdleTimeout = idleTimeout - - return rp.poollist.Get().Err() -} - -// SessionRead read redis session by sid -func (rp *Provider) SessionRead(sid string) (session.Store, error) { - c := rp.poollist.Get() - defer c.Close() - - var kv map[interface{}]interface{} - - kvs, err := redis.String(c.Do("GET", sid)) - if err != nil && err != redis.ErrNil { - return nil, err - } - if len(kvs) == 0 { - kv = make(map[interface{}]interface{}) - } else { - if kv, err = session.DecodeGob([]byte(kvs)); err != nil { - return nil, err - } - } - - rs := &SessionStore{p: rp.poollist, sid: sid, values: kv, maxlifetime: rp.maxlifetime} - return rs, nil -} - -// SessionExist check redis session exist by sid -func (rp *Provider) SessionExist(sid string) bool { - c := rp.poollist.Get() - defer c.Close() - - if existed, err := redis.Int(c.Do("EXISTS", sid)); err != nil || existed == 0 { - return false - } - return true -} - -// SessionRegenerate generate new sid for redis session -func (rp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) { - c := rp.poollist.Get() - defer c.Close() - - if existed, _ := redis.Int(c.Do("EXISTS", oldsid)); existed == 0 { - // oldsid doesn't exists, set the new sid directly - // ignore error here, since if it return error - // the existed value will be 0 - c.Do("SET", sid, "", "EX", rp.maxlifetime) - } else { - c.Do("RENAME", oldsid, sid) - c.Do("EXPIRE", sid, rp.maxlifetime) - } - return rp.SessionRead(sid) -} - -// SessionDestroy delete redis session by id -func (rp *Provider) SessionDestroy(sid string) error { - c := rp.poollist.Get() - defer c.Close() - - c.Do("DEL", sid) - return nil -} - -// SessionGC Impelment method, no used. -func (rp *Provider) SessionGC() { -} - -// SessionAll return all activeSession -func (rp *Provider) SessionAll() int { - return 0 -} - -func init() { - session.Register("redis", redispder) -} diff --git a/vender/github.com/astaxie/beego/session/redis_cluster/redis_cluster.go b/vender/github.com/astaxie/beego/session/redis_cluster/redis_cluster.go deleted file mode 100755 index 9adff11..0000000 --- a/vender/github.com/astaxie/beego/session/redis_cluster/redis_cluster.go +++ /dev/null @@ -1,221 +0,0 @@ -// 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 session provider -// -// depend on github.com/go-redis/redis -// -// go install github.com/go-redis/redis -// -// Usage: -// import( -// _ "github.com/cnlh/nps/vender/github.com/astaxie/beego/session/redis_cluster" -// "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" -// ) -// -// func init() { -// globalSessions, _ = session.NewManager("redis_cluster", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:7070;127.0.0.1:7071"}``) -// go globalSessions.GC() -// } -// -// more docs: http://beego.me/docs/module/session.md -package redis_cluster - -import ( - "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" - rediss "github.com/go-redis/redis" - "net/http" - "strconv" - "strings" - "sync" - "time" -) - -var redispder = &Provider{} - -// MaxPoolSize redis_cluster max pool size -var MaxPoolSize = 1000 - -// SessionStore redis_cluster session store -type SessionStore struct { - p *rediss.ClusterClient - sid string - lock sync.RWMutex - values map[interface{}]interface{} - maxlifetime int64 -} - -// Set value in redis_cluster session -func (rs *SessionStore) Set(key, value interface{}) error { - rs.lock.Lock() - defer rs.lock.Unlock() - rs.values[key] = value - return nil -} - -// Get value in redis_cluster session -func (rs *SessionStore) Get(key interface{}) interface{} { - rs.lock.RLock() - defer rs.lock.RUnlock() - if v, ok := rs.values[key]; ok { - return v - } - return nil -} - -// Delete value in redis_cluster session -func (rs *SessionStore) Delete(key interface{}) error { - rs.lock.Lock() - defer rs.lock.Unlock() - delete(rs.values, key) - return nil -} - -// Flush clear all values in redis_cluster session -func (rs *SessionStore) Flush() error { - rs.lock.Lock() - defer rs.lock.Unlock() - rs.values = make(map[interface{}]interface{}) - return nil -} - -// SessionID get redis_cluster session id -func (rs *SessionStore) SessionID() string { - return rs.sid -} - -// SessionRelease save session values to redis_cluster -func (rs *SessionStore) SessionRelease(w http.ResponseWriter) { - b, err := session.EncodeGob(rs.values) - if err != nil { - return - } - c := rs.p - c.Set(rs.sid, string(b), time.Duration(rs.maxlifetime)*time.Second) -} - -// Provider redis_cluster session provider -type Provider struct { - maxlifetime int64 - savePath string - poolsize int - password string - dbNum int - poollist *rediss.ClusterClient -} - -// SessionInit init redis_cluster session -// savepath like redis server addr,pool size,password,dbnum -// e.g. 127.0.0.1:6379;127.0.0.1:6380,100,test,0 -func (rp *Provider) SessionInit(maxlifetime int64, savePath string) error { - rp.maxlifetime = maxlifetime - configs := strings.Split(savePath, ",") - if len(configs) > 0 { - rp.savePath = configs[0] - } - if len(configs) > 1 { - poolsize, err := strconv.Atoi(configs[1]) - if err != nil || poolsize < 0 { - rp.poolsize = MaxPoolSize - } else { - rp.poolsize = poolsize - } - } else { - rp.poolsize = MaxPoolSize - } - if len(configs) > 2 { - rp.password = configs[2] - } - if len(configs) > 3 { - dbnum, err := strconv.Atoi(configs[3]) - if err != nil || dbnum < 0 { - rp.dbNum = 0 - } else { - rp.dbNum = dbnum - } - } else { - rp.dbNum = 0 - } - - rp.poollist = rediss.NewClusterClient(&rediss.ClusterOptions{ - Addrs: strings.Split(rp.savePath, ";"), - Password: rp.password, - PoolSize: rp.poolsize, - }) - return rp.poollist.Ping().Err() -} - -// SessionRead read redis_cluster session by sid -func (rp *Provider) SessionRead(sid string) (session.Store, error) { - var kv map[interface{}]interface{} - kvs, err := rp.poollist.Get(sid).Result() - if err != nil && err != rediss.Nil { - return nil, err - } - if len(kvs) == 0 { - kv = make(map[interface{}]interface{}) - } else { - if kv, err = session.DecodeGob([]byte(kvs)); err != nil { - return nil, err - } - } - - rs := &SessionStore{p: rp.poollist, sid: sid, values: kv, maxlifetime: rp.maxlifetime} - return rs, nil -} - -// SessionExist check redis_cluster session exist by sid -func (rp *Provider) SessionExist(sid string) bool { - c := rp.poollist - if existed, err := c.Exists(sid).Result(); err != nil || existed == 0 { - return false - } - return true -} - -// SessionRegenerate generate new sid for redis_cluster session -func (rp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) { - c := rp.poollist - - if existed, err := c.Exists(oldsid).Result(); err != nil || existed == 0 { - // oldsid doesn't exists, set the new sid directly - // ignore error here, since if it return error - // the existed value will be 0 - c.Set(sid, "", time.Duration(rp.maxlifetime)*time.Second) - } else { - c.Rename(oldsid, sid) - c.Expire(sid, time.Duration(rp.maxlifetime)*time.Second) - } - return rp.SessionRead(sid) -} - -// SessionDestroy delete redis session by id -func (rp *Provider) SessionDestroy(sid string) error { - c := rp.poollist - c.Del(sid) - return nil -} - -// SessionGC Impelment method, no used. -func (rp *Provider) SessionGC() { -} - -// SessionAll return all activeSession -func (rp *Provider) SessionAll() int { - return 0 -} - -func init() { - session.Register("redis_cluster", redispder) -} diff --git a/vender/github.com/astaxie/beego/session/sess_cookie.go b/vender/github.com/astaxie/beego/session/sess_cookie.go deleted file mode 100755 index 145e53c..0000000 --- a/vender/github.com/astaxie/beego/session/sess_cookie.go +++ /dev/null @@ -1,178 +0,0 @@ -// 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 session - -import ( - "crypto/aes" - "crypto/cipher" - "encoding/json" - "net/http" - "net/url" - "sync" -) - -var cookiepder = &CookieProvider{} - -// CookieSessionStore Cookie SessionStore -type CookieSessionStore struct { - sid string - values map[interface{}]interface{} // session data - lock sync.RWMutex -} - -// Set value to cookie session. -// the value are encoded as gob with hash block string. -func (st *CookieSessionStore) Set(key, value interface{}) error { - st.lock.Lock() - defer st.lock.Unlock() - st.values[key] = value - return nil -} - -// Get value from cookie session -func (st *CookieSessionStore) Get(key interface{}) interface{} { - st.lock.RLock() - defer st.lock.RUnlock() - if v, ok := st.values[key]; ok { - return v - } - return nil -} - -// Delete value in cookie session -func (st *CookieSessionStore) Delete(key interface{}) error { - st.lock.Lock() - defer st.lock.Unlock() - delete(st.values, key) - return nil -} - -// Flush Clean all values in cookie session -func (st *CookieSessionStore) Flush() error { - st.lock.Lock() - defer st.lock.Unlock() - st.values = make(map[interface{}]interface{}) - return nil -} - -// SessionID Return id of this cookie session -func (st *CookieSessionStore) SessionID() string { - return st.sid -} - -// SessionRelease Write cookie session to http response cookie -func (st *CookieSessionStore) SessionRelease(w http.ResponseWriter) { - encodedCookie, err := encodeCookie(cookiepder.block, cookiepder.config.SecurityKey, cookiepder.config.SecurityName, st.values) - if err == nil { - cookie := &http.Cookie{Name: cookiepder.config.CookieName, - Value: url.QueryEscape(encodedCookie), - Path: "/", - HttpOnly: true, - Secure: cookiepder.config.Secure, - MaxAge: cookiepder.config.Maxage} - http.SetCookie(w, cookie) - } -} - -type cookieConfig struct { - SecurityKey string `json:"securityKey"` - BlockKey string `json:"blockKey"` - SecurityName string `json:"securityName"` - CookieName string `json:"cookieName"` - Secure bool `json:"secure"` - Maxage int `json:"maxage"` -} - -// CookieProvider Cookie session provider -type CookieProvider struct { - maxlifetime int64 - config *cookieConfig - block cipher.Block -} - -// SessionInit Init cookie session provider with max lifetime and config json. -// maxlifetime is ignored. -// json config: -// securityKey - hash string -// blockKey - gob encode hash string. it's saved as aes crypto. -// securityName - recognized name in encoded cookie string -// cookieName - cookie name -// maxage - cookie max life time. -func (pder *CookieProvider) SessionInit(maxlifetime int64, config string) error { - pder.config = &cookieConfig{} - err := json.Unmarshal([]byte(config), pder.config) - if err != nil { - return err - } - if pder.config.BlockKey == "" { - pder.config.BlockKey = string(generateRandomKey(16)) - } - if pder.config.SecurityName == "" { - pder.config.SecurityName = string(generateRandomKey(20)) - } - pder.block, err = aes.NewCipher([]byte(pder.config.BlockKey)) - if err != nil { - return err - } - pder.maxlifetime = maxlifetime - return nil -} - -// SessionRead Get SessionStore in cooke. -// decode cooke string to map and put into SessionStore with sid. -func (pder *CookieProvider) SessionRead(sid string) (Store, error) { - maps, _ := decodeCookie(pder.block, - pder.config.SecurityKey, - pder.config.SecurityName, - sid, pder.maxlifetime) - if maps == nil { - maps = make(map[interface{}]interface{}) - } - rs := &CookieSessionStore{sid: sid, values: maps} - return rs, nil -} - -// SessionExist Cookie session is always existed -func (pder *CookieProvider) SessionExist(sid string) bool { - return true -} - -// SessionRegenerate Implement method, no used. -func (pder *CookieProvider) SessionRegenerate(oldsid, sid string) (Store, error) { - return nil, nil -} - -// SessionDestroy Implement method, no used. -func (pder *CookieProvider) SessionDestroy(sid string) error { - return nil -} - -// SessionGC Implement method, no used. -func (pder *CookieProvider) SessionGC() { -} - -// SessionAll Implement method, return 0. -func (pder *CookieProvider) SessionAll() int { - return 0 -} - -// SessionUpdate Implement method, no used. -func (pder *CookieProvider) SessionUpdate(sid string) error { - return nil -} - -func init() { - Register("cookie", cookiepder) -} diff --git a/vender/github.com/astaxie/beego/session/sess_cookie_test.go b/vender/github.com/astaxie/beego/session/sess_cookie_test.go deleted file mode 100755 index b672600..0000000 --- a/vender/github.com/astaxie/beego/session/sess_cookie_test.go +++ /dev/null @@ -1,105 +0,0 @@ -// 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 session - -import ( - "encoding/json" - "net/http" - "net/http/httptest" - "strings" - "testing" -) - -func TestCookie(t *testing.T) { - config := `{"cookieName":"gosessionid","enableSetCookie":false,"gclifetime":3600,"ProviderConfig":"{\"cookieName\":\"gosessionid\",\"securityKey\":\"beegocookiehashkey\"}"}` - conf := new(ManagerConfig) - if err := json.Unmarshal([]byte(config), conf); err != nil { - t.Fatal("json decode error", err) - } - globalSessions, err := NewManager("cookie", conf) - if err != nil { - t.Fatal("init cookie session err", err) - } - r, _ := http.NewRequest("GET", "/", nil) - w := httptest.NewRecorder() - sess, err := globalSessions.SessionStart(w, r) - if err != nil { - t.Fatal("set error,", err) - } - err = sess.Set("username", "astaxie") - if err != nil { - t.Fatal("set error,", err) - } - if username := sess.Get("username"); username != "astaxie" { - t.Fatal("get username error") - } - sess.SessionRelease(w) - if cookiestr := w.Header().Get("Set-Cookie"); cookiestr == "" { - t.Fatal("setcookie error") - } else { - parts := strings.Split(strings.TrimSpace(cookiestr), ";") - for k, v := range parts { - nameval := strings.Split(v, "=") - if k == 0 && nameval[0] != "gosessionid" { - t.Fatal("error") - } - } - } -} - -func TestDestorySessionCookie(t *testing.T) { - config := `{"cookieName":"gosessionid","enableSetCookie":true,"gclifetime":3600,"ProviderConfig":"{\"cookieName\":\"gosessionid\",\"securityKey\":\"beegocookiehashkey\"}"}` - conf := new(ManagerConfig) - if err := json.Unmarshal([]byte(config), conf); err != nil { - t.Fatal("json decode error", err) - } - globalSessions, err := NewManager("cookie", conf) - if err != nil { - t.Fatal("init cookie session err", err) - } - - r, _ := http.NewRequest("GET", "/", nil) - w := httptest.NewRecorder() - session, err := globalSessions.SessionStart(w, r) - if err != nil { - t.Fatal("session start err,", err) - } - - // request again ,will get same sesssion id . - r1, _ := http.NewRequest("GET", "/", nil) - r1.Header.Set("Cookie", w.Header().Get("Set-Cookie")) - w = httptest.NewRecorder() - newSession, err := globalSessions.SessionStart(w, r1) - if err != nil { - t.Fatal("session start err,", err) - } - if newSession.SessionID() != session.SessionID() { - t.Fatal("get cookie session id is not the same again.") - } - - // After destroy session , will get a new session id . - globalSessions.SessionDestroy(w, r1) - r2, _ := http.NewRequest("GET", "/", nil) - r2.Header.Set("Cookie", w.Header().Get("Set-Cookie")) - - w = httptest.NewRecorder() - newSession, err = globalSessions.SessionStart(w, r2) - if err != nil { - t.Fatal("session start error") - } - if newSession.SessionID() == session.SessionID() { - t.Fatal("after destroy session and reqeust again ,get cookie session id is same.") - } -} diff --git a/vender/github.com/astaxie/beego/session/sess_file.go b/vender/github.com/astaxie/beego/session/sess_file.go deleted file mode 100755 index 53e1981..0000000 --- a/vender/github.com/astaxie/beego/session/sess_file.go +++ /dev/null @@ -1,301 +0,0 @@ -// 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 session - -import ( - "fmt" - "io/ioutil" - "net/http" - "os" - "path" - "path/filepath" - "sync" - "time" -) - -var ( - filepder = &FileProvider{} - gcmaxlifetime int64 -) - -// FileSessionStore File session store -type FileSessionStore struct { - sid string - lock sync.RWMutex - values map[interface{}]interface{} -} - -// Set value to file session -func (fs *FileSessionStore) Set(key, value interface{}) error { - fs.lock.Lock() - defer fs.lock.Unlock() - fs.values[key] = value - return nil -} - -// Get value from file session -func (fs *FileSessionStore) Get(key interface{}) interface{} { - fs.lock.RLock() - defer fs.lock.RUnlock() - if v, ok := fs.values[key]; ok { - return v - } - return nil -} - -// Delete value in file session by given key -func (fs *FileSessionStore) Delete(key interface{}) error { - fs.lock.Lock() - defer fs.lock.Unlock() - delete(fs.values, key) - return nil -} - -// Flush Clean all values in file session -func (fs *FileSessionStore) Flush() error { - fs.lock.Lock() - defer fs.lock.Unlock() - fs.values = make(map[interface{}]interface{}) - return nil -} - -// SessionID Get file session store id -func (fs *FileSessionStore) SessionID() string { - return fs.sid -} - -// SessionRelease Write file session to local file with Gob string -func (fs *FileSessionStore) SessionRelease(w http.ResponseWriter) { - filepder.lock.Lock() - defer filepder.lock.Unlock() - b, err := EncodeGob(fs.values) - if err != nil { - SLogger.Println(err) - return - } - _, err = os.Stat(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid)) - var f *os.File - if err == nil { - f, err = os.OpenFile(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid), os.O_RDWR, 0777) - if err != nil { - SLogger.Println(err) - return - } - } else if os.IsNotExist(err) { - f, err = os.Create(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid)) - if err != nil { - SLogger.Println(err) - return - } - } else { - return - } - f.Truncate(0) - f.Seek(0, 0) - f.Write(b) - f.Close() -} - -// FileProvider File session provider -type FileProvider struct { - lock sync.RWMutex - maxlifetime int64 - savePath string -} - -// SessionInit Init file session provider. -// savePath sets the session files path. -func (fp *FileProvider) SessionInit(maxlifetime int64, savePath string) error { - fp.maxlifetime = maxlifetime - fp.savePath = savePath - return nil -} - -// SessionRead Read file session by sid. -// if file is not exist, create it. -// the file path is generated from sid string. -func (fp *FileProvider) SessionRead(sid string) (Store, error) { - filepder.lock.Lock() - defer filepder.lock.Unlock() - - err := os.MkdirAll(path.Join(fp.savePath, string(sid[0]), string(sid[1])), 0777) - if err != nil { - SLogger.Println(err.Error()) - } - _, err = os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid)) - var f *os.File - if err == nil { - f, err = os.OpenFile(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), os.O_RDWR, 0777) - } else if os.IsNotExist(err) { - f, err = os.Create(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid)) - } else { - return nil, err - } - - defer f.Close() - - os.Chtimes(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), time.Now(), time.Now()) - var kv map[interface{}]interface{} - b, err := ioutil.ReadAll(f) - if err != nil { - return nil, err - } - if len(b) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = DecodeGob(b) - if err != nil { - return nil, err - } - } - - ss := &FileSessionStore{sid: sid, values: kv} - return ss, nil -} - -// SessionExist Check file session exist. -// it checks the file named from sid exist or not. -func (fp *FileProvider) SessionExist(sid string) bool { - filepder.lock.Lock() - defer filepder.lock.Unlock() - - _, err := os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid)) - return err == nil -} - -// SessionDestroy Remove all files in this save path -func (fp *FileProvider) SessionDestroy(sid string) error { - filepder.lock.Lock() - defer filepder.lock.Unlock() - os.Remove(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid)) - return nil -} - -// SessionGC Recycle files in save path -func (fp *FileProvider) SessionGC() { - filepder.lock.Lock() - defer filepder.lock.Unlock() - - gcmaxlifetime = fp.maxlifetime - filepath.Walk(fp.savePath, gcpath) -} - -// SessionAll Get active file session number. -// it walks save path to count files. -func (fp *FileProvider) SessionAll() int { - a := &activeSession{} - err := filepath.Walk(fp.savePath, func(path string, f os.FileInfo, err error) error { - return a.visit(path, f, err) - }) - if err != nil { - SLogger.Printf("filepath.Walk() returned %v\n", err) - return 0 - } - return a.total -} - -// SessionRegenerate Generate new sid for file session. -// it delete old file and create new file named from new sid. -func (fp *FileProvider) SessionRegenerate(oldsid, sid string) (Store, error) { - filepder.lock.Lock() - defer filepder.lock.Unlock() - - oldPath := path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1])) - oldSidFile := path.Join(oldPath, oldsid) - newPath := path.Join(fp.savePath, string(sid[0]), string(sid[1])) - newSidFile := path.Join(newPath, sid) - - // new sid file is exist - _, err := os.Stat(newSidFile) - if err == nil { - return nil, fmt.Errorf("newsid %s exist", newSidFile) - } - - err = os.MkdirAll(newPath, 0777) - if err != nil { - SLogger.Println(err.Error()) - } - - // if old sid file exist - // 1.read and parse file content - // 2.write content to new sid file - // 3.remove old sid file, change new sid file atime and ctime - // 4.return FileSessionStore - _, err = os.Stat(oldSidFile) - if err == nil { - b, err := ioutil.ReadFile(oldSidFile) - if err != nil { - return nil, err - } - - var kv map[interface{}]interface{} - if len(b) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = DecodeGob(b) - if err != nil { - return nil, err - } - } - - ioutil.WriteFile(newSidFile, b, 0777) - os.Remove(oldSidFile) - os.Chtimes(newSidFile, time.Now(), time.Now()) - ss := &FileSessionStore{sid: sid, values: kv} - return ss, nil - } - - // if old sid file not exist, just create new sid file and return - newf, err := os.Create(newSidFile) - if err != nil { - return nil, err - } - newf.Close() - ss := &FileSessionStore{sid: sid, values: make(map[interface{}]interface{})} - return ss, nil -} - -// remove file in save path if expired -func gcpath(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if info.IsDir() { - return nil - } - if (info.ModTime().Unix() + gcmaxlifetime) < time.Now().Unix() { - os.Remove(path) - } - return nil -} - -type activeSession struct { - total int -} - -func (as *activeSession) visit(paths string, f os.FileInfo, err error) error { - if err != nil { - return err - } - if f.IsDir() { - return nil - } - as.total = as.total + 1 - return nil -} - -func init() { - Register("file", filepder) -} diff --git a/vender/github.com/astaxie/beego/session/sess_mem.go b/vender/github.com/astaxie/beego/session/sess_mem.go deleted file mode 100755 index 64d8b05..0000000 --- a/vender/github.com/astaxie/beego/session/sess_mem.go +++ /dev/null @@ -1,196 +0,0 @@ -// 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 session - -import ( - "container/list" - "net/http" - "sync" - "time" -) - -var mempder = &MemProvider{list: list.New(), sessions: make(map[string]*list.Element)} - -// MemSessionStore memory session store. -// it saved sessions in a map in memory. -type MemSessionStore struct { - sid string //session id - timeAccessed time.Time //last access time - value map[interface{}]interface{} //session store - lock sync.RWMutex -} - -// Set value to memory session -func (st *MemSessionStore) Set(key, value interface{}) error { - st.lock.Lock() - defer st.lock.Unlock() - st.value[key] = value - return nil -} - -// Get value from memory session by key -func (st *MemSessionStore) Get(key interface{}) interface{} { - st.lock.RLock() - defer st.lock.RUnlock() - if v, ok := st.value[key]; ok { - return v - } - return nil -} - -// Delete in memory session by key -func (st *MemSessionStore) Delete(key interface{}) error { - st.lock.Lock() - defer st.lock.Unlock() - delete(st.value, key) - return nil -} - -// Flush clear all values in memory session -func (st *MemSessionStore) Flush() error { - st.lock.Lock() - defer st.lock.Unlock() - st.value = make(map[interface{}]interface{}) - return nil -} - -// SessionID get this id of memory session store -func (st *MemSessionStore) SessionID() string { - return st.sid -} - -// SessionRelease Implement method, no used. -func (st *MemSessionStore) SessionRelease(w http.ResponseWriter) { -} - -// MemProvider Implement the provider interface -type MemProvider struct { - lock sync.RWMutex // locker - sessions map[string]*list.Element // map in memory - list *list.List // for gc - maxlifetime int64 - savePath string -} - -// SessionInit init memory session -func (pder *MemProvider) SessionInit(maxlifetime int64, savePath string) error { - pder.maxlifetime = maxlifetime - pder.savePath = savePath - return nil -} - -// SessionRead get memory session store by sid -func (pder *MemProvider) SessionRead(sid string) (Store, error) { - pder.lock.RLock() - if element, ok := pder.sessions[sid]; ok { - go pder.SessionUpdate(sid) - pder.lock.RUnlock() - return element.Value.(*MemSessionStore), nil - } - pder.lock.RUnlock() - pder.lock.Lock() - newsess := &MemSessionStore{sid: sid, timeAccessed: time.Now(), value: make(map[interface{}]interface{})} - element := pder.list.PushFront(newsess) - pder.sessions[sid] = element - pder.lock.Unlock() - return newsess, nil -} - -// SessionExist check session store exist in memory session by sid -func (pder *MemProvider) SessionExist(sid string) bool { - pder.lock.RLock() - defer pder.lock.RUnlock() - if _, ok := pder.sessions[sid]; ok { - return true - } - return false -} - -// SessionRegenerate generate new sid for session store in memory session -func (pder *MemProvider) SessionRegenerate(oldsid, sid string) (Store, error) { - pder.lock.RLock() - if element, ok := pder.sessions[oldsid]; ok { - go pder.SessionUpdate(oldsid) - pder.lock.RUnlock() - pder.lock.Lock() - element.Value.(*MemSessionStore).sid = sid - pder.sessions[sid] = element - delete(pder.sessions, oldsid) - pder.lock.Unlock() - return element.Value.(*MemSessionStore), nil - } - pder.lock.RUnlock() - pder.lock.Lock() - newsess := &MemSessionStore{sid: sid, timeAccessed: time.Now(), value: make(map[interface{}]interface{})} - element := pder.list.PushFront(newsess) - pder.sessions[sid] = element - pder.lock.Unlock() - return newsess, nil -} - -// SessionDestroy delete session store in memory session by id -func (pder *MemProvider) SessionDestroy(sid string) error { - pder.lock.Lock() - defer pder.lock.Unlock() - if element, ok := pder.sessions[sid]; ok { - delete(pder.sessions, sid) - pder.list.Remove(element) - return nil - } - return nil -} - -// SessionGC clean expired session stores in memory session -func (pder *MemProvider) SessionGC() { - pder.lock.RLock() - for { - element := pder.list.Back() - if element == nil { - break - } - if (element.Value.(*MemSessionStore).timeAccessed.Unix() + pder.maxlifetime) < time.Now().Unix() { - pder.lock.RUnlock() - pder.lock.Lock() - pder.list.Remove(element) - delete(pder.sessions, element.Value.(*MemSessionStore).sid) - pder.lock.Unlock() - pder.lock.RLock() - } else { - break - } - } - pder.lock.RUnlock() -} - -// SessionAll get count number of memory session -func (pder *MemProvider) SessionAll() int { - return pder.list.Len() -} - -// SessionUpdate expand time of session store by id in memory session -func (pder *MemProvider) SessionUpdate(sid string) error { - pder.lock.Lock() - defer pder.lock.Unlock() - if element, ok := pder.sessions[sid]; ok { - element.Value.(*MemSessionStore).timeAccessed = time.Now() - pder.list.MoveToFront(element) - return nil - } - return nil -} - -func init() { - Register("memory", mempder) -} diff --git a/vender/github.com/astaxie/beego/session/sess_mem_test.go b/vender/github.com/astaxie/beego/session/sess_mem_test.go deleted file mode 100755 index 2e8934b..0000000 --- a/vender/github.com/astaxie/beego/session/sess_mem_test.go +++ /dev/null @@ -1,58 +0,0 @@ -// 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 session - -import ( - "encoding/json" - "net/http" - "net/http/httptest" - "strings" - "testing" -) - -func TestMem(t *testing.T) { - config := `{"cookieName":"gosessionid","gclifetime":10, "enableSetCookie":true}` - conf := new(ManagerConfig) - if err := json.Unmarshal([]byte(config), conf); err != nil { - t.Fatal("json decode error", err) - } - globalSessions, _ := NewManager("memory", conf) - go globalSessions.GC() - r, _ := http.NewRequest("GET", "/", nil) - w := httptest.NewRecorder() - sess, err := globalSessions.SessionStart(w, r) - if err != nil { - t.Fatal("set error,", err) - } - defer sess.SessionRelease(w) - err = sess.Set("username", "astaxie") - if err != nil { - t.Fatal("set error,", err) - } - if username := sess.Get("username"); username != "astaxie" { - t.Fatal("get username error") - } - if cookiestr := w.Header().Get("Set-Cookie"); cookiestr == "" { - t.Fatal("setcookie error") - } else { - parts := strings.Split(strings.TrimSpace(cookiestr), ";") - for k, v := range parts { - nameval := strings.Split(v, "=") - if k == 0 && nameval[0] != "gosessionid" { - t.Fatal("error") - } - } - } -} diff --git a/vender/github.com/astaxie/beego/session/sess_test.go b/vender/github.com/astaxie/beego/session/sess_test.go deleted file mode 100755 index 906abec..0000000 --- a/vender/github.com/astaxie/beego/session/sess_test.go +++ /dev/null @@ -1,131 +0,0 @@ -// 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 session - -import ( - "crypto/aes" - "encoding/json" - "testing" -) - -func Test_gob(t *testing.T) { - a := make(map[interface{}]interface{}) - a["username"] = "astaxie" - a[12] = 234 - a["user"] = User{"asta", "xie"} - b, err := EncodeGob(a) - if err != nil { - t.Error(err) - } - c, err := DecodeGob(b) - if err != nil { - t.Error(err) - } - if len(c) == 0 { - t.Error("decodeGob empty") - } - if c["username"] != "astaxie" { - t.Error("decode string error") - } - if c[12] != 234 { - t.Error("decode int error") - } - if c["user"].(User).Username != "asta" { - t.Error("decode struct error") - } -} - -type User struct { - Username string - NickName string -} - -func TestGenerate(t *testing.T) { - str := generateRandomKey(20) - if len(str) != 20 { - t.Fatal("generate length is not equal to 20") - } -} - -func TestCookieEncodeDecode(t *testing.T) { - hashKey := "testhashKey" - blockkey := generateRandomKey(16) - block, err := aes.NewCipher(blockkey) - if err != nil { - t.Fatal("NewCipher:", err) - } - securityName := string(generateRandomKey(20)) - val := make(map[interface{}]interface{}) - val["name"] = "astaxie" - val["gender"] = "male" - str, err := encodeCookie(block, hashKey, securityName, val) - if err != nil { - t.Fatal("encodeCookie:", err) - } - dst, err := decodeCookie(block, hashKey, securityName, str, 3600) - if err != nil { - t.Fatal("decodeCookie", err) - } - if dst["name"] != "astaxie" { - t.Fatal("dst get map error") - } - if dst["gender"] != "male" { - t.Fatal("dst get map error") - } -} - -func TestParseConfig(t *testing.T) { - s := `{"cookieName":"gosessionid","gclifetime":3600}` - cf := new(ManagerConfig) - cf.EnableSetCookie = true - err := json.Unmarshal([]byte(s), cf) - if err != nil { - t.Fatal("parse json error,", err) - } - if cf.CookieName != "gosessionid" { - t.Fatal("parseconfig get cookiename error") - } - if cf.Gclifetime != 3600 { - t.Fatal("parseconfig get gclifetime error") - } - - cc := `{"cookieName":"gosessionid","enableSetCookie":false,"gclifetime":3600,"ProviderConfig":"{\"cookieName\":\"gosessionid\",\"securityKey\":\"beegocookiehashkey\"}"}` - cf2 := new(ManagerConfig) - cf2.EnableSetCookie = true - err = json.Unmarshal([]byte(cc), cf2) - if err != nil { - t.Fatal("parse json error,", err) - } - if cf2.CookieName != "gosessionid" { - t.Fatal("parseconfig get cookiename error") - } - if cf2.Gclifetime != 3600 { - t.Fatal("parseconfig get gclifetime error") - } - if cf2.EnableSetCookie { - t.Fatal("parseconfig get enableSetCookie error") - } - cconfig := new(cookieConfig) - err = json.Unmarshal([]byte(cf2.ProviderConfig), cconfig) - if err != nil { - t.Fatal("parse ProviderConfig err,", err) - } - if cconfig.CookieName != "gosessionid" { - t.Fatal("ProviderConfig get cookieName error") - } - if cconfig.SecurityKey != "beegocookiehashkey" { - t.Fatal("ProviderConfig get securityKey error") - } -} diff --git a/vender/github.com/astaxie/beego/session/sess_utils.go b/vender/github.com/astaxie/beego/session/sess_utils.go deleted file mode 100755 index 52ee894..0000000 --- a/vender/github.com/astaxie/beego/session/sess_utils.go +++ /dev/null @@ -1,207 +0,0 @@ -// 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 session - -import ( - "bytes" - "crypto/cipher" - "crypto/hmac" - "crypto/rand" - "crypto/sha1" - "crypto/subtle" - "encoding/base64" - "encoding/gob" - "errors" - "fmt" - "io" - "strconv" - "time" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/utils" -) - -func init() { - gob.Register([]interface{}{}) - gob.Register(map[int]interface{}{}) - gob.Register(map[string]interface{}{}) - gob.Register(map[interface{}]interface{}{}) - gob.Register(map[string]string{}) - gob.Register(map[int]string{}) - gob.Register(map[int]int{}) - gob.Register(map[int]int64{}) -} - -// EncodeGob encode the obj to gob -func EncodeGob(obj map[interface{}]interface{}) ([]byte, error) { - for _, v := range obj { - gob.Register(v) - } - buf := bytes.NewBuffer(nil) - enc := gob.NewEncoder(buf) - err := enc.Encode(obj) - if err != nil { - return []byte(""), err - } - return buf.Bytes(), nil -} - -// DecodeGob decode data to map -func DecodeGob(encoded []byte) (map[interface{}]interface{}, error) { - buf := bytes.NewBuffer(encoded) - dec := gob.NewDecoder(buf) - var out map[interface{}]interface{} - err := dec.Decode(&out) - if err != nil { - return nil, err - } - return out, nil -} - -// generateRandomKey creates a random key with the given strength. -func generateRandomKey(strength int) []byte { - k := make([]byte, strength) - if n, err := io.ReadFull(rand.Reader, k); n != strength || err != nil { - return utils.RandomCreateBytes(strength) - } - return k -} - -// Encryption ----------------------------------------------------------------- - -// encrypt encrypts a value using the given block in counter mode. -// -// A random initialization vector (http://goo.gl/zF67k) with the length of the -// block size is prepended to the resulting ciphertext. -func encrypt(block cipher.Block, value []byte) ([]byte, error) { - iv := generateRandomKey(block.BlockSize()) - if iv == nil { - return nil, errors.New("encrypt: failed to generate random iv") - } - // Encrypt it. - stream := cipher.NewCTR(block, iv) - stream.XORKeyStream(value, value) - // Return iv + ciphertext. - return append(iv, value...), nil -} - -// decrypt decrypts a value using the given block in counter mode. -// -// The value to be decrypted must be prepended by a initialization vector -// (http://goo.gl/zF67k) with the length of the block size. -func decrypt(block cipher.Block, value []byte) ([]byte, error) { - size := block.BlockSize() - if len(value) > size { - // Extract iv. - iv := value[:size] - // Extract ciphertext. - value = value[size:] - // Decrypt it. - stream := cipher.NewCTR(block, iv) - stream.XORKeyStream(value, value) - return value, nil - } - return nil, errors.New("decrypt: the value could not be decrypted") -} - -func encodeCookie(block cipher.Block, hashKey, name string, value map[interface{}]interface{}) (string, error) { - var err error - var b []byte - // 1. EncodeGob. - if b, err = EncodeGob(value); err != nil { - return "", err - } - // 2. Encrypt (optional). - if b, err = encrypt(block, b); err != nil { - return "", err - } - b = encode(b) - // 3. Create MAC for "name|date|value". Extra pipe to be used later. - b = []byte(fmt.Sprintf("%s|%d|%s|", name, time.Now().UTC().Unix(), b)) - h := hmac.New(sha1.New, []byte(hashKey)) - h.Write(b) - sig := h.Sum(nil) - // Append mac, remove name. - b = append(b, sig...)[len(name)+1:] - // 4. Encode to base64. - b = encode(b) - // Done. - return string(b), nil -} - -func decodeCookie(block cipher.Block, hashKey, name, value string, gcmaxlifetime int64) (map[interface{}]interface{}, error) { - // 1. Decode from base64. - b, err := decode([]byte(value)) - if err != nil { - return nil, err - } - // 2. Verify MAC. Value is "date|value|mac". - parts := bytes.SplitN(b, []byte("|"), 3) - if len(parts) != 3 { - return nil, errors.New("Decode: invalid value format") - } - - b = append([]byte(name+"|"), b[:len(b)-len(parts[2])]...) - h := hmac.New(sha1.New, []byte(hashKey)) - h.Write(b) - sig := h.Sum(nil) - if len(sig) != len(parts[2]) || subtle.ConstantTimeCompare(sig, parts[2]) != 1 { - return nil, errors.New("Decode: the value is not valid") - } - // 3. Verify date ranges. - var t1 int64 - if t1, err = strconv.ParseInt(string(parts[0]), 10, 64); err != nil { - return nil, errors.New("Decode: invalid timestamp") - } - t2 := time.Now().UTC().Unix() - if t1 > t2 { - return nil, errors.New("Decode: timestamp is too new") - } - if t1 < t2-gcmaxlifetime { - return nil, errors.New("Decode: expired timestamp") - } - // 4. Decrypt (optional). - b, err = decode(parts[1]) - if err != nil { - return nil, err - } - if b, err = decrypt(block, b); err != nil { - return nil, err - } - // 5. DecodeGob. - dst, err := DecodeGob(b) - if err != nil { - return nil, err - } - return dst, nil -} - -// Encoding ------------------------------------------------------------------- - -// encode encodes a value using base64. -func encode(value []byte) []byte { - encoded := make([]byte, base64.URLEncoding.EncodedLen(len(value))) - base64.URLEncoding.Encode(encoded, value) - return encoded -} - -// decode decodes a cookie using base64. -func decode(value []byte) ([]byte, error) { - decoded := make([]byte, base64.URLEncoding.DecodedLen(len(value))) - b, err := base64.URLEncoding.Decode(decoded, value) - if err != nil { - return nil, err - } - return decoded[:b], nil -} diff --git a/vender/github.com/astaxie/beego/session/session.go b/vender/github.com/astaxie/beego/session/session.go deleted file mode 100755 index 9215dff..0000000 --- a/vender/github.com/astaxie/beego/session/session.go +++ /dev/null @@ -1,361 +0,0 @@ -// 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 session provider -// -// Usage: -// import( -// "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" -// ) -// -// func init() { -// globalSessions, _ = session.NewManager("memory", `{"cookieName":"gosessionid", "enableSetCookie,omitempty": true, "gclifetime":3600, "maxLifetime": 3600, "secure": false, "cookieLifeTime": 3600, "providerConfig": ""}`) -// go globalSessions.GC() -// } -// -// more docs: http://beego.me/docs/module/session.md -package session - -import ( - "crypto/rand" - "encoding/hex" - "errors" - "fmt" - "io" - "log" - "net/http" - "net/textproto" - "net/url" - "os" - "time" -) - -// Store contains all data for one session process with specific id. -type Store interface { - Set(key, value interface{}) error //set session value - Get(key interface{}) interface{} //get session value - Delete(key interface{}) error //delete session value - SessionID() string //back current sessionID - SessionRelease(w http.ResponseWriter) // release the resource & save data to provider & return the data - Flush() error //delete all data -} - -// Provider contains global session methods and saved SessionStores. -// it can operate a SessionStore by its id. -type Provider interface { - SessionInit(gclifetime int64, config string) error - SessionRead(sid string) (Store, error) - SessionExist(sid string) bool - SessionRegenerate(oldsid, sid string) (Store, error) - SessionDestroy(sid string) error - SessionAll() int //get all active session - SessionGC() -} - -var provides = make(map[string]Provider) - -// SLogger a helpful variable to log information about session -var SLogger = NewSessionLog(os.Stderr) - -// Register makes a session 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, provide Provider) { - if provide == nil { - panic("session: Register provide is nil") - } - if _, dup := provides[name]; dup { - panic("session: Register called twice for provider " + name) - } - provides[name] = provide -} - -// ManagerConfig define the session config -type ManagerConfig struct { - CookieName string `json:"cookieName"` - EnableSetCookie bool `json:"enableSetCookie,omitempty"` - Gclifetime int64 `json:"gclifetime"` - Maxlifetime int64 `json:"maxLifetime"` - DisableHTTPOnly bool `json:"disableHTTPOnly"` - Secure bool `json:"secure"` - CookieLifeTime int `json:"cookieLifeTime"` - ProviderConfig string `json:"providerConfig"` - Domain string `json:"domain"` - SessionIDLength int64 `json:"sessionIDLength"` - EnableSidInHTTPHeader bool `json:"EnableSidInHTTPHeader"` - SessionNameInHTTPHeader string `json:"SessionNameInHTTPHeader"` - EnableSidInURLQuery bool `json:"EnableSidInURLQuery"` -} - -// Manager contains Provider and its configuration. -type Manager struct { - provider Provider - config *ManagerConfig -} - -// NewManager Create new Manager with provider name and json config string. -// provider name: -// 1. cookie -// 2. file -// 3. memory -// 4. redis -// 5. mysql -// json config: -// 1. is https default false -// 2. hashfunc default sha1 -// 3. hashkey default beegosessionkey -// 4. maxage default is none -func NewManager(provideName string, cf *ManagerConfig) (*Manager, error) { - provider, ok := provides[provideName] - if !ok { - return nil, fmt.Errorf("session: unknown provide %q (forgotten import?)", provideName) - } - - if cf.Maxlifetime == 0 { - cf.Maxlifetime = cf.Gclifetime - } - - if cf.EnableSidInHTTPHeader { - if cf.SessionNameInHTTPHeader == "" { - panic(errors.New("SessionNameInHTTPHeader is empty")) - } - - strMimeHeader := textproto.CanonicalMIMEHeaderKey(cf.SessionNameInHTTPHeader) - if cf.SessionNameInHTTPHeader != strMimeHeader { - strErrMsg := "SessionNameInHTTPHeader (" + cf.SessionNameInHTTPHeader + ") has the wrong format, it should be like this : " + strMimeHeader - panic(errors.New(strErrMsg)) - } - } - - err := provider.SessionInit(cf.Maxlifetime, cf.ProviderConfig) - if err != nil { - return nil, err - } - - if cf.SessionIDLength == 0 { - cf.SessionIDLength = 16 - } - - return &Manager{ - provider, - cf, - }, nil -} - -// getSid retrieves session identifier from HTTP Request. -// First try to retrieve id by reading from cookie, session cookie name is configurable, -// if not exist, then retrieve id from querying parameters. -// -// error is not nil when there is anything wrong. -// sid is empty when need to generate a new session id -// otherwise return an valid session id. -func (manager *Manager) getSid(r *http.Request) (string, error) { - cookie, errs := r.Cookie(manager.config.CookieName) - if errs != nil || cookie.Value == "" { - var sid string - if manager.config.EnableSidInURLQuery { - errs := r.ParseForm() - if errs != nil { - return "", errs - } - - sid = r.FormValue(manager.config.CookieName) - } - - // if not found in Cookie / param, then read it from request headers - if manager.config.EnableSidInHTTPHeader && sid == "" { - sids, isFound := r.Header[manager.config.SessionNameInHTTPHeader] - if isFound && len(sids) != 0 { - return sids[0], nil - } - } - - return sid, nil - } - - // HTTP Request contains cookie for sessionid info. - return url.QueryUnescape(cookie.Value) -} - -// SessionStart generate or read the session id from http request. -// if session id exists, return SessionStore with this id. -func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (session Store, err error) { - sid, errs := manager.getSid(r) - if errs != nil { - return nil, errs - } - - if sid != "" && manager.provider.SessionExist(sid) { - return manager.provider.SessionRead(sid) - } - - // Generate a new session - sid, errs = manager.sessionID() - if errs != nil { - return nil, errs - } - - session, err = manager.provider.SessionRead(sid) - if err != nil { - return nil, err - } - cookie := &http.Cookie{ - Name: manager.config.CookieName, - Value: url.QueryEscape(sid), - Path: "/", - HttpOnly: !manager.config.DisableHTTPOnly, - Secure: manager.isSecure(r), - Domain: manager.config.Domain, - } - if manager.config.CookieLifeTime > 0 { - cookie.MaxAge = manager.config.CookieLifeTime - cookie.Expires = time.Now().Add(time.Duration(manager.config.CookieLifeTime) * time.Second) - } - if manager.config.EnableSetCookie { - http.SetCookie(w, cookie) - } - r.AddCookie(cookie) - - if manager.config.EnableSidInHTTPHeader { - r.Header.Set(manager.config.SessionNameInHTTPHeader, sid) - w.Header().Set(manager.config.SessionNameInHTTPHeader, sid) - } - - return -} - -// SessionDestroy Destroy session by its id in http request cookie. -func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) { - if manager.config.EnableSidInHTTPHeader { - r.Header.Del(manager.config.SessionNameInHTTPHeader) - w.Header().Del(manager.config.SessionNameInHTTPHeader) - } - - cookie, err := r.Cookie(manager.config.CookieName) - if err != nil || cookie.Value == "" { - return - } - - sid, _ := url.QueryUnescape(cookie.Value) - manager.provider.SessionDestroy(sid) - if manager.config.EnableSetCookie { - expiration := time.Now() - cookie = &http.Cookie{Name: manager.config.CookieName, - Path: "/", - HttpOnly: !manager.config.DisableHTTPOnly, - Expires: expiration, - MaxAge: -1} - - http.SetCookie(w, cookie) - } -} - -// GetSessionStore Get SessionStore by its id. -func (manager *Manager) GetSessionStore(sid string) (sessions Store, err error) { - sessions, err = manager.provider.SessionRead(sid) - return -} - -// GC Start session gc process. -// it can do gc in times after gc lifetime. -func (manager *Manager) GC() { - manager.provider.SessionGC() - time.AfterFunc(time.Duration(manager.config.Gclifetime)*time.Second, func() { manager.GC() }) -} - -// SessionRegenerateID Regenerate a session id for this SessionStore who's id is saving in http request. -func (manager *Manager) SessionRegenerateID(w http.ResponseWriter, r *http.Request) (session Store) { - sid, err := manager.sessionID() - if err != nil { - return - } - cookie, err := r.Cookie(manager.config.CookieName) - if err != nil || cookie.Value == "" { - //delete old cookie - session, _ = manager.provider.SessionRead(sid) - cookie = &http.Cookie{Name: manager.config.CookieName, - Value: url.QueryEscape(sid), - Path: "/", - HttpOnly: !manager.config.DisableHTTPOnly, - Secure: manager.isSecure(r), - Domain: manager.config.Domain, - } - } else { - oldsid, _ := url.QueryUnescape(cookie.Value) - session, _ = manager.provider.SessionRegenerate(oldsid, sid) - cookie.Value = url.QueryEscape(sid) - cookie.HttpOnly = true - cookie.Path = "/" - } - if manager.config.CookieLifeTime > 0 { - cookie.MaxAge = manager.config.CookieLifeTime - cookie.Expires = time.Now().Add(time.Duration(manager.config.CookieLifeTime) * time.Second) - } - if manager.config.EnableSetCookie { - http.SetCookie(w, cookie) - } - r.AddCookie(cookie) - - if manager.config.EnableSidInHTTPHeader { - r.Header.Set(manager.config.SessionNameInHTTPHeader, sid) - w.Header().Set(manager.config.SessionNameInHTTPHeader, sid) - } - - return -} - -// GetActiveSession Get all active sessions count number. -func (manager *Manager) GetActiveSession() int { - return manager.provider.SessionAll() -} - -// SetSecure Set cookie with https. -func (manager *Manager) SetSecure(secure bool) { - manager.config.Secure = secure -} - -func (manager *Manager) sessionID() (string, error) { - b := make([]byte, manager.config.SessionIDLength) - n, err := rand.Read(b) - if n != len(b) || err != nil { - return "", fmt.Errorf("Could not successfully read from the system CSPRNG") - } - return hex.EncodeToString(b), nil -} - -// Set cookie with https. -func (manager *Manager) isSecure(req *http.Request) bool { - if !manager.config.Secure { - return false - } - if req.URL.Scheme != "" { - return req.URL.Scheme == "https" - } - if req.TLS == nil { - return false - } - return true -} - -// Log implement the log.Logger -type Log struct { - *log.Logger -} - -// NewSessionLog set io.Writer to create a Logger for session. -func NewSessionLog(out io.Writer) *Log { - sl := new(Log) - sl.Logger = log.New(out, "[SESSION]", 1e9) - return sl -} diff --git a/vender/github.com/astaxie/beego/session/ssdb/sess_ssdb.go b/vender/github.com/astaxie/beego/session/ssdb/sess_ssdb.go deleted file mode 100755 index 263752a..0000000 --- a/vender/github.com/astaxie/beego/session/ssdb/sess_ssdb.go +++ /dev/null @@ -1,199 +0,0 @@ -package ssdb - -import ( - "errors" - "net/http" - "strconv" - "strings" - "sync" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/session" - "github.com/ssdb/gossdb/ssdb" -) - -var ssdbProvider = &Provider{} - -// Provider holds ssdb client and configs -type Provider struct { - client *ssdb.Client - host string - port int - maxLifetime int64 -} - -func (p *Provider) connectInit() error { - var err error - if p.host == "" || p.port == 0 { - return errors.New("SessionInit First") - } - p.client, err = ssdb.Connect(p.host, p.port) - return err -} - -// SessionInit init the ssdb with the config -func (p *Provider) SessionInit(maxLifetime int64, savePath string) error { - p.maxLifetime = maxLifetime - address := strings.Split(savePath, ":") - p.host = address[0] - - var err error - if p.port, err = strconv.Atoi(address[1]); err != nil { - return err - } - return p.connectInit() -} - -// SessionRead return a ssdb client session Store -func (p *Provider) SessionRead(sid string) (session.Store, error) { - if p.client == nil { - if err := p.connectInit(); err != nil { - return nil, err - } - } - var kv map[interface{}]interface{} - value, err := p.client.Get(sid) - if err != nil { - return nil, err - } - if value == nil || len(value.(string)) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob([]byte(value.(string))) - if err != nil { - return nil, err - } - } - rs := &SessionStore{sid: sid, values: kv, maxLifetime: p.maxLifetime, client: p.client} - return rs, nil -} - -// SessionExist judged whether sid is exist in session -func (p *Provider) SessionExist(sid string) bool { - if p.client == nil { - if err := p.connectInit(); err != nil { - panic(err) - } - } - value, err := p.client.Get(sid) - if err != nil { - panic(err) - } - if value == nil || len(value.(string)) == 0 { - return false - } - return true -} - -// SessionRegenerate regenerate session with new sid and delete oldsid -func (p *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) { - //conn.Do("setx", key, v, ttl) - if p.client == nil { - if err := p.connectInit(); err != nil { - return nil, err - } - } - value, err := p.client.Get(oldsid) - if err != nil { - return nil, err - } - var kv map[interface{}]interface{} - if value == nil || len(value.(string)) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob([]byte(value.(string))) - if err != nil { - return nil, err - } - _, err = p.client.Del(oldsid) - if err != nil { - return nil, err - } - } - _, e := p.client.Do("setx", sid, value, p.maxLifetime) - if e != nil { - return nil, e - } - rs := &SessionStore{sid: sid, values: kv, maxLifetime: p.maxLifetime, client: p.client} - return rs, nil -} - -// SessionDestroy destroy the sid -func (p *Provider) SessionDestroy(sid string) error { - if p.client == nil { - if err := p.connectInit(); err != nil { - return err - } - } - _, err := p.client.Del(sid) - return err -} - -// SessionGC not implemented -func (p *Provider) SessionGC() { -} - -// SessionAll not implemented -func (p *Provider) SessionAll() int { - return 0 -} - -// SessionStore holds the session information which stored in ssdb -type SessionStore struct { - sid string - lock sync.RWMutex - values map[interface{}]interface{} - maxLifetime int64 - client *ssdb.Client -} - -// Set the key and value -func (s *SessionStore) Set(key, value interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - s.values[key] = value - return nil -} - -// Get return the value by the key -func (s *SessionStore) Get(key interface{}) interface{} { - s.lock.Lock() - defer s.lock.Unlock() - if value, ok := s.values[key]; ok { - return value - } - return nil -} - -// Delete the key in session store -func (s *SessionStore) Delete(key interface{}) error { - s.lock.Lock() - defer s.lock.Unlock() - delete(s.values, key) - return nil -} - -// Flush delete all keys and values -func (s *SessionStore) Flush() error { - s.lock.Lock() - defer s.lock.Unlock() - s.values = make(map[interface{}]interface{}) - return nil -} - -// SessionID return the sessionID -func (s *SessionStore) SessionID() string { - return s.sid -} - -// SessionRelease Store the keyvalues into ssdb -func (s *SessionStore) SessionRelease(w http.ResponseWriter) { - b, err := session.EncodeGob(s.values) - if err != nil { - return - } - s.client.Do("setx", s.sid, string(b), s.maxLifetime) -} - -func init() { - session.Register("ssdb", ssdbProvider) -} diff --git a/vender/github.com/astaxie/beego/staticfile.go b/vender/github.com/astaxie/beego/staticfile.go deleted file mode 100755 index 18b49ed..0000000 --- a/vender/github.com/astaxie/beego/staticfile.go +++ /dev/null @@ -1,210 +0,0 @@ -// 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" - "net/http" - "os" - "path" - "path/filepath" - "strconv" - "strings" - "sync" - "time" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" -) - -var errNotStaticRequest = errors.New("request not a static file request") - -func serverStaticRouter(ctx *context.Context) { - if ctx.Input.Method() != "GET" && ctx.Input.Method() != "HEAD" { - return - } - - forbidden, filePath, fileInfo, err := lookupFile(ctx) - if err == errNotStaticRequest { - return - } - - if forbidden { - exception("403", ctx) - return - } - - if filePath == "" || fileInfo == nil { - if BConfig.RunMode == DEV { - logs.Warn("Can't find/open the file:", filePath, err) - } - http.NotFound(ctx.ResponseWriter, ctx.Request) - return - } - if fileInfo.IsDir() { - requestURL := ctx.Input.URL() - if requestURL[len(requestURL)-1] != '/' { - redirectURL := requestURL + "/" - if ctx.Request.URL.RawQuery != "" { - redirectURL = redirectURL + "?" + ctx.Request.URL.RawQuery - } - ctx.Redirect(302, redirectURL) - } else { - //serveFile will list dir - http.ServeFile(ctx.ResponseWriter, ctx.Request, filePath) - } - return - } - - var enableCompress = BConfig.EnableGzip && isStaticCompress(filePath) - var acceptEncoding string - if enableCompress { - acceptEncoding = context.ParseEncoding(ctx.Request) - } - b, n, sch, reader, err := openFile(filePath, fileInfo, acceptEncoding) - if err != nil { - if BConfig.RunMode == DEV { - logs.Warn("Can't compress the file:", filePath, err) - } - http.NotFound(ctx.ResponseWriter, ctx.Request) - return - } - - if b { - ctx.Output.Header("Content-Encoding", n) - } else { - ctx.Output.Header("Content-Length", strconv.FormatInt(sch.size, 10)) - } - - http.ServeContent(ctx.ResponseWriter, ctx.Request, filePath, sch.modTime, reader) -} - -type serveContentHolder struct { - data []byte - modTime time.Time - size int64 - encoding string -} - -type serveContentReader struct { - *bytes.Reader -} - -var ( - staticFileMap = make(map[string]*serveContentHolder) - mapLock sync.RWMutex -) - -func openFile(filePath string, fi os.FileInfo, acceptEncoding string) (bool, string, *serveContentHolder, *serveContentReader, error) { - mapKey := acceptEncoding + ":" + filePath - mapLock.RLock() - mapFile := staticFileMap[mapKey] - mapLock.RUnlock() - if isOk(mapFile, fi) { - reader := &serveContentReader{Reader: bytes.NewReader(mapFile.data)} - return mapFile.encoding != "", mapFile.encoding, mapFile, reader, nil - } - mapLock.Lock() - defer mapLock.Unlock() - if mapFile = staticFileMap[mapKey]; !isOk(mapFile, fi) { - file, err := os.Open(filePath) - if err != nil { - return false, "", nil, nil, err - } - defer file.Close() - var bufferWriter bytes.Buffer - _, n, err := context.WriteFile(acceptEncoding, &bufferWriter, file) - if err != nil { - return false, "", nil, nil, err - } - mapFile = &serveContentHolder{data: bufferWriter.Bytes(), modTime: fi.ModTime(), size: int64(bufferWriter.Len()), encoding: n} - staticFileMap[mapKey] = mapFile - } - - reader := &serveContentReader{Reader: bytes.NewReader(mapFile.data)} - return mapFile.encoding != "", mapFile.encoding, mapFile, reader, nil -} - -func isOk(s *serveContentHolder, fi os.FileInfo) bool { - if s == nil { - return false - } - return s.modTime == fi.ModTime() && s.size == fi.Size() -} - -// isStaticCompress detect static files -func isStaticCompress(filePath string) bool { - for _, statExtension := range BConfig.WebConfig.StaticExtensionsToGzip { - if strings.HasSuffix(strings.ToLower(filePath), strings.ToLower(statExtension)) { - return true - } - } - return false -} - -// searchFile search the file by url path -// if none the static file prefix matches ,return notStaticRequestErr -func searchFile(ctx *context.Context) (string, os.FileInfo, error) { - requestPath := filepath.ToSlash(filepath.Clean(ctx.Request.URL.Path)) - // special processing : favicon.ico/robots.txt can be in any static dir - if requestPath == "/favicon.ico" || requestPath == "/robots.txt" { - file := path.Join(".", requestPath) - if fi, _ := os.Stat(file); fi != nil { - return file, fi, nil - } - for _, staticDir := range BConfig.WebConfig.StaticDir { - filePath := path.Join(staticDir, requestPath) - if fi, _ := os.Stat(filePath); fi != nil { - return filePath, fi, nil - } - } - return "", nil, errNotStaticRequest - } - - for prefix, staticDir := range BConfig.WebConfig.StaticDir { - if !strings.Contains(requestPath, prefix) { - continue - } - if prefix != "/" && len(requestPath) > len(prefix) && requestPath[len(prefix)] != '/' { - continue - } - filePath := path.Join(staticDir, requestPath[len(prefix):]) - if fi, err := os.Stat(filePath); fi != nil { - return filePath, fi, err - } - } - return "", nil, errNotStaticRequest -} - -// lookupFile find the file to serve -// if the file is dir ,search the index.html as default file( MUST NOT A DIR also) -// if the index.html not exist or is a dir, give a forbidden response depending on DirectoryIndex -func lookupFile(ctx *context.Context) (bool, string, os.FileInfo, error) { - fp, fi, err := searchFile(ctx) - if fp == "" || fi == nil { - return false, "", nil, err - } - if !fi.IsDir() { - return false, fp, fi, err - } - if requestURL := ctx.Input.URL(); requestURL[len(requestURL)-1] == '/' { - ifp := filepath.Join(fp, "index.html") - if ifi, _ := os.Stat(ifp); ifi != nil && ifi.Mode().IsRegular() { - return false, ifp, ifi, err - } - } - return !BConfig.WebConfig.DirectoryIndex, fp, fi, err -} diff --git a/vender/github.com/astaxie/beego/staticfile_test.go b/vender/github.com/astaxie/beego/staticfile_test.go deleted file mode 100755 index 69667bf..0000000 --- a/vender/github.com/astaxie/beego/staticfile_test.go +++ /dev/null @@ -1,73 +0,0 @@ -package beego - -import ( - "bytes" - "compress/gzip" - "compress/zlib" - "io" - "io/ioutil" - "os" - "path/filepath" - "testing" -) - -var currentWorkDir, _ = os.Getwd() -var licenseFile = filepath.Join(currentWorkDir, "LICENSE") - -func testOpenFile(encoding string, content []byte, t *testing.T) { - fi, _ := os.Stat(licenseFile) - b, n, sch, reader, err := openFile(licenseFile, fi, encoding) - if err != nil { - t.Log(err) - t.Fail() - } - - t.Log("open static file encoding "+n, b) - - assetOpenFileAndContent(sch, reader, content, t) -} -func TestOpenStaticFile_1(t *testing.T) { - file, _ := os.Open(licenseFile) - content, _ := ioutil.ReadAll(file) - testOpenFile("", content, t) -} - -func TestOpenStaticFileGzip_1(t *testing.T) { - file, _ := os.Open(licenseFile) - var zipBuf bytes.Buffer - fileWriter, _ := gzip.NewWriterLevel(&zipBuf, gzip.BestCompression) - io.Copy(fileWriter, file) - fileWriter.Close() - content, _ := ioutil.ReadAll(&zipBuf) - - testOpenFile("gzip", content, t) -} -func TestOpenStaticFileDeflate_1(t *testing.T) { - file, _ := os.Open(licenseFile) - var zipBuf bytes.Buffer - fileWriter, _ := zlib.NewWriterLevel(&zipBuf, zlib.BestCompression) - io.Copy(fileWriter, file) - fileWriter.Close() - content, _ := ioutil.ReadAll(&zipBuf) - - testOpenFile("deflate", content, t) -} - -func assetOpenFileAndContent(sch *serveContentHolder, reader *serveContentReader, content []byte, t *testing.T) { - t.Log(sch.size, len(content)) - if sch.size != int64(len(content)) { - t.Log("static content file size not same") - t.Fail() - } - bs, _ := ioutil.ReadAll(reader) - for i, v := range content { - if v != bs[i] { - t.Log("content not same") - t.Fail() - } - } - if len(staticFileMap) == 0 { - t.Log("men map is empty") - t.Fail() - } -} diff --git a/vender/github.com/astaxie/beego/swagger/swagger.go b/vender/github.com/astaxie/beego/swagger/swagger.go deleted file mode 100755 index a55676c..0000000 --- a/vender/github.com/astaxie/beego/swagger/swagger.go +++ /dev/null @@ -1,174 +0,0 @@ -// 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. -// -// Swagger™ is a project used to describe and document RESTful APIs. -// -// The Swagger specification defines a set of files required to describe such an API. These files can then be used by the Swagger-UI project to display the API and Swagger-Codegen to generate clients in various languages. Additional utilities can also take advantage of the resulting files, such as testing tools. -// Now in version 2.0, Swagger is more enabling than ever. And it's 100% open source software. - -// Package swagger struct definition -package swagger - -// Swagger list the resource -type Swagger struct { - SwaggerVersion string `json:"swagger,omitempty" yaml:"swagger,omitempty"` - Infos Information `json:"info" yaml:"info"` - Host string `json:"host,omitempty" yaml:"host,omitempty"` - BasePath string `json:"basePath,omitempty" yaml:"basePath,omitempty"` - Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"` - Consumes []string `json:"consumes,omitempty" yaml:"consumes,omitempty"` - Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"` - Paths map[string]*Item `json:"paths" yaml:"paths"` - Definitions map[string]Schema `json:"definitions,omitempty" yaml:"definitions,omitempty"` - SecurityDefinitions map[string]Security `json:"securityDefinitions,omitempty" yaml:"securityDefinitions,omitempty"` - Security []map[string][]string `json:"security,omitempty" yaml:"security,omitempty"` - Tags []Tag `json:"tags,omitempty" yaml:"tags,omitempty"` - ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` -} - -// Information Provides metadata about the API. The metadata can be used by the clients if needed. -type Information struct { - Title string `json:"title,omitempty" yaml:"title,omitempty"` - Description string `json:"description,omitempty" yaml:"description,omitempty"` - Version string `json:"version,omitempty" yaml:"version,omitempty"` - TermsOfService string `json:"termsOfService,omitempty" yaml:"termsOfService,omitempty"` - - Contact Contact `json:"contact,omitempty" yaml:"contact,omitempty"` - License *License `json:"license,omitempty" yaml:"license,omitempty"` -} - -// Contact information for the exposed API. -type Contact struct { - Name string `json:"name,omitempty" yaml:"name,omitempty"` - URL string `json:"url,omitempty" yaml:"url,omitempty"` - EMail string `json:"email,omitempty" yaml:"email,omitempty"` -} - -// License information for the exposed API. -type License struct { - Name string `json:"name,omitempty" yaml:"name,omitempty"` - URL string `json:"url,omitempty" yaml:"url,omitempty"` -} - -// Item Describes the operations available on a single path. -type Item struct { - Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"` - Get *Operation `json:"get,omitempty" yaml:"get,omitempty"` - Put *Operation `json:"put,omitempty" yaml:"put,omitempty"` - Post *Operation `json:"post,omitempty" yaml:"post,omitempty"` - Delete *Operation `json:"delete,omitempty" yaml:"delete,omitempty"` - Options *Operation `json:"options,omitempty" yaml:"options,omitempty"` - Head *Operation `json:"head,omitempty" yaml:"head,omitempty"` - Patch *Operation `json:"patch,omitempty" yaml:"patch,omitempty"` -} - -// Operation Describes a single API operation on a path. -type Operation struct { - Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"` - Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` - Description string `json:"description,omitempty" yaml:"description,omitempty"` - OperationID string `json:"operationId,omitempty" yaml:"operationId,omitempty"` - Consumes []string `json:"consumes,omitempty" yaml:"consumes,omitempty"` - Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"` - Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"` - Parameters []Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"` - Responses map[string]Response `json:"responses,omitempty" yaml:"responses,omitempty"` - Security []map[string][]string `json:"security,omitempty" yaml:"security,omitempty"` - Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` -} - -// Parameter Describes a single operation parameter. -type Parameter struct { - In string `json:"in,omitempty" yaml:"in,omitempty"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` - Description string `json:"description,omitempty" yaml:"description,omitempty"` - Required bool `json:"required,omitempty" yaml:"required,omitempty"` - Schema *Schema `json:"schema,omitempty" yaml:"schema,omitempty"` - Type string `json:"type,omitempty" yaml:"type,omitempty"` - Format string `json:"format,omitempty" yaml:"format,omitempty"` - Items *ParameterItems `json:"items,omitempty" yaml:"items,omitempty"` - Default interface{} `json:"default,omitempty" yaml:"default,omitempty"` -} - -// ParameterItems A limited subset of JSON-Schema's items object. It is used by parameter definitions that are not located in "body". -// http://swagger.io/specification/#itemsObject -type ParameterItems struct { - Type string `json:"type,omitempty" yaml:"type,omitempty"` - Format string `json:"format,omitempty" yaml:"format,omitempty"` - Items []*ParameterItems `json:"items,omitempty" yaml:"items,omitempty"` //Required if type is "array". Describes the type of items in the array. - CollectionFormat string `json:"collectionFormat,omitempty" yaml:"collectionFormat,omitempty"` - Default string `json:"default,omitempty" yaml:"default,omitempty"` -} - -// Schema Object allows the definition of input and output data types. -type Schema struct { - Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"` - Title string `json:"title,omitempty" yaml:"title,omitempty"` - Format string `json:"format,omitempty" yaml:"format,omitempty"` - Description string `json:"description,omitempty" yaml:"description,omitempty"` - Required []string `json:"required,omitempty" yaml:"required,omitempty"` - Type string `json:"type,omitempty" yaml:"type,omitempty"` - Items *Schema `json:"items,omitempty" yaml:"items,omitempty"` - Properties map[string]Propertie `json:"properties,omitempty" yaml:"properties,omitempty"` - Enum []interface{} `json:"enum,omitempty" yaml:"enum,omitempty"` - Example interface{} `json:"example,omitempty" yaml:"example,omitempty"` -} - -// Propertie are taken from the JSON Schema definition but their definitions were adjusted to the Swagger Specification -type Propertie struct { - Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"` - Title string `json:"title,omitempty" yaml:"title,omitempty"` - Description string `json:"description,omitempty" yaml:"description,omitempty"` - Default interface{} `json:"default,omitempty" yaml:"default,omitempty"` - Type string `json:"type,omitempty" yaml:"type,omitempty"` - Example interface{} `json:"example,omitempty" yaml:"example,omitempty"` - Required []string `json:"required,omitempty" yaml:"required,omitempty"` - Format string `json:"format,omitempty" yaml:"format,omitempty"` - ReadOnly bool `json:"readOnly,omitempty" yaml:"readOnly,omitempty"` - Properties map[string]Propertie `json:"properties,omitempty" yaml:"properties,omitempty"` - Items *Propertie `json:"items,omitempty" yaml:"items,omitempty"` - AdditionalProperties *Propertie `json:"additionalProperties,omitempty" yaml:"additionalProperties,omitempty"` -} - -// Response as they are returned from executing this operation. -type Response struct { - Description string `json:"description" yaml:"description"` - Schema *Schema `json:"schema,omitempty" yaml:"schema,omitempty"` - Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"` -} - -// Security Allows the definition of a security scheme that can be used by the operations -type Security struct { - Type string `json:"type,omitempty" yaml:"type,omitempty"` // Valid values are "basic", "apiKey" or "oauth2". - Description string `json:"description,omitempty" yaml:"description,omitempty"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` - In string `json:"in,omitempty" yaml:"in,omitempty"` // Valid values are "query" or "header". - Flow string `json:"flow,omitempty" yaml:"flow,omitempty"` // Valid values are "implicit", "password", "application" or "accessCode". - AuthorizationURL string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"` - TokenURL string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"` - Scopes map[string]string `json:"scopes,omitempty" yaml:"scopes,omitempty"` // The available scopes for the OAuth2 security scheme. -} - -// Tag Allows adding meta data to a single tag that is used by the Operation Object -type Tag struct { - Name string `json:"name,omitempty" yaml:"name,omitempty"` - Description string `json:"description,omitempty" yaml:"description,omitempty"` - ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` -} - -// ExternalDocs include Additional external documentation -type ExternalDocs struct { - Description string `json:"description,omitempty" yaml:"description,omitempty"` - URL string `json:"url,omitempty" yaml:"url,omitempty"` -} diff --git a/vender/github.com/astaxie/beego/template.go b/vender/github.com/astaxie/beego/template.go deleted file mode 100755 index 36826af..0000000 --- a/vender/github.com/astaxie/beego/template.go +++ /dev/null @@ -1,373 +0,0 @@ -// 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 ( - "errors" - "fmt" - "html/template" - "io" - "io/ioutil" - "os" - "path/filepath" - "regexp" - "strings" - "sync" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/utils" -) - -var ( - beegoTplFuncMap = make(template.FuncMap) - beeViewPathTemplateLocked = false - // beeViewPathTemplates caching map and supported template file extensions per view - beeViewPathTemplates = make(map[string]map[string]*template.Template) - templatesLock sync.RWMutex - // beeTemplateExt stores the template extension which will build - beeTemplateExt = []string{"tpl", "html"} - // beeTemplatePreprocessors stores associations of extension -> preprocessor handler - beeTemplateEngines = map[string]templatePreProcessor{} -) - -// ExecuteTemplate applies the template with name to the specified data object, -// writing the output to wr. -// A template will be executed safely in parallel. -func ExecuteTemplate(wr io.Writer, name string, data interface{}) error { - return ExecuteViewPathTemplate(wr, name, BConfig.WebConfig.ViewsPath, data) -} - -// ExecuteViewPathTemplate applies the template with name and from specific viewPath to the specified data object, -// writing the output to wr. -// A template will be executed safely in parallel. -func ExecuteViewPathTemplate(wr io.Writer, name string, viewPath string, data interface{}) error { - if BConfig.RunMode == DEV { - templatesLock.RLock() - defer templatesLock.RUnlock() - } - if beeTemplates, ok := beeViewPathTemplates[viewPath]; ok { - if t, ok := beeTemplates[name]; ok { - var err error - if t.Lookup(name) != nil { - err = t.ExecuteTemplate(wr, name, data) - } else { - err = t.Execute(wr, data) - } - if err != nil { - logs.Trace("template Execute err:", err) - } - return err - } - panic("can't find templatefile in the path:" + viewPath + "/" + name) - } - panic("Unknown view path:" + viewPath) -} - -func init() { - beegoTplFuncMap["dateformat"] = DateFormat - beegoTplFuncMap["date"] = Date - beegoTplFuncMap["compare"] = Compare - beegoTplFuncMap["compare_not"] = CompareNot - beegoTplFuncMap["not_nil"] = NotNil - beegoTplFuncMap["not_null"] = NotNil - beegoTplFuncMap["substr"] = Substr - beegoTplFuncMap["html2str"] = HTML2str - beegoTplFuncMap["str2html"] = Str2html - beegoTplFuncMap["htmlquote"] = Htmlquote - beegoTplFuncMap["htmlunquote"] = Htmlunquote - beegoTplFuncMap["renderform"] = RenderForm - beegoTplFuncMap["assets_js"] = AssetsJs - beegoTplFuncMap["assets_css"] = AssetsCSS - beegoTplFuncMap["config"] = GetConfig - beegoTplFuncMap["map_get"] = MapGet - - // Comparisons - beegoTplFuncMap["eq"] = eq // == - beegoTplFuncMap["ge"] = ge // >= - beegoTplFuncMap["gt"] = gt // > - beegoTplFuncMap["le"] = le // <= - beegoTplFuncMap["lt"] = lt // < - beegoTplFuncMap["ne"] = ne // != - - beegoTplFuncMap["urlfor"] = URLFor // build a URL to match a Controller and it's method -} - -// AddFuncMap let user to register a func in the template. -func AddFuncMap(key string, fn interface{}) error { - beegoTplFuncMap[key] = fn - return nil -} - -type templatePreProcessor func(root, path string, funcs template.FuncMap) (*template.Template, error) - -type templateFile struct { - root string - files map[string][]string -} - -// visit will make the paths into two part,the first is subDir (without tf.root),the second is full path(without tf.root). -// if tf.root="views" and -// paths is "views/errors/404.html",the subDir will be "errors",the file will be "errors/404.html" -// paths is "views/admin/errors/404.html",the subDir will be "admin/errors",the file will be "admin/errors/404.html" -func (tf *templateFile) visit(paths string, f os.FileInfo, err error) error { - if f == nil { - return err - } - if f.IsDir() || (f.Mode()&os.ModeSymlink) > 0 { - return nil - } - if !HasTemplateExt(paths) { - return nil - } - - replace := strings.NewReplacer("\\", "/") - file := strings.TrimLeft(replace.Replace(paths[len(tf.root):]), "/") - subDir := filepath.Dir(file) - tf.files[subDir] = append(tf.files[subDir], file) - return nil -} - -// HasTemplateExt return this path contains supported template extension of beego or not. -func HasTemplateExt(paths string) bool { - for _, v := range beeTemplateExt { - if strings.HasSuffix(paths, "."+v) { - return true - } - } - return false -} - -// AddTemplateExt add new extension for template. -func AddTemplateExt(ext string) { - for _, v := range beeTemplateExt { - if v == ext { - return - } - } - beeTemplateExt = append(beeTemplateExt, ext) -} - -// AddViewPath adds a new path to the supported view paths. -//Can later be used by setting a controller ViewPath to this folder -//will panic if called after beego.Run() -func AddViewPath(viewPath string) error { - if beeViewPathTemplateLocked { - if _, exist := beeViewPathTemplates[viewPath]; exist { - return nil //Ignore if viewpath already exists - } - panic("Can not add new view paths after beego.Run()") - } - beeViewPathTemplates[viewPath] = make(map[string]*template.Template) - return BuildTemplate(viewPath) -} - -func lockViewPaths() { - beeViewPathTemplateLocked = true -} - -// BuildTemplate will build all template files in a directory. -// it makes beego can render any template file in view directory. -func BuildTemplate(dir string, files ...string) error { - if _, err := os.Stat(dir); err != nil { - if os.IsNotExist(err) { - return nil - } - return errors.New("dir open err") - } - beeTemplates, ok := beeViewPathTemplates[dir] - if !ok { - panic("Unknown view path: " + dir) - } - self := &templateFile{ - root: dir, - files: make(map[string][]string), - } - err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error { - return self.visit(path, f, err) - }) - if err != nil { - fmt.Printf("filepath.Walk() returned %v\n", err) - return err - } - buildAllFiles := len(files) == 0 - for _, v := range self.files { - for _, file := range v { - if buildAllFiles || utils.InSlice(file, files) { - templatesLock.Lock() - ext := filepath.Ext(file) - var t *template.Template - if len(ext) == 0 { - t, err = getTemplate(self.root, file, v...) - } else if fn, ok := beeTemplateEngines[ext[1:]]; ok { - t, err = fn(self.root, file, beegoTplFuncMap) - } else { - t, err = getTemplate(self.root, file, v...) - } - if err != nil { - logs.Error("parse template err:", file, err) - templatesLock.Unlock() - return err - } - beeTemplates[file] = t - templatesLock.Unlock() - } - } - } - return nil -} - -func getTplDeep(root, file, parent string, t *template.Template) (*template.Template, [][]string, error) { - var fileAbsPath string - var rParent string - if filepath.HasPrefix(file, "../") { - rParent = filepath.Join(filepath.Dir(parent), file) - fileAbsPath = filepath.Join(root, filepath.Dir(parent), file) - } else { - rParent = file - fileAbsPath = filepath.Join(root, file) - } - if e := utils.FileExists(fileAbsPath); !e { - panic("can't find template file:" + file) - } - data, err := ioutil.ReadFile(fileAbsPath) - if err != nil { - return nil, [][]string{}, err - } - t, err = t.New(file).Parse(string(data)) - if err != nil { - return nil, [][]string{}, err - } - reg := regexp.MustCompile(BConfig.WebConfig.TemplateLeft + "[ ]*template[ ]+\"([^\"]+)\"") - allSub := reg.FindAllStringSubmatch(string(data), -1) - for _, m := range allSub { - if len(m) == 2 { - tl := t.Lookup(m[1]) - if tl != nil { - continue - } - if !HasTemplateExt(m[1]) { - continue - } - _, _, err = getTplDeep(root, m[1], rParent, t) - if err != nil { - return nil, [][]string{}, err - } - } - } - return t, allSub, nil -} - -func getTemplate(root, file string, others ...string) (t *template.Template, err error) { - t = template.New(file).Delims(BConfig.WebConfig.TemplateLeft, BConfig.WebConfig.TemplateRight).Funcs(beegoTplFuncMap) - var subMods [][]string - t, subMods, err = getTplDeep(root, file, "", t) - if err != nil { - return nil, err - } - t, err = _getTemplate(t, root, subMods, others...) - - if err != nil { - return nil, err - } - return -} - -func _getTemplate(t0 *template.Template, root string, subMods [][]string, others ...string) (t *template.Template, err error) { - t = t0 - for _, m := range subMods { - if len(m) == 2 { - tpl := t.Lookup(m[1]) - if tpl != nil { - continue - } - //first check filename - for _, otherFile := range others { - if otherFile == m[1] { - var subMods1 [][]string - t, subMods1, err = getTplDeep(root, otherFile, "", t) - if err != nil { - logs.Trace("template parse file err:", err) - } else if len(subMods1) > 0 { - t, err = _getTemplate(t, root, subMods1, others...) - } - break - } - } - //second check define - for _, otherFile := range others { - var data []byte - fileAbsPath := filepath.Join(root, otherFile) - data, err = ioutil.ReadFile(fileAbsPath) - if err != nil { - continue - } - reg := regexp.MustCompile(BConfig.WebConfig.TemplateLeft + "[ ]*define[ ]+\"([^\"]+)\"") - allSub := reg.FindAllStringSubmatch(string(data), -1) - for _, sub := range allSub { - if len(sub) == 2 && sub[1] == m[1] { - var subMods1 [][]string - t, subMods1, err = getTplDeep(root, otherFile, "", t) - if err != nil { - logs.Trace("template parse file err:", err) - } else if len(subMods1) > 0 { - t, err = _getTemplate(t, root, subMods1, others...) - } - break - } - } - } - } - - } - return -} - -// SetViewsPath sets view directory path in beego application. -func SetViewsPath(path string) *App { - BConfig.WebConfig.ViewsPath = path - return BeeApp -} - -// SetStaticPath sets static directory path and proper url pattern in beego application. -// if beego.SetStaticPath("static","public"), visit /static/* to load static file in folder "public". -func SetStaticPath(url string, path string) *App { - if !strings.HasPrefix(url, "/") { - url = "/" + url - } - if url != "/" { - url = strings.TrimRight(url, "/") - } - BConfig.WebConfig.StaticDir[url] = path - return BeeApp -} - -// DelStaticPath removes the static folder setting in this url pattern in beego application. -func DelStaticPath(url string) *App { - if !strings.HasPrefix(url, "/") { - url = "/" + url - } - if url != "/" { - url = strings.TrimRight(url, "/") - } - delete(BConfig.WebConfig.StaticDir, url) - return BeeApp -} - -// AddTemplateEngine add a new templatePreProcessor which support extension -func AddTemplateEngine(extension string, fn templatePreProcessor) *App { - AddTemplateExt(extension) - beeTemplateEngines[extension] = fn - return BeeApp -} diff --git a/vender/github.com/astaxie/beego/template_test.go b/vender/github.com/astaxie/beego/template_test.go deleted file mode 100755 index 2153ef7..0000000 --- a/vender/github.com/astaxie/beego/template_test.go +++ /dev/null @@ -1,258 +0,0 @@ -// 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" - "os" - "path/filepath" - "testing" -) - -var header = `{{define "header"}} -

Hello, astaxie!

-{{end}}` - -var index = ` - - - beego welcome template - - -{{template "block"}} -{{template "header"}} -{{template "blocks/block.tpl"}} - - -` - -var block = `{{define "block"}} -

Hello, blocks!

-{{end}}` - -func TestTemplate(t *testing.T) { - dir := "_beeTmp" - files := []string{ - "header.tpl", - "index.tpl", - "blocks/block.tpl", - } - if err := os.MkdirAll(dir, 0777); err != nil { - t.Fatal(err) - } - for k, name := range files { - os.MkdirAll(filepath.Dir(filepath.Join(dir, name)), 0777) - if f, err := os.Create(filepath.Join(dir, name)); err != nil { - t.Fatal(err) - } else { - if k == 0 { - f.WriteString(header) - } else if k == 1 { - f.WriteString(index) - } else if k == 2 { - f.WriteString(block) - } - - f.Close() - } - } - if err := AddViewPath(dir); err != nil { - t.Fatal(err) - } - beeTemplates := beeViewPathTemplates[dir] - if len(beeTemplates) != 3 { - t.Fatalf("should be 3 but got %v", len(beeTemplates)) - } - if err := beeTemplates["index.tpl"].ExecuteTemplate(os.Stdout, "index.tpl", nil); err != nil { - t.Fatal(err) - } - for _, name := range files { - os.RemoveAll(filepath.Join(dir, name)) - } - os.RemoveAll(dir) -} - -var menu = ` -` -var user = ` - - - beego welcome template - - -{{template "../public/menu.tpl"}} - - -` - -func TestRelativeTemplate(t *testing.T) { - dir := "_beeTmp" - - //Just add dir to known viewPaths - if err := AddViewPath(dir); err != nil { - t.Fatal(err) - } - - files := []string{ - "easyui/public/menu.tpl", - "easyui/rbac/user.tpl", - } - if err := os.MkdirAll(dir, 0777); err != nil { - t.Fatal(err) - } - for k, name := range files { - os.MkdirAll(filepath.Dir(filepath.Join(dir, name)), 0777) - if f, err := os.Create(filepath.Join(dir, name)); err != nil { - t.Fatal(err) - } else { - if k == 0 { - f.WriteString(menu) - } else if k == 1 { - f.WriteString(user) - } - f.Close() - } - } - if err := BuildTemplate(dir, files[1]); err != nil { - t.Fatal(err) - } - beeTemplates := beeViewPathTemplates[dir] - if err := beeTemplates["easyui/rbac/user.tpl"].ExecuteTemplate(os.Stdout, "easyui/rbac/user.tpl", nil); err != nil { - t.Fatal(err) - } - for _, name := range files { - os.RemoveAll(filepath.Join(dir, name)) - } - os.RemoveAll(dir) -} - -var add = `{{ template "layout_blog.tpl" . }} -{{ define "css" }} - -{{ end}} - - -{{ define "content" }} -

{{ .Title }}

-

This is SomeVar: {{ .SomeVar }}

-{{ end }} - -{{ define "js" }} - -{{ end}}` - -var layoutBlog = ` - - - Lin Li - - - - - {{ block "css" . }}{{ end }} - - - -
- {{ block "content" . }}{{ end }} -
- - - {{ block "js" . }}{{ end }} - -` - -var output = ` - - - Lin Li - - - - - - - - - - -
- -

Hello

-

This is SomeVar: val

- -
- - - - - - - - - - - - -` - -func TestTemplateLayout(t *testing.T) { - dir := "_beeTmp" - files := []string{ - "add.tpl", - "layout_blog.tpl", - } - if err := os.MkdirAll(dir, 0777); err != nil { - t.Fatal(err) - } - for k, name := range files { - os.MkdirAll(filepath.Dir(filepath.Join(dir, name)), 0777) - if f, err := os.Create(filepath.Join(dir, name)); err != nil { - t.Fatal(err) - } else { - if k == 0 { - f.WriteString(add) - } else if k == 1 { - f.WriteString(layoutBlog) - } - f.Close() - } - } - if err := AddViewPath(dir); err != nil { - t.Fatal(err) - } - beeTemplates := beeViewPathTemplates[dir] - if len(beeTemplates) != 2 { - t.Fatalf("should be 2 but got %v", len(beeTemplates)) - } - out := bytes.NewBufferString("") - if err := beeTemplates["add.tpl"].ExecuteTemplate(out, "add.tpl", map[string]string{"Title": "Hello", "SomeVar": "val"}); err != nil { - t.Fatal(err) - } - if out.String() != output { - t.Log(out.String()) - t.Fatal("Compare failed") - } - for _, name := range files { - os.RemoveAll(filepath.Join(dir, name)) - } - os.RemoveAll(dir) -} diff --git a/vender/github.com/astaxie/beego/templatefunc.go b/vender/github.com/astaxie/beego/templatefunc.go deleted file mode 100755 index 8c1504a..0000000 --- a/vender/github.com/astaxie/beego/templatefunc.go +++ /dev/null @@ -1,766 +0,0 @@ -// 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 ( - "errors" - "fmt" - "html" - "html/template" - "net/url" - "reflect" - "regexp" - "strconv" - "strings" - "time" -) - -const ( - formatTime = "15:04:05" - formatDate = "2006-01-02" - formatDateTime = "2006-01-02 15:04:05" - formatDateTimeT = "2006-01-02T15:04:05" -) - -// Substr returns the substr from start to length. -func Substr(s string, start, length int) string { - bt := []rune(s) - if start < 0 { - start = 0 - } - if start > len(bt) { - start = start % len(bt) - } - var end int - if (start + length) > (len(bt) - 1) { - end = len(bt) - } else { - end = start + length - } - return string(bt[start:end]) -} - -// HTML2str returns escaping text convert from html. -func HTML2str(html string) string { - - re, _ := regexp.Compile(`\<[\S\s]+?\>`) - html = re.ReplaceAllStringFunc(html, strings.ToLower) - - //remove STYLE - re, _ = regexp.Compile(`\`) - html = re.ReplaceAllString(html, "") - - //remove SCRIPT - re, _ = regexp.Compile(`\`) - html = re.ReplaceAllString(html, "") - - re, _ = regexp.Compile(`\<[\S\s]+?\>`) - html = re.ReplaceAllString(html, "\n") - - re, _ = regexp.Compile(`\s{2,}`) - html = re.ReplaceAllString(html, "\n") - - return strings.TrimSpace(html) -} - -// DateFormat takes a time and a layout string and returns a string with the formatted date. Used by the template parser as "dateformat" -func DateFormat(t time.Time, layout string) (datestring string) { - datestring = t.Format(layout) - return -} - -// DateFormat pattern rules. -var datePatterns = []string{ - // year - "Y", "2006", // A full numeric representation of a year, 4 digits Examples: 1999 or 2003 - "y", "06", //A two digit representation of a year Examples: 99 or 03 - - // month - "m", "01", // Numeric representation of a month, with leading zeros 01 through 12 - "n", "1", // Numeric representation of a month, without leading zeros 1 through 12 - "M", "Jan", // A short textual representation of a month, three letters Jan through Dec - "F", "January", // A full textual representation of a month, such as January or March January through December - - // day - "d", "02", // Day of the month, 2 digits with leading zeros 01 to 31 - "j", "2", // Day of the month without leading zeros 1 to 31 - - // week - "D", "Mon", // A textual representation of a day, three letters Mon through Sun - "l", "Monday", // A full textual representation of the day of the week Sunday through Saturday - - // time - "g", "3", // 12-hour format of an hour without leading zeros 1 through 12 - "G", "15", // 24-hour format of an hour without leading zeros 0 through 23 - "h", "03", // 12-hour format of an hour with leading zeros 01 through 12 - "H", "15", // 24-hour format of an hour with leading zeros 00 through 23 - - "a", "pm", // Lowercase Ante meridiem and Post meridiem am or pm - "A", "PM", // Uppercase Ante meridiem and Post meridiem AM or PM - - "i", "04", // Minutes with leading zeros 00 to 59 - "s", "05", // Seconds, with leading zeros 00 through 59 - - // time zone - "T", "MST", - "P", "-07:00", - "O", "-0700", - - // RFC 2822 - "r", time.RFC1123Z, -} - -// DateParse Parse Date use PHP time format. -func DateParse(dateString, format string) (time.Time, error) { - replacer := strings.NewReplacer(datePatterns...) - format = replacer.Replace(format) - return time.ParseInLocation(format, dateString, time.Local) -} - -// Date takes a PHP like date func to Go's time format. -func Date(t time.Time, format string) string { - replacer := strings.NewReplacer(datePatterns...) - format = replacer.Replace(format) - return t.Format(format) -} - -// Compare is a quick and dirty comparison function. It will convert whatever you give it to strings and see if the two values are equal. -// Whitespace is trimmed. Used by the template parser as "eq". -func Compare(a, b interface{}) (equal bool) { - equal = false - if strings.TrimSpace(fmt.Sprintf("%v", a)) == strings.TrimSpace(fmt.Sprintf("%v", b)) { - equal = true - } - return -} - -// CompareNot !Compare -func CompareNot(a, b interface{}) (equal bool) { - return !Compare(a, b) -} - -// NotNil the same as CompareNot -func NotNil(a interface{}) (isNil bool) { - return CompareNot(a, nil) -} - -// GetConfig get the Appconfig -func GetConfig(returnType, key string, defaultVal interface{}) (value interface{}, err error) { - switch returnType { - case "String": - value = AppConfig.String(key) - case "Bool": - value, err = AppConfig.Bool(key) - case "Int": - value, err = AppConfig.Int(key) - case "Int64": - value, err = AppConfig.Int64(key) - case "Float": - value, err = AppConfig.Float(key) - case "DIY": - value, err = AppConfig.DIY(key) - default: - err = errors.New("Config keys must be of type String, Bool, Int, Int64, Float, or DIY") - } - - if err != nil { - if reflect.TypeOf(returnType) != reflect.TypeOf(defaultVal) { - err = errors.New("defaultVal type does not match returnType") - } else { - value, err = defaultVal, nil - } - } else if reflect.TypeOf(value).Kind() == reflect.String { - if value == "" { - if reflect.TypeOf(defaultVal).Kind() != reflect.String { - err = errors.New("defaultVal type must be a String if the returnType is a String") - } else { - value = defaultVal.(string) - } - } - } - - return -} - -// Str2html Convert string to template.HTML type. -func Str2html(raw string) template.HTML { - return template.HTML(raw) -} - -// Htmlquote returns quoted html string. -func Htmlquote(text string) string { - //HTML编码为实体符号 - /* - Encodes `text` for raw use in HTML. - >>> htmlquote("<'&\\">") - '<'&">' - */ - - text = html.EscapeString(text) - text = strings.NewReplacer( - `“`, "“", - `”`, "”", - ` `, " ", - ).Replace(text) - - return strings.TrimSpace(text) -} - -// Htmlunquote returns unquoted html string. -func Htmlunquote(text string) string { - //实体符号解释为HTML - /* - Decodes `text` that's HTML quoted. - >>> htmlunquote('<'&">') - '<\\'&">' - */ - - text = html.UnescapeString(text) - - return strings.TrimSpace(text) -} - -// URLFor returns url string with another registered controller handler with params. -// usage: -// -// URLFor(".index") -// print URLFor("index") -// router /login -// print URLFor("login") -// print URLFor("login", "next","/"") -// router /profile/:username -// print UrlFor("profile", ":username","John Doe") -// result: -// / -// /login -// /login?next=/ -// /user/John%20Doe -// -// more detail http://beego.me/docs/mvc/controller/urlbuilding.md -func URLFor(endpoint string, values ...interface{}) string { - return BeeApp.Handlers.URLFor(endpoint, values...) -} - -// AssetsJs returns script tag with src string. -func AssetsJs(text string) template.HTML { - - text = "" - - return template.HTML(text) -} - -// AssetsCSS returns stylesheet link tag with src string. -func AssetsCSS(text string) template.HTML { - - text = "" - - return template.HTML(text) -} - -// ParseForm will parse form values to struct via tag. -// Support for anonymous struct. -func parseFormToStruct(form url.Values, objT reflect.Type, objV reflect.Value) error { - for i := 0; i < objT.NumField(); i++ { - fieldV := objV.Field(i) - if !fieldV.CanSet() { - continue - } - - fieldT := objT.Field(i) - if fieldT.Anonymous && fieldT.Type.Kind() == reflect.Struct { - err := parseFormToStruct(form, fieldT.Type, fieldV) - if err != nil { - return err - } - continue - } - - tags := strings.Split(fieldT.Tag.Get("form"), ",") - var tag string - if len(tags) == 0 || len(tags[0]) == 0 { - tag = fieldT.Name - } else if tags[0] == "-" { - continue - } else { - tag = tags[0] - } - - value := form.Get(tag) - if len(value) == 0 { - continue - } - - switch fieldT.Type.Kind() { - case reflect.Bool: - if strings.ToLower(value) == "on" || strings.ToLower(value) == "1" || strings.ToLower(value) == "yes" { - fieldV.SetBool(true) - continue - } - if strings.ToLower(value) == "off" || strings.ToLower(value) == "0" || strings.ToLower(value) == "no" { - fieldV.SetBool(false) - continue - } - b, err := strconv.ParseBool(value) - if err != nil { - return err - } - fieldV.SetBool(b) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - x, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return err - } - fieldV.SetInt(x) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - x, err := strconv.ParseUint(value, 10, 64) - if err != nil { - return err - } - fieldV.SetUint(x) - case reflect.Float32, reflect.Float64: - x, err := strconv.ParseFloat(value, 64) - if err != nil { - return err - } - fieldV.SetFloat(x) - case reflect.Interface: - fieldV.Set(reflect.ValueOf(value)) - case reflect.String: - fieldV.SetString(value) - case reflect.Struct: - switch fieldT.Type.String() { - case "time.Time": - var ( - t time.Time - err error - ) - if len(value) >= 25 { - value = value[:25] - t, err = time.ParseInLocation(time.RFC3339, value, time.Local) - } else if len(value) >= 19 { - if strings.Contains(value, "T") { - value = value[:19] - t, err = time.ParseInLocation(formatDateTimeT, value, time.Local) - } else { - value = value[:19] - t, err = time.ParseInLocation(formatDateTime, value, time.Local) - } - } else if len(value) >= 10 { - if len(value) > 10 { - value = value[:10] - } - t, err = time.ParseInLocation(formatDate, value, time.Local) - } else if len(value) >= 8 { - if len(value) > 8 { - value = value[:8] - } - t, err = time.ParseInLocation(formatTime, value, time.Local) - } - if err != nil { - return err - } - fieldV.Set(reflect.ValueOf(t)) - } - case reflect.Slice: - if fieldT.Type == sliceOfInts { - formVals := form[tag] - fieldV.Set(reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(int(1))), len(formVals), len(formVals))) - for i := 0; i < len(formVals); i++ { - val, err := strconv.Atoi(formVals[i]) - if err != nil { - return err - } - fieldV.Index(i).SetInt(int64(val)) - } - } else if fieldT.Type == sliceOfStrings { - formVals := form[tag] - fieldV.Set(reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf("")), len(formVals), len(formVals))) - for i := 0; i < len(formVals); i++ { - fieldV.Index(i).SetString(formVals[i]) - } - } - } - } - return nil -} - -// ParseForm will parse form values to struct via tag. -func ParseForm(form url.Values, obj interface{}) error { - objT := reflect.TypeOf(obj) - objV := reflect.ValueOf(obj) - if !isStructPtr(objT) { - return fmt.Errorf("%v must be a struct pointer", obj) - } - objT = objT.Elem() - objV = objV.Elem() - - return parseFormToStruct(form, objT, objV) -} - -var sliceOfInts = reflect.TypeOf([]int(nil)) -var sliceOfStrings = reflect.TypeOf([]string(nil)) - -var unKind = map[reflect.Kind]bool{ - reflect.Uintptr: true, - reflect.Complex64: true, - reflect.Complex128: true, - reflect.Array: true, - reflect.Chan: true, - reflect.Func: true, - reflect.Map: true, - reflect.Ptr: true, - reflect.Slice: true, - reflect.Struct: true, - reflect.UnsafePointer: true, -} - -// RenderForm will render object to form html. -// obj must be a struct pointer. -func RenderForm(obj interface{}) template.HTML { - objT := reflect.TypeOf(obj) - objV := reflect.ValueOf(obj) - if !isStructPtr(objT) { - return template.HTML("") - } - objT = objT.Elem() - objV = objV.Elem() - - var raw []string - for i := 0; i < objT.NumField(); i++ { - fieldV := objV.Field(i) - if !fieldV.CanSet() || unKind[fieldV.Kind()] { - continue - } - - fieldT := objT.Field(i) - - label, name, fType, id, class, ignored, required := parseFormTag(fieldT) - if ignored { - continue - } - - raw = append(raw, renderFormField(label, name, fType, fieldV.Interface(), id, class, required)) - } - return template.HTML(strings.Join(raw, "
")) -} - -// renderFormField returns a string containing HTML of a single form field. -func renderFormField(label, name, fType string, value interface{}, id string, class string, required bool) string { - if id != "" { - id = " id=\"" + id + "\"" - } - - if class != "" { - class = " class=\"" + class + "\"" - } - - requiredString := "" - if required { - requiredString = " required" - } - - if isValidForInput(fType) { - return fmt.Sprintf(`%v`, label, id, class, name, fType, value, requiredString) - } - - return fmt.Sprintf(`%v<%v%v%v name="%v"%v>%v`, label, fType, id, class, name, requiredString, value, fType) -} - -// isValidForInput checks if fType is a valid value for the `type` property of an HTML input element. -func isValidForInput(fType string) bool { - validInputTypes := strings.Fields("text password checkbox radio submit reset hidden image file button search email url tel number range date month week time datetime datetime-local color") - for _, validType := range validInputTypes { - if fType == validType { - return true - } - } - return false -} - -// parseFormTag takes the stuct-tag of a StructField and parses the `form` value. -// returned are the form label, name-property, type and wether the field should be ignored. -func parseFormTag(fieldT reflect.StructField) (label, name, fType string, id string, class string, ignored bool, required bool) { - tags := strings.Split(fieldT.Tag.Get("form"), ",") - label = fieldT.Name + ": " - name = fieldT.Name - fType = "text" - ignored = false - id = fieldT.Tag.Get("id") - class = fieldT.Tag.Get("class") - - required = false - requiredField := fieldT.Tag.Get("required") - if requiredField != "-" && requiredField != "" { - required, _ = strconv.ParseBool(requiredField) - } - - switch len(tags) { - case 1: - if tags[0] == "-" { - ignored = true - } - if len(tags[0]) > 0 { - name = tags[0] - } - case 2: - if len(tags[0]) > 0 { - name = tags[0] - } - if len(tags[1]) > 0 { - fType = tags[1] - } - case 3: - if len(tags[0]) > 0 { - name = tags[0] - } - if len(tags[1]) > 0 { - fType = tags[1] - } - if len(tags[2]) > 0 { - label = tags[2] - } - } - - return -} - -func isStructPtr(t reflect.Type) bool { - return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct -} - -// go1.2 added template funcs. begin -var ( - errBadComparisonType = errors.New("invalid type for comparison") - errBadComparison = errors.New("incompatible types for comparison") - errNoComparison = errors.New("missing argument for comparison") -) - -type kind int - -const ( - invalidKind kind = iota - boolKind - complexKind - intKind - floatKind - stringKind - uintKind -) - -func basicKind(v reflect.Value) (kind, error) { - switch v.Kind() { - case reflect.Bool: - return boolKind, nil - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return intKind, nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return uintKind, nil - case reflect.Float32, reflect.Float64: - return floatKind, nil - case reflect.Complex64, reflect.Complex128: - return complexKind, nil - case reflect.String: - return stringKind, nil - } - return invalidKind, errBadComparisonType -} - -// eq evaluates the comparison a == b || a == c || ... -func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) { - v1 := reflect.ValueOf(arg1) - k1, err := basicKind(v1) - if err != nil { - return false, err - } - if len(arg2) == 0 { - return false, errNoComparison - } - for _, arg := range arg2 { - v2 := reflect.ValueOf(arg) - k2, err := basicKind(v2) - if err != nil { - return false, err - } - if k1 != k2 { - return false, errBadComparison - } - truth := false - switch k1 { - case boolKind: - truth = v1.Bool() == v2.Bool() - case complexKind: - truth = v1.Complex() == v2.Complex() - case floatKind: - truth = v1.Float() == v2.Float() - case intKind: - truth = v1.Int() == v2.Int() - case stringKind: - truth = v1.String() == v2.String() - case uintKind: - truth = v1.Uint() == v2.Uint() - default: - panic("invalid kind") - } - if truth { - return true, nil - } - } - return false, nil -} - -// ne evaluates the comparison a != b. -func ne(arg1, arg2 interface{}) (bool, error) { - // != is the inverse of ==. - equal, err := eq(arg1, arg2) - return !equal, err -} - -// lt evaluates the comparison a < b. -func lt(arg1, arg2 interface{}) (bool, error) { - v1 := reflect.ValueOf(arg1) - k1, err := basicKind(v1) - if err != nil { - return false, err - } - v2 := reflect.ValueOf(arg2) - k2, err := basicKind(v2) - if err != nil { - return false, err - } - if k1 != k2 { - return false, errBadComparison - } - truth := false - switch k1 { - case boolKind, complexKind: - return false, errBadComparisonType - case floatKind: - truth = v1.Float() < v2.Float() - case intKind: - truth = v1.Int() < v2.Int() - case stringKind: - truth = v1.String() < v2.String() - case uintKind: - truth = v1.Uint() < v2.Uint() - default: - panic("invalid kind") - } - return truth, nil -} - -// le evaluates the comparison <= b. -func le(arg1, arg2 interface{}) (bool, error) { - // <= is < or ==. - lessThan, err := lt(arg1, arg2) - if lessThan || err != nil { - return lessThan, err - } - return eq(arg1, arg2) -} - -// gt evaluates the comparison a > b. -func gt(arg1, arg2 interface{}) (bool, error) { - // > is the inverse of <=. - lessOrEqual, err := le(arg1, arg2) - if err != nil { - return false, err - } - return !lessOrEqual, nil -} - -// ge evaluates the comparison a >= b. -func ge(arg1, arg2 interface{}) (bool, error) { - // >= is the inverse of <. - lessThan, err := lt(arg1, arg2) - if err != nil { - return false, err - } - return !lessThan, nil -} - -// MapGet getting value from map by keys -// usage: -// Data["m"] = M{ -// "a": 1, -// "1": map[string]float64{ -// "c": 4, -// }, -// } -// -// {{ map_get m "a" }} // return 1 -// {{ map_get m 1 "c" }} // return 4 -func MapGet(arg1 interface{}, arg2 ...interface{}) (interface{}, error) { - arg1Type := reflect.TypeOf(arg1) - arg1Val := reflect.ValueOf(arg1) - - if arg1Type.Kind() == reflect.Map && len(arg2) > 0 { - // check whether arg2[0] type equals to arg1 key type - // if they are different, make conversion - arg2Val := reflect.ValueOf(arg2[0]) - arg2Type := reflect.TypeOf(arg2[0]) - if arg2Type.Kind() != arg1Type.Key().Kind() { - // convert arg2Value to string - var arg2ConvertedVal interface{} - arg2String := fmt.Sprintf("%v", arg2[0]) - - // convert string representation to any other type - switch arg1Type.Key().Kind() { - case reflect.Bool: - arg2ConvertedVal, _ = strconv.ParseBool(arg2String) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - arg2ConvertedVal, _ = strconv.ParseInt(arg2String, 0, 64) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - arg2ConvertedVal, _ = strconv.ParseUint(arg2String, 0, 64) - case reflect.Float32, reflect.Float64: - arg2ConvertedVal, _ = strconv.ParseFloat(arg2String, 64) - case reflect.String: - arg2ConvertedVal = arg2String - default: - arg2ConvertedVal = arg2Val.Interface() - } - arg2Val = reflect.ValueOf(arg2ConvertedVal) - } - - storedVal := arg1Val.MapIndex(arg2Val) - - if storedVal.IsValid() { - var result interface{} - - switch arg1Type.Elem().Kind() { - case reflect.Bool: - result = storedVal.Bool() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - result = storedVal.Int() - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - result = storedVal.Uint() - case reflect.Float32, reflect.Float64: - result = storedVal.Float() - case reflect.String: - result = storedVal.String() - default: - result = storedVal.Interface() - } - - // if there is more keys, handle this recursively - if len(arg2) > 1 { - return MapGet(result, arg2[1:]...) - } - return result, nil - } - return nil, nil - - } - return nil, nil -} diff --git a/vender/github.com/astaxie/beego/templatefunc_test.go b/vender/github.com/astaxie/beego/templatefunc_test.go deleted file mode 100755 index c7b8fbd..0000000 --- a/vender/github.com/astaxie/beego/templatefunc_test.go +++ /dev/null @@ -1,375 +0,0 @@ -// 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 ( - "html/template" - "net/url" - "reflect" - "testing" - "time" -) - -func TestSubstr(t *testing.T) { - s := `012345` - if Substr(s, 0, 2) != "01" { - t.Error("should be equal") - } - if Substr(s, 0, 100) != "012345" { - t.Error("should be equal") - } - if Substr(s, 12, 100) != "012345" { - t.Error("should be equal") - } -} - -func TestHtml2str(t *testing.T) { - h := `<123> 123\n - - - \n` - if HTML2str(h) != "123\\n\n\\n" { - t.Error("should be equal") - } -} - -func TestDateFormat(t *testing.T) { - ts := "Mon, 01 Jul 2013 13:27:42 CST" - tt, _ := time.Parse(time.RFC1123, ts) - - if ss := DateFormat(tt, "2006-01-02 15:04:05"); ss != "2013-07-01 13:27:42" { - t.Errorf("2013-07-01 13:27:42 does not equal %v", ss) - } -} - -func TestDate(t *testing.T) { - ts := "Mon, 01 Jul 2013 13:27:42 CST" - tt, _ := time.Parse(time.RFC1123, ts) - - if ss := Date(tt, "Y-m-d H:i:s"); ss != "2013-07-01 13:27:42" { - t.Errorf("2013-07-01 13:27:42 does not equal %v", ss) - } - if ss := Date(tt, "y-n-j h:i:s A"); ss != "13-7-1 01:27:42 PM" { - t.Errorf("13-7-1 01:27:42 PM does not equal %v", ss) - } - if ss := Date(tt, "D, d M Y g:i:s a"); ss != "Mon, 01 Jul 2013 1:27:42 pm" { - t.Errorf("Mon, 01 Jul 2013 1:27:42 pm does not equal %v", ss) - } - if ss := Date(tt, "l, d F Y G:i:s"); ss != "Monday, 01 July 2013 13:27:42" { - t.Errorf("Monday, 01 July 2013 13:27:42 does not equal %v", ss) - } -} - -func TestCompareRelated(t *testing.T) { - if !Compare("abc", "abc") { - t.Error("should be equal") - } - if Compare("abc", "aBc") { - t.Error("should be not equal") - } - if !Compare("1", 1) { - t.Error("should be equal") - } - if CompareNot("abc", "abc") { - t.Error("should be equal") - } - if !CompareNot("abc", "aBc") { - t.Error("should be not equal") - } - if !NotNil("a string") { - t.Error("should not be nil") - } -} - -func TestHtmlquote(t *testing.T) { - h := `<' ”“&">` - s := `<' ”“&">` - if Htmlquote(s) != h { - t.Error("should be equal") - } -} - -func TestHtmlunquote(t *testing.T) { - h := `<' ”“&">` - s := `<' ”“&">` - if Htmlunquote(h) != s { - t.Error("should be equal") - } -} - -func TestParseForm(t *testing.T) { - type ExtendInfo struct { - Hobby string `form:"hobby"` - Memo string - } - - type OtherInfo struct { - Organization string `form:"organization"` - Title string `form:"title"` - ExtendInfo - } - - type user struct { - ID int `form:"-"` - tag string `form:"tag"` - Name interface{} `form:"username"` - Age int `form:"age,text"` - Email string - Intro string `form:",textarea"` - StrBool bool `form:"strbool"` - Date time.Time `form:"date,2006-01-02"` - OtherInfo - } - - u := user{} - form := url.Values{ - "ID": []string{"1"}, - "-": []string{"1"}, - "tag": []string{"no"}, - "username": []string{"test"}, - "age": []string{"40"}, - "Email": []string{"test@gmail.com"}, - "Intro": []string{"I am an engineer!"}, - "strbool": []string{"yes"}, - "date": []string{"2014-11-12"}, - "organization": []string{"beego"}, - "title": []string{"CXO"}, - "hobby": []string{"Basketball"}, - "memo": []string{"nothing"}, - } - if err := ParseForm(form, u); err == nil { - t.Fatal("nothing will be changed") - } - if err := ParseForm(form, &u); err != nil { - t.Fatal(err) - } - if u.ID != 0 { - t.Errorf("ID should equal 0 but got %v", u.ID) - } - if len(u.tag) != 0 { - t.Errorf("tag's length should equal 0 but got %v", len(u.tag)) - } - if u.Name.(string) != "test" { - t.Errorf("Name should equal `test` but got `%v`", u.Name.(string)) - } - if u.Age != 40 { - t.Errorf("Age should equal 40 but got %v", u.Age) - } - if u.Email != "test@gmail.com" { - t.Errorf("Email should equal `test@gmail.com` but got `%v`", u.Email) - } - if u.Intro != "I am an engineer!" { - t.Errorf("Intro should equal `I am an engineer!` but got `%v`", u.Intro) - } - if !u.StrBool { - t.Errorf("strboll should equal `true`, but got `%v`", u.StrBool) - } - y, m, d := u.Date.Date() - if y != 2014 || m.String() != "November" || d != 12 { - t.Errorf("Date should equal `2014-11-12`, but got `%v`", u.Date.String()) - } - if u.Organization != "beego" { - t.Errorf("Organization should equal `beego`, but got `%v`", u.Organization) - } - if u.Title != "CXO" { - t.Errorf("Title should equal `CXO`, but got `%v`", u.Title) - } - if u.Hobby != "Basketball" { - t.Errorf("Hobby should equal `Basketball`, but got `%v`", u.Hobby) - } - if len(u.Memo) != 0 { - t.Errorf("Memo's length should equal 0 but got %v", len(u.Memo)) - } -} - -func TestRenderForm(t *testing.T) { - type user struct { - ID int `form:"-"` - tag string `form:"tag"` - Name interface{} `form:"username"` - Age int `form:"age,text,年龄:"` - Sex string - Email []string - Intro string `form:",textarea"` - Ignored string `form:"-"` - } - - u := user{Name: "test", Intro: "Some Text"} - output := RenderForm(u) - if output != template.HTML("") { - t.Errorf("output should be empty but got %v", output) - } - output = RenderForm(&u) - result := template.HTML( - `Name:
` + - `年龄:
` + - `Sex:
` + - `Intro: `) - if output != result { - t.Errorf("output should equal `%v` but got `%v`", result, output) - } -} - -func TestRenderFormField(t *testing.T) { - html := renderFormField("Label: ", "Name", "text", "Value", "", "", false) - if html != `Label: ` { - t.Errorf("Wrong html output for input[type=text]: %v ", html) - } - - html = renderFormField("Label: ", "Name", "textarea", "Value", "", "", false) - if html != `Label: ` { - t.Errorf("Wrong html output for textarea: %v ", html) - } - - html = renderFormField("Label: ", "Name", "textarea", "Value", "", "", true) - if html != `Label: ` { - t.Errorf("Wrong html output for textarea: %v ", html) - } -} - -func TestParseFormTag(t *testing.T) { - // create struct to contain field with different types of struct-tag `form` - type user struct { - All int `form:"name,text,年龄:"` - NoName int `form:",hidden,年龄:"` - OnlyLabel int `form:",,年龄:"` - OnlyName int `form:"name" id:"name" class:"form-name"` - Ignored int `form:"-"` - Required int `form:"name" required:"true"` - IgnoreRequired int `form:"name"` - NotRequired int `form:"name" required:"false"` - } - - objT := reflect.TypeOf(&user{}).Elem() - - label, name, fType, _, _, ignored, _ := parseFormTag(objT.Field(0)) - if !(name == "name" && label == "年龄:" && fType == "text" && !ignored) { - t.Errorf("Form Tag with name, label and type was not correctly parsed.") - } - - label, name, fType, _, _, ignored, _ = parseFormTag(objT.Field(1)) - if !(name == "NoName" && label == "年龄:" && fType == "hidden" && !ignored) { - t.Errorf("Form Tag with label and type but without name was not correctly parsed.") - } - - label, name, fType, _, _, ignored, _ = parseFormTag(objT.Field(2)) - if !(name == "OnlyLabel" && label == "年龄:" && fType == "text" && !ignored) { - t.Errorf("Form Tag containing only label was not correctly parsed.") - } - - label, name, fType, id, class, ignored, _ := parseFormTag(objT.Field(3)) - if !(name == "name" && label == "OnlyName: " && fType == "text" && !ignored && - id == "name" && class == "form-name") { - t.Errorf("Form Tag containing only name was not correctly parsed.") - } - - _, _, _, _, _, ignored, _ = parseFormTag(objT.Field(4)) - if !ignored { - t.Errorf("Form Tag that should be ignored was not correctly parsed.") - } - - _, name, _, _, _, _, required := parseFormTag(objT.Field(5)) - if !(name == "name" && required) { - t.Errorf("Form Tag containing only name and required was not correctly parsed.") - } - - _, name, _, _, _, _, required = parseFormTag(objT.Field(6)) - if !(name == "name" && !required) { - t.Errorf("Form Tag containing only name and ignore required was not correctly parsed.") - } - - _, name, _, _, _, _, required = parseFormTag(objT.Field(7)) - if !(name == "name" && !required) { - t.Errorf("Form Tag containing only name and not required was not correctly parsed.") - } - -} - -func TestMapGet(t *testing.T) { - // test one level map - m1 := map[string]int64{ - "a": 1, - "1": 2, - } - - if res, err := MapGet(m1, "a"); err == nil { - if res.(int64) != 1 { - t.Errorf("Should return 1, but return %v", res) - } - } else { - t.Errorf("Error happens %v", err) - } - - if res, err := MapGet(m1, "1"); err == nil { - if res.(int64) != 2 { - t.Errorf("Should return 2, but return %v", res) - } - } else { - t.Errorf("Error happens %v", err) - } - - if res, err := MapGet(m1, 1); err == nil { - if res.(int64) != 2 { - t.Errorf("Should return 2, but return %v", res) - } - } else { - t.Errorf("Error happens %v", err) - } - - // test 2 level map - m2 := M{ - "1": map[string]float64{ - "2": 3.5, - }, - } - - if res, err := MapGet(m2, 1, 2); err == nil { - if res.(float64) != 3.5 { - t.Errorf("Should return 3.5, but return %v", res) - } - } else { - t.Errorf("Error happens %v", err) - } - - // test 5 level map - m5 := M{ - "1": M{ - "2": M{ - "3": M{ - "4": M{ - "5": 1.2, - }, - }, - }, - }, - } - - if res, err := MapGet(m5, 1, 2, 3, 4, 5); err == nil { - if res.(float64) != 1.2 { - t.Errorf("Should return 1.2, but return %v", res) - } - } else { - t.Errorf("Error happens %v", err) - } - - // check whether element not exists in map - if res, err := MapGet(m5, 5, 4, 3, 2, 1); err == nil { - if res != nil { - t.Errorf("Should return nil, but return %v", res) - } - } else { - t.Errorf("Error happens %v", err) - } -} diff --git a/vender/github.com/astaxie/beego/testing/assertions.go b/vender/github.com/astaxie/beego/testing/assertions.go deleted file mode 100755 index 96c5d4d..0000000 --- a/vender/github.com/astaxie/beego/testing/assertions.go +++ /dev/null @@ -1,15 +0,0 @@ -// 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 testing diff --git a/vender/github.com/astaxie/beego/testing/client.go b/vender/github.com/astaxie/beego/testing/client.go deleted file mode 100755 index d2818ee..0000000 --- a/vender/github.com/astaxie/beego/testing/client.go +++ /dev/null @@ -1,65 +0,0 @@ -// 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 testing - -import ( - "github.com/cnlh/nps/vender/github.com/astaxie/beego/config" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/httplib" -) - -var port = "" -var baseURL = "http://localhost:" - -// TestHTTPRequest beego test request client -type TestHTTPRequest struct { - httplib.BeegoHTTPRequest -} - -func getPort() string { - if port == "" { - config, err := config.NewConfig("ini", "../conf/app.conf") - if err != nil { - return "8080" - } - port = config.String("httpport") - return port - } - return port -} - -// Get returns test client in GET method -func Get(path string) *TestHTTPRequest { - return &TestHTTPRequest{*httplib.Get(baseURL + getPort() + path)} -} - -// Post returns test client in POST method -func Post(path string) *TestHTTPRequest { - return &TestHTTPRequest{*httplib.Post(baseURL + getPort() + path)} -} - -// Put returns test client in PUT method -func Put(path string) *TestHTTPRequest { - return &TestHTTPRequest{*httplib.Put(baseURL + getPort() + path)} -} - -// Delete returns test client in DELETE method -func Delete(path string) *TestHTTPRequest { - return &TestHTTPRequest{*httplib.Delete(baseURL + getPort() + path)} -} - -// Head returns test client in HEAD method -func Head(path string) *TestHTTPRequest { - return &TestHTTPRequest{*httplib.Head(baseURL + getPort() + path)} -} diff --git a/vender/github.com/astaxie/beego/toolbox/healthcheck.go b/vender/github.com/astaxie/beego/toolbox/healthcheck.go deleted file mode 100755 index e3544b3..0000000 --- a/vender/github.com/astaxie/beego/toolbox/healthcheck.go +++ /dev/null @@ -1,48 +0,0 @@ -// 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 toolbox healthcheck -// -// type DatabaseCheck struct { -// } -// -// func (dc *DatabaseCheck) Check() error { -// if dc.isConnected() { -// return nil -// } else { -// return errors.New("can't connect database") -// } -// } -// -// AddHealthCheck("database",&DatabaseCheck{}) -// -// more docs: http://beego.me/docs/module/toolbox.md -package toolbox - -// AdminCheckList holds health checker map -var AdminCheckList map[string]HealthChecker - -// HealthChecker health checker interface -type HealthChecker interface { - Check() error -} - -// AddHealthCheck add health checker with name string -func AddHealthCheck(name string, hc HealthChecker) { - AdminCheckList[name] = hc -} - -func init() { - AdminCheckList = make(map[string]HealthChecker) -} diff --git a/vender/github.com/astaxie/beego/toolbox/profile.go b/vender/github.com/astaxie/beego/toolbox/profile.go deleted file mode 100755 index 06e40ed..0000000 --- a/vender/github.com/astaxie/beego/toolbox/profile.go +++ /dev/null @@ -1,184 +0,0 @@ -// 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 toolbox - -import ( - "fmt" - "io" - "log" - "os" - "path" - "runtime" - "runtime/debug" - "runtime/pprof" - "strconv" - "time" -) - -var startTime = time.Now() -var pid int - -func init() { - pid = os.Getpid() -} - -// ProcessInput parse input command string -func ProcessInput(input string, w io.Writer) { - switch input { - case "lookup goroutine": - p := pprof.Lookup("goroutine") - p.WriteTo(w, 2) - case "lookup heap": - p := pprof.Lookup("heap") - p.WriteTo(w, 2) - case "lookup threadcreate": - p := pprof.Lookup("threadcreate") - p.WriteTo(w, 2) - case "lookup block": - p := pprof.Lookup("block") - p.WriteTo(w, 2) - case "get cpuprof": - GetCPUProfile(w) - case "get memprof": - MemProf(w) - case "gc summary": - PrintGCSummary(w) - } -} - -// MemProf record memory profile in pprof -func MemProf(w io.Writer) { - filename := "mem-" + strconv.Itoa(pid) + ".memprof" - if f, err := os.Create(filename); err != nil { - fmt.Fprintf(w, "create file %s error %s\n", filename, err.Error()) - log.Fatal("record heap profile failed: ", err) - } else { - runtime.GC() - pprof.WriteHeapProfile(f) - f.Close() - fmt.Fprintf(w, "create heap profile %s \n", filename) - _, fl := path.Split(os.Args[0]) - fmt.Fprintf(w, "Now you can use this to check it: go tool pprof %s %s\n", fl, filename) - } -} - -// GetCPUProfile start cpu profile monitor -func GetCPUProfile(w io.Writer) { - sec := 30 - filename := "cpu-" + strconv.Itoa(pid) + ".pprof" - f, err := os.Create(filename) - if err != nil { - fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err) - log.Fatal("record cpu profile failed: ", err) - } - pprof.StartCPUProfile(f) - time.Sleep(time.Duration(sec) * time.Second) - pprof.StopCPUProfile() - - fmt.Fprintf(w, "create cpu profile %s \n", filename) - _, fl := path.Split(os.Args[0]) - fmt.Fprintf(w, "Now you can use this to check it: go tool pprof %s %s\n", fl, filename) -} - -// PrintGCSummary print gc information to io.Writer -func PrintGCSummary(w io.Writer) { - memStats := &runtime.MemStats{} - runtime.ReadMemStats(memStats) - gcstats := &debug.GCStats{PauseQuantiles: make([]time.Duration, 100)} - debug.ReadGCStats(gcstats) - - printGC(memStats, gcstats, w) -} - -func printGC(memStats *runtime.MemStats, gcstats *debug.GCStats, w io.Writer) { - - if gcstats.NumGC > 0 { - lastPause := gcstats.Pause[0] - elapsed := time.Now().Sub(startTime) - overhead := float64(gcstats.PauseTotal) / float64(elapsed) * 100 - allocatedRate := float64(memStats.TotalAlloc) / elapsed.Seconds() - - fmt.Fprintf(w, "NumGC:%d Pause:%s Pause(Avg):%s Overhead:%3.2f%% Alloc:%s Sys:%s Alloc(Rate):%s/s Histogram:%s %s %s \n", - gcstats.NumGC, - toS(lastPause), - toS(avg(gcstats.Pause)), - overhead, - toH(memStats.Alloc), - toH(memStats.Sys), - toH(uint64(allocatedRate)), - toS(gcstats.PauseQuantiles[94]), - toS(gcstats.PauseQuantiles[98]), - toS(gcstats.PauseQuantiles[99])) - } else { - // while GC has disabled - elapsed := time.Now().Sub(startTime) - allocatedRate := float64(memStats.TotalAlloc) / elapsed.Seconds() - - fmt.Fprintf(w, "Alloc:%s Sys:%s Alloc(Rate):%s/s\n", - toH(memStats.Alloc), - toH(memStats.Sys), - toH(uint64(allocatedRate))) - } -} - -func avg(items []time.Duration) time.Duration { - var sum time.Duration - for _, item := range items { - sum += item - } - return time.Duration(int64(sum) / int64(len(items))) -} - -// format bytes number friendly -func toH(bytes uint64) string { - switch { - case bytes < 1024: - return fmt.Sprintf("%dB", bytes) - case bytes < 1024*1024: - return fmt.Sprintf("%.2fK", float64(bytes)/1024) - case bytes < 1024*1024*1024: - return fmt.Sprintf("%.2fM", float64(bytes)/1024/1024) - default: - return fmt.Sprintf("%.2fG", float64(bytes)/1024/1024/1024) - } -} - -// short string format -func toS(d time.Duration) string { - - u := uint64(d) - if u < uint64(time.Second) { - switch { - case u == 0: - return "0" - case u < uint64(time.Microsecond): - return fmt.Sprintf("%.2fns", float64(u)) - case u < uint64(time.Millisecond): - return fmt.Sprintf("%.2fus", float64(u)/1000) - default: - return fmt.Sprintf("%.2fms", float64(u)/1000/1000) - } - } else { - switch { - case u < uint64(time.Minute): - return fmt.Sprintf("%.2fs", float64(u)/1000/1000/1000) - case u < uint64(time.Hour): - return fmt.Sprintf("%.2fm", float64(u)/1000/1000/1000/60) - default: - return fmt.Sprintf("%.2fh", float64(u)/1000/1000/1000/60/60) - } - } - -} diff --git a/vender/github.com/astaxie/beego/toolbox/profile_test.go b/vender/github.com/astaxie/beego/toolbox/profile_test.go deleted file mode 100755 index 07a20c4..0000000 --- a/vender/github.com/astaxie/beego/toolbox/profile_test.go +++ /dev/null @@ -1,28 +0,0 @@ -// 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 toolbox - -import ( - "os" - "testing" -) - -func TestProcessInput(t *testing.T) { - ProcessInput("lookup goroutine", os.Stdout) - ProcessInput("lookup heap", os.Stdout) - ProcessInput("lookup threadcreate", os.Stdout) - ProcessInput("lookup block", os.Stdout) - ProcessInput("gc summary", os.Stdout) -} diff --git a/vender/github.com/astaxie/beego/toolbox/statistics.go b/vender/github.com/astaxie/beego/toolbox/statistics.go deleted file mode 100755 index d014544..0000000 --- a/vender/github.com/astaxie/beego/toolbox/statistics.go +++ /dev/null @@ -1,149 +0,0 @@ -// 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 toolbox - -import ( - "fmt" - "sync" - "time" -) - -// Statistics struct -type Statistics struct { - RequestURL string - RequestController string - RequestNum int64 - MinTime time.Duration - MaxTime time.Duration - TotalTime time.Duration -} - -// URLMap contains several statistics struct to log different data -type URLMap struct { - lock sync.RWMutex - LengthLimit int //limit the urlmap's length if it's equal to 0 there's no limit - urlmap map[string]map[string]*Statistics -} - -// AddStatistics add statistics task. -// it needs request method, request url, request controller and statistics time duration -func (m *URLMap) AddStatistics(requestMethod, requestURL, requestController string, requesttime time.Duration) { - m.lock.Lock() - defer m.lock.Unlock() - if method, ok := m.urlmap[requestURL]; ok { - if s, ok := method[requestMethod]; ok { - s.RequestNum++ - if s.MaxTime < requesttime { - s.MaxTime = requesttime - } - if s.MinTime > requesttime { - s.MinTime = requesttime - } - s.TotalTime += requesttime - } else { - nb := &Statistics{ - RequestURL: requestURL, - RequestController: requestController, - RequestNum: 1, - MinTime: requesttime, - MaxTime: requesttime, - TotalTime: requesttime, - } - m.urlmap[requestURL][requestMethod] = nb - } - - } else { - if m.LengthLimit > 0 && m.LengthLimit <= len(m.urlmap) { - return - } - methodmap := make(map[string]*Statistics) - nb := &Statistics{ - RequestURL: requestURL, - RequestController: requestController, - RequestNum: 1, - MinTime: requesttime, - MaxTime: requesttime, - TotalTime: requesttime, - } - methodmap[requestMethod] = nb - m.urlmap[requestURL] = methodmap - } -} - -// GetMap put url statistics result in io.Writer -func (m *URLMap) GetMap() map[string]interface{} { - m.lock.RLock() - defer m.lock.RUnlock() - - var fields = []string{"requestUrl", "method", "times", "used", "max used", "min used", "avg used"} - - var resultLists [][]string - content := make(map[string]interface{}) - content["Fields"] = fields - - for k, v := range m.urlmap { - for kk, vv := range v { - result := []string{ - fmt.Sprintf("% -50s", k), - fmt.Sprintf("% -10s", kk), - fmt.Sprintf("% -16d", vv.RequestNum), - fmt.Sprintf("%d", vv.TotalTime), - fmt.Sprintf("% -16s", toS(vv.TotalTime)), - fmt.Sprintf("%d", vv.MaxTime), - fmt.Sprintf("% -16s", toS(vv.MaxTime)), - fmt.Sprintf("%d", vv.MinTime), - fmt.Sprintf("% -16s", toS(vv.MinTime)), - fmt.Sprintf("%d", time.Duration(int64(vv.TotalTime)/vv.RequestNum)), - fmt.Sprintf("% -16s", toS(time.Duration(int64(vv.TotalTime)/vv.RequestNum))), - } - resultLists = append(resultLists, result) - } - } - content["Data"] = resultLists - return content -} - -// GetMapData return all mapdata -func (m *URLMap) GetMapData() []map[string]interface{} { - m.lock.Lock() - defer m.lock.Unlock() - - var resultLists []map[string]interface{} - - for k, v := range m.urlmap { - for kk, vv := range v { - result := map[string]interface{}{ - "request_url": k, - "method": kk, - "times": vv.RequestNum, - "total_time": toS(vv.TotalTime), - "max_time": toS(vv.MaxTime), - "min_time": toS(vv.MinTime), - "avg_time": toS(time.Duration(int64(vv.TotalTime) / vv.RequestNum)), - } - resultLists = append(resultLists, result) - } - } - return resultLists -} - -// StatisticsMap hosld global statistics data map -var StatisticsMap *URLMap - -func init() { - StatisticsMap = &URLMap{ - urlmap: make(map[string]map[string]*Statistics), - } -} diff --git a/vender/github.com/astaxie/beego/toolbox/statistics_test.go b/vender/github.com/astaxie/beego/toolbox/statistics_test.go deleted file mode 100755 index ac29476..0000000 --- a/vender/github.com/astaxie/beego/toolbox/statistics_test.go +++ /dev/null @@ -1,40 +0,0 @@ -// 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 toolbox - -import ( - "encoding/json" - "testing" - "time" -) - -func TestStatics(t *testing.T) { - StatisticsMap.AddStatistics("POST", "/api/user", "&admin.user", time.Duration(2000)) - StatisticsMap.AddStatistics("POST", "/api/user", "&admin.user", time.Duration(120000)) - StatisticsMap.AddStatistics("GET", "/api/user", "&admin.user", time.Duration(13000)) - StatisticsMap.AddStatistics("POST", "/api/admin", "&admin.user", time.Duration(14000)) - StatisticsMap.AddStatistics("POST", "/api/user/astaxie", "&admin.user", time.Duration(12000)) - StatisticsMap.AddStatistics("POST", "/api/user/xiemengjun", "&admin.user", time.Duration(13000)) - StatisticsMap.AddStatistics("DELETE", "/api/user", "&admin.user", time.Duration(1400)) - t.Log(StatisticsMap.GetMap()) - - data := StatisticsMap.GetMapData() - b, err := json.Marshal(data) - if err != nil { - t.Errorf(err.Error()) - } - - t.Log(string(b)) -} diff --git a/vender/github.com/astaxie/beego/toolbox/task.go b/vender/github.com/astaxie/beego/toolbox/task.go deleted file mode 100755 index 259f358..0000000 --- a/vender/github.com/astaxie/beego/toolbox/task.go +++ /dev/null @@ -1,618 +0,0 @@ -// 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 toolbox - -import ( - "log" - "math" - "sort" - "strconv" - "strings" - "time" -) - -// bounds provides a range of acceptable values (plus a map of name to value). -type bounds struct { - min, max uint - names map[string]uint -} - -// The bounds for each field. -var ( - AdminTaskList map[string]Tasker - stop chan bool - changed chan bool - isstart bool - seconds = bounds{0, 59, nil} - minutes = bounds{0, 59, nil} - hours = bounds{0, 23, nil} - days = bounds{1, 31, nil} - months = bounds{1, 12, map[string]uint{ - "jan": 1, - "feb": 2, - "mar": 3, - "apr": 4, - "may": 5, - "jun": 6, - "jul": 7, - "aug": 8, - "sep": 9, - "oct": 10, - "nov": 11, - "dec": 12, - }} - weeks = bounds{0, 6, map[string]uint{ - "sun": 0, - "mon": 1, - "tue": 2, - "wed": 3, - "thu": 4, - "fri": 5, - "sat": 6, - }} -) - -const ( - // Set the top bit if a star was included in the expression. - starBit = 1 << 63 -) - -// Schedule time taks schedule -type Schedule struct { - Second uint64 - Minute uint64 - Hour uint64 - Day uint64 - Month uint64 - Week uint64 -} - -// TaskFunc task func type -type TaskFunc func() error - -// Tasker task interface -type Tasker interface { - GetSpec() string - GetStatus() string - Run() error - SetNext(time.Time) - GetNext() time.Time - SetPrev(time.Time) - GetPrev() time.Time -} - -// task error -type taskerr struct { - t time.Time - errinfo string -} - -// Task task struct -type Task struct { - Taskname string - Spec *Schedule - SpecStr string - DoFunc TaskFunc - Prev time.Time - Next time.Time - Errlist []*taskerr // like errtime:errinfo - ErrLimit int // max length for the errlist, 0 stand for no limit -} - -// NewTask add new task with name, time and func -func NewTask(tname string, spec string, f TaskFunc) *Task { - - task := &Task{ - Taskname: tname, - DoFunc: f, - ErrLimit: 100, - SpecStr: spec, - } - task.SetCron(spec) - return task -} - -// GetSpec get spec string -func (t *Task) GetSpec() string { - return t.SpecStr -} - -// GetStatus get current task status -func (t *Task) GetStatus() string { - var str string - for _, v := range t.Errlist { - str += v.t.String() + ":" + v.errinfo + "
" - } - return str -} - -// Run run all tasks -func (t *Task) Run() error { - err := t.DoFunc() - if err != nil { - if t.ErrLimit > 0 && t.ErrLimit > len(t.Errlist) { - t.Errlist = append(t.Errlist, &taskerr{t: t.Next, errinfo: err.Error()}) - } - } - return err -} - -// SetNext set next time for this task -func (t *Task) SetNext(now time.Time) { - t.Next = t.Spec.Next(now) -} - -// GetNext get the next call time of this task -func (t *Task) GetNext() time.Time { - return t.Next -} - -// SetPrev set prev time of this task -func (t *Task) SetPrev(now time.Time) { - t.Prev = now -} - -// GetPrev get prev time of this task -func (t *Task) GetPrev() time.Time { - return t.Prev -} - -// six columns mean: -// second:0-59 -// minute:0-59 -// hour:1-23 -// day:1-31 -// month:1-12 -// week:0-6(0 means Sunday) - -// SetCron some signals: -// *: any time -// ,:  separate signal -//   -:duration -// /n : do as n times of time duration -///////////////////////////////////////////////////////// -// 0/30 * * * * * every 30s -// 0 43 21 * * * 21:43 -// 0 15 05 * * *    05:15 -// 0 0 17 * * * 17:00 -// 0 0 17 * * 1 17:00 in every Monday -// 0 0,10 17 * * 0,2,3 17:00 and 17:10 in every Sunday, Tuesday and Wednesday -// 0 0-10 17 1 * * 17:00 to 17:10 in 1 min duration each time on the first day of month -// 0 0 0 1,15 * 1 0:00 on the 1st day and 15th day of month -// 0 42 4 1 * *     4:42 on the 1st day of month -// 0 0 21 * * 1-6   21:00 from Monday to Saturday -// 0 0,10,20,30,40,50 * * * *  every 10 min duration -// 0 */10 * * * *        every 10 min duration -// 0 * 1 * * *         1:00 to 1:59 in 1 min duration each time -// 0 0 1 * * *         1:00 -// 0 0 */1 * * *        0 min of hour in 1 hour duration -// 0 0 * * * *         0 min of hour in 1 hour duration -// 0 2 8-20/3 * * *       8:02, 11:02, 14:02, 17:02, 20:02 -// 0 30 5 1,15 * *       5:30 on the 1st day and 15th day of month -func (t *Task) SetCron(spec string) { - t.Spec = t.parse(spec) -} - -func (t *Task) parse(spec string) *Schedule { - if len(spec) > 0 && spec[0] == '@' { - return t.parseSpec(spec) - } - // Split on whitespace. We require 5 or 6 fields. - // (second) (minute) (hour) (day of month) (month) (day of week, optional) - fields := strings.Fields(spec) - if len(fields) != 5 && len(fields) != 6 { - log.Panicf("Expected 5 or 6 fields, found %d: %s", len(fields), spec) - } - - // If a sixth field is not provided (DayOfWeek), then it is equivalent to star. - if len(fields) == 5 { - fields = append(fields, "*") - } - - schedule := &Schedule{ - Second: getField(fields[0], seconds), - Minute: getField(fields[1], minutes), - Hour: getField(fields[2], hours), - Day: getField(fields[3], days), - Month: getField(fields[4], months), - Week: getField(fields[5], weeks), - } - - return schedule -} - -func (t *Task) parseSpec(spec string) *Schedule { - switch spec { - case "@yearly", "@annually": - return &Schedule{ - Second: 1 << seconds.min, - Minute: 1 << minutes.min, - Hour: 1 << hours.min, - Day: 1 << days.min, - Month: 1 << months.min, - Week: all(weeks), - } - - case "@monthly": - return &Schedule{ - Second: 1 << seconds.min, - Minute: 1 << minutes.min, - Hour: 1 << hours.min, - Day: 1 << days.min, - Month: all(months), - Week: all(weeks), - } - - case "@weekly": - return &Schedule{ - Second: 1 << seconds.min, - Minute: 1 << minutes.min, - Hour: 1 << hours.min, - Day: all(days), - Month: all(months), - Week: 1 << weeks.min, - } - - case "@daily", "@midnight": - return &Schedule{ - Second: 1 << seconds.min, - Minute: 1 << minutes.min, - Hour: 1 << hours.min, - Day: all(days), - Month: all(months), - Week: all(weeks), - } - - case "@hourly": - return &Schedule{ - Second: 1 << seconds.min, - Minute: 1 << minutes.min, - Hour: all(hours), - Day: all(days), - Month: all(months), - Week: all(weeks), - } - } - log.Panicf("Unrecognized descriptor: %s", spec) - return nil -} - -// Next set schedule to next time -func (s *Schedule) Next(t time.Time) time.Time { - - // Start at the earliest possible time (the upcoming second). - t = t.Add(1*time.Second - time.Duration(t.Nanosecond())*time.Nanosecond) - - // This flag indicates whether a field has been incremented. - added := false - - // If no time is found within five years, return zero. - yearLimit := t.Year() + 5 - -WRAP: - if t.Year() > yearLimit { - return time.Time{} - } - - // Find the first applicable month. - // If it's this month, then do nothing. - for 1< 0 - dowMatch = 1< 0 - ) - - if s.Day&starBit > 0 || s.Week&starBit > 0 { - return domMatch && dowMatch - } - return domMatch || dowMatch -} - -// StartTask start all tasks -func StartTask() { - if isstart { - //If already started, no need to start another goroutine. - return - } - isstart = true - go run() -} - -func run() { - now := time.Now().Local() - for _, t := range AdminTaskList { - t.SetNext(now) - } - - for { - sortList := NewMapSorter(AdminTaskList) - sortList.Sort() - var effective time.Time - if len(AdminTaskList) == 0 || sortList.Vals[0].GetNext().IsZero() { - // If there are no entries yet, just sleep - it still handles new entries - // and stop requests. - effective = now.AddDate(10, 0, 0) - } else { - effective = sortList.Vals[0].GetNext() - } - select { - case now = <-time.After(effective.Sub(now)): - // Run every entry whose next time was this effective time. - for _, e := range sortList.Vals { - if e.GetNext() != effective { - break - } - go e.Run() - e.SetPrev(e.GetNext()) - e.SetNext(effective) - } - continue - case <-changed: - now = time.Now().Local() - for _, t := range AdminTaskList { - t.SetNext(now) - } - continue - case <-stop: - return - } - } -} - -// StopTask stop all tasks -func StopTask() { - if isstart { - isstart = false - stop <- true - } - -} - -// AddTask add task with name -func AddTask(taskname string, t Tasker) { - AdminTaskList[taskname] = t - if isstart { - changed <- true - } -} - -// DeleteTask delete task with name -func DeleteTask(taskname string) { - delete(AdminTaskList, taskname) - if isstart { - changed <- true - } -} - -// MapSorter sort map for tasker -type MapSorter struct { - Keys []string - Vals []Tasker -} - -// NewMapSorter create new tasker map -func NewMapSorter(m map[string]Tasker) *MapSorter { - ms := &MapSorter{ - Keys: make([]string, 0, len(m)), - Vals: make([]Tasker, 0, len(m)), - } - for k, v := range m { - ms.Keys = append(ms.Keys, k) - ms.Vals = append(ms.Vals, v) - } - return ms -} - -// Sort sort tasker map -func (ms *MapSorter) Sort() { - sort.Sort(ms) -} - -func (ms *MapSorter) Len() int { return len(ms.Keys) } -func (ms *MapSorter) Less(i, j int) bool { - if ms.Vals[i].GetNext().IsZero() { - return false - } - if ms.Vals[j].GetNext().IsZero() { - return true - } - return ms.Vals[i].GetNext().Before(ms.Vals[j].GetNext()) -} -func (ms *MapSorter) Swap(i, j int) { - ms.Vals[i], ms.Vals[j] = ms.Vals[j], ms.Vals[i] - ms.Keys[i], ms.Keys[j] = ms.Keys[j], ms.Keys[i] -} - -func getField(field string, r bounds) uint64 { - // list = range {"," range} - var bits uint64 - ranges := strings.FieldsFunc(field, func(r rune) bool { return r == ',' }) - for _, expr := range ranges { - bits |= getRange(expr, r) - } - return bits -} - -// getRange returns the bits indicated by the given expression: -// number | number "-" number [ "/" number ] -func getRange(expr string, r bounds) uint64 { - - var ( - start, end, step uint - rangeAndStep = strings.Split(expr, "/") - lowAndHigh = strings.Split(rangeAndStep[0], "-") - singleDigit = len(lowAndHigh) == 1 - ) - - var extrastar uint64 - if lowAndHigh[0] == "*" || lowAndHigh[0] == "?" { - start = r.min - end = r.max - extrastar = starBit - } else { - start = parseIntOrName(lowAndHigh[0], r.names) - switch len(lowAndHigh) { - case 1: - end = start - case 2: - end = parseIntOrName(lowAndHigh[1], r.names) - default: - log.Panicf("Too many hyphens: %s", expr) - } - } - - switch len(rangeAndStep) { - case 1: - step = 1 - case 2: - step = mustParseInt(rangeAndStep[1]) - - // Special handling: "N/step" means "N-max/step". - if singleDigit { - end = r.max - } - default: - log.Panicf("Too many slashes: %s", expr) - } - - if start < r.min { - log.Panicf("Beginning of range (%d) below minimum (%d): %s", start, r.min, expr) - } - if end > r.max { - log.Panicf("End of range (%d) above maximum (%d): %s", end, r.max, expr) - } - if start > end { - log.Panicf("Beginning of range (%d) beyond end of range (%d): %s", start, end, expr) - } - - return getBits(start, end, step) | extrastar -} - -// parseIntOrName returns the (possibly-named) integer contained in expr. -func parseIntOrName(expr string, names map[string]uint) uint { - if names != nil { - if namedInt, ok := names[strings.ToLower(expr)]; ok { - return namedInt - } - } - return mustParseInt(expr) -} - -// mustParseInt parses the given expression as an int or panics. -func mustParseInt(expr string) uint { - num, err := strconv.Atoi(expr) - if err != nil { - log.Panicf("Failed to parse int from %s: %s", expr, err) - } - if num < 0 { - log.Panicf("Negative number (%d) not allowed: %s", num, expr) - } - - return uint(num) -} - -// getBits sets all bits in the range [min, max], modulo the given step size. -func getBits(min, max, step uint) uint64 { - var bits uint64 - - // If step is 1, use shifts. - if step == 1 { - return ^(math.MaxUint64 << (max + 1)) & (math.MaxUint64 << min) - } - - // Else, use a simple loop. - for i := min; i <= max; i += step { - bits |= 1 << i - } - return bits -} - -// all returns all bits within the given bounds. (plus the star bit) -func all(r bounds) uint64 { - return getBits(r.min, r.max, 1) | starBit -} - -func init() { - AdminTaskList = make(map[string]Tasker) - stop = make(chan bool) - changed = make(chan bool) -} diff --git a/vender/github.com/astaxie/beego/toolbox/task_test.go b/vender/github.com/astaxie/beego/toolbox/task_test.go deleted file mode 100755 index 596bc9c..0000000 --- a/vender/github.com/astaxie/beego/toolbox/task_test.go +++ /dev/null @@ -1,63 +0,0 @@ -// 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 toolbox - -import ( - "fmt" - "sync" - "testing" - "time" -) - -func TestParse(t *testing.T) { - tk := NewTask("taska", "0/30 * * * * *", func() error { fmt.Println("hello world"); return nil }) - err := tk.Run() - if err != nil { - t.Fatal(err) - } - AddTask("taska", tk) - StartTask() - time.Sleep(6 * time.Second) - StopTask() -} - -func TestSpec(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(2) - tk1 := NewTask("tk1", "0 12 * * * *", func() error { fmt.Println("tk1"); return nil }) - tk2 := NewTask("tk2", "0,10,20 * * * * *", func() error { fmt.Println("tk2"); wg.Done(); return nil }) - tk3 := NewTask("tk3", "0 10 * * * *", func() error { fmt.Println("tk3"); wg.Done(); return nil }) - - AddTask("tk1", tk1) - AddTask("tk2", tk2) - AddTask("tk3", tk3) - StartTask() - defer StopTask() - - select { - case <-time.After(200 * time.Second): - t.FailNow() - case <-wait(wg): - } -} - -func wait(wg *sync.WaitGroup) chan bool { - ch := make(chan bool) - go func() { - wg.Wait() - ch <- true - }() - return ch -} diff --git a/vender/github.com/astaxie/beego/tree.go b/vender/github.com/astaxie/beego/tree.go deleted file mode 100755 index 2466ee9..0000000 --- a/vender/github.com/astaxie/beego/tree.go +++ /dev/null @@ -1,585 +0,0 @@ -// 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 ( - "path" - "regexp" - "strings" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/utils" -) - -var ( - allowSuffixExt = []string{".json", ".xml", ".html"} -) - -// Tree has three elements: FixRouter/wildcard/leaves -// fixRouter stores Fixed Router -// wildcard stores params -// leaves store the endpoint information -type Tree struct { - //prefix set for static router - prefix string - //search fix route first - fixrouters []*Tree - //if set, failure to match fixrouters search then search wildcard - wildcard *Tree - //if set, failure to match wildcard search - leaves []*leafInfo -} - -// NewTree return a new Tree -func NewTree() *Tree { - return &Tree{} -} - -// AddTree will add tree to the exist Tree -// prefix should has no params -func (t *Tree) AddTree(prefix string, tree *Tree) { - t.addtree(splitPath(prefix), tree, nil, "") -} - -func (t *Tree) addtree(segments []string, tree *Tree, wildcards []string, reg string) { - if len(segments) == 0 { - panic("prefix should has path") - } - seg := segments[0] - iswild, params, regexpStr := splitSegment(seg) - // if it's ? meaning can igone this, so add one more rule for it - if len(params) > 0 && params[0] == ":" { - params = params[1:] - if len(segments[1:]) > 0 { - t.addtree(segments[1:], tree, append(wildcards, params...), reg) - } else { - filterTreeWithPrefix(tree, wildcards, reg) - } - } - //Rule: /login/*/access match /login/2009/11/access - //if already has *, and when loop the access, should as a regexpStr - if !iswild && utils.InSlice(":splat", wildcards) { - iswild = true - regexpStr = seg - } - //Rule: /user/:id/* - if seg == "*" && len(wildcards) > 0 && reg == "" { - regexpStr = "(.+)" - } - if len(segments) == 1 { - if iswild { - if regexpStr != "" { - if reg == "" { - rr := "" - for _, w := range wildcards { - if w == ":splat" { - rr = rr + "(.+)/" - } else { - rr = rr + "([^/]+)/" - } - } - regexpStr = rr + regexpStr - } else { - regexpStr = "/" + regexpStr - } - } else if reg != "" { - if seg == "*.*" { - regexpStr = "([^.]+).(.+)" - } else { - for _, w := range params { - if w == "." || w == ":" { - continue - } - regexpStr = "([^/]+)/" + regexpStr - } - } - } - reg = strings.Trim(reg+"/"+regexpStr, "/") - filterTreeWithPrefix(tree, append(wildcards, params...), reg) - t.wildcard = tree - } else { - reg = strings.Trim(reg+"/"+regexpStr, "/") - filterTreeWithPrefix(tree, append(wildcards, params...), reg) - tree.prefix = seg - t.fixrouters = append(t.fixrouters, tree) - } - return - } - - if iswild { - if t.wildcard == nil { - t.wildcard = NewTree() - } - if regexpStr != "" { - if reg == "" { - rr := "" - for _, w := range wildcards { - if w == ":splat" { - rr = rr + "(.+)/" - } else { - rr = rr + "([^/]+)/" - } - } - regexpStr = rr + regexpStr - } else { - regexpStr = "/" + regexpStr - } - } else if reg != "" { - if seg == "*.*" { - regexpStr = "([^.]+).(.+)" - params = params[1:] - } else { - for range params { - regexpStr = "([^/]+)/" + regexpStr - } - } - } else { - if seg == "*.*" { - params = params[1:] - } - } - reg = strings.TrimRight(strings.TrimRight(reg, "/")+"/"+regexpStr, "/") - t.wildcard.addtree(segments[1:], tree, append(wildcards, params...), reg) - } else { - subTree := NewTree() - subTree.prefix = seg - t.fixrouters = append(t.fixrouters, subTree) - subTree.addtree(segments[1:], tree, append(wildcards, params...), reg) - } -} - -func filterTreeWithPrefix(t *Tree, wildcards []string, reg string) { - for _, v := range t.fixrouters { - filterTreeWithPrefix(v, wildcards, reg) - } - if t.wildcard != nil { - filterTreeWithPrefix(t.wildcard, wildcards, reg) - } - for _, l := range t.leaves { - if reg != "" { - if l.regexps != nil { - l.wildcards = append(wildcards, l.wildcards...) - l.regexps = regexp.MustCompile("^" + reg + "/" + strings.Trim(l.regexps.String(), "^$") + "$") - } else { - for _, v := range l.wildcards { - if v == ":splat" { - reg = reg + "/(.+)" - } else { - reg = reg + "/([^/]+)" - } - } - l.regexps = regexp.MustCompile("^" + reg + "$") - l.wildcards = append(wildcards, l.wildcards...) - } - } else { - l.wildcards = append(wildcards, l.wildcards...) - if l.regexps != nil { - for _, w := range wildcards { - if w == ":splat" { - reg = "(.+)/" + reg - } else { - reg = "([^/]+)/" + reg - } - } - l.regexps = regexp.MustCompile("^" + reg + strings.Trim(l.regexps.String(), "^$") + "$") - } - } - } -} - -// AddRouter call addseg function -func (t *Tree) AddRouter(pattern string, runObject interface{}) { - t.addseg(splitPath(pattern), runObject, nil, "") -} - -// "/" -// "admin" -> -func (t *Tree) addseg(segments []string, route interface{}, wildcards []string, reg string) { - if len(segments) == 0 { - if reg != "" { - t.leaves = append(t.leaves, &leafInfo{runObject: route, wildcards: wildcards, regexps: regexp.MustCompile("^" + reg + "$")}) - } else { - t.leaves = append(t.leaves, &leafInfo{runObject: route, wildcards: wildcards}) - } - } else { - seg := segments[0] - iswild, params, regexpStr := splitSegment(seg) - // if it's ? meaning can igone this, so add one more rule for it - if len(params) > 0 && params[0] == ":" { - t.addseg(segments[1:], route, wildcards, reg) - params = params[1:] - } - //Rule: /login/*/access match /login/2009/11/access - //if already has *, and when loop the access, should as a regexpStr - if !iswild && utils.InSlice(":splat", wildcards) { - iswild = true - regexpStr = seg - } - //Rule: /user/:id/* - if seg == "*" && len(wildcards) > 0 && reg == "" { - regexpStr = "(.+)" - } - if iswild { - if t.wildcard == nil { - t.wildcard = NewTree() - } - if regexpStr != "" { - if reg == "" { - rr := "" - for _, w := range wildcards { - if w == ":splat" { - rr = rr + "(.+)/" - } else { - rr = rr + "([^/]+)/" - } - } - regexpStr = rr + regexpStr - } else { - regexpStr = "/" + regexpStr - } - } else if reg != "" { - if seg == "*.*" { - regexpStr = "/([^.]+).(.+)" - params = params[1:] - } else { - for range params { - regexpStr = "/([^/]+)" + regexpStr - } - } - } else { - if seg == "*.*" { - params = params[1:] - } - } - t.wildcard.addseg(segments[1:], route, append(wildcards, params...), reg+regexpStr) - } else { - var subTree *Tree - for _, sub := range t.fixrouters { - if sub.prefix == seg { - subTree = sub - break - } - } - if subTree == nil { - subTree = NewTree() - subTree.prefix = seg - t.fixrouters = append(t.fixrouters, subTree) - } - subTree.addseg(segments[1:], route, wildcards, reg) - } - } -} - -// Match router to runObject & params -func (t *Tree) Match(pattern string, ctx *context.Context) (runObject interface{}) { - if len(pattern) == 0 || pattern[0] != '/' { - return nil - } - w := make([]string, 0, 20) - return t.match(pattern[1:], pattern, w, ctx) -} - -func (t *Tree) match(treePattern string, pattern string, wildcardValues []string, ctx *context.Context) (runObject interface{}) { - if len(pattern) > 0 { - i := 0 - for ; i < len(pattern) && pattern[i] == '/'; i++ { - } - pattern = pattern[i:] - } - // Handle leaf nodes: - if len(pattern) == 0 { - for _, l := range t.leaves { - if ok := l.match(treePattern, wildcardValues, ctx); ok { - return l.runObject - } - } - if t.wildcard != nil { - for _, l := range t.wildcard.leaves { - if ok := l.match(treePattern, wildcardValues, ctx); ok { - return l.runObject - } - } - } - return nil - } - var seg string - i, l := 0, len(pattern) - for ; i < l && pattern[i] != '/'; i++ { - } - if i == 0 { - seg = pattern - pattern = "" - } else { - seg = pattern[:i] - pattern = pattern[i:] - } - for _, subTree := range t.fixrouters { - if subTree.prefix == seg { - if len(pattern) != 0 && pattern[0] == '/' { - treePattern = pattern[1:] - } else { - treePattern = pattern - } - runObject = subTree.match(treePattern, pattern, wildcardValues, ctx) - if runObject != nil { - break - } - } - } - if runObject == nil && len(t.fixrouters) > 0 { - // Filter the .json .xml .html extension - for _, str := range allowSuffixExt { - if strings.HasSuffix(seg, str) { - for _, subTree := range t.fixrouters { - if subTree.prefix == seg[:len(seg)-len(str)] { - runObject = subTree.match(treePattern, pattern, wildcardValues, ctx) - if runObject != nil { - ctx.Input.SetParam(":ext", str[1:]) - } - } - } - } - } - } - if runObject == nil && t.wildcard != nil { - runObject = t.wildcard.match(treePattern, pattern, append(wildcardValues, seg), ctx) - } - - if runObject == nil && len(t.leaves) > 0 { - wildcardValues = append(wildcardValues, seg) - start, i := 0, 0 - for ; i < len(pattern); i++ { - if pattern[i] == '/' { - if i != 0 && start < len(pattern) { - wildcardValues = append(wildcardValues, pattern[start:i]) - } - start = i + 1 - continue - } - } - if start > 0 { - wildcardValues = append(wildcardValues, pattern[start:i]) - } - for _, l := range t.leaves { - if ok := l.match(treePattern, wildcardValues, ctx); ok { - return l.runObject - } - } - } - return runObject -} - -type leafInfo struct { - // names of wildcards that lead to this leaf. eg, ["id" "name"] for the wildcard ":id" and ":name" - wildcards []string - - // if the leaf is regexp - regexps *regexp.Regexp - - runObject interface{} -} - -func (leaf *leafInfo) match(treePattern string, wildcardValues []string, ctx *context.Context) (ok bool) { - //fmt.Println("Leaf:", wildcardValues, leaf.wildcards, leaf.regexps) - if leaf.regexps == nil { - if len(wildcardValues) == 0 && len(leaf.wildcards) == 0 { // static path - return true - } - // match * - if len(leaf.wildcards) == 1 && leaf.wildcards[0] == ":splat" { - ctx.Input.SetParam(":splat", treePattern) - return true - } - // match *.* or :id - if len(leaf.wildcards) >= 2 && leaf.wildcards[len(leaf.wildcards)-2] == ":path" && leaf.wildcards[len(leaf.wildcards)-1] == ":ext" { - if len(leaf.wildcards) == 2 { - lastone := wildcardValues[len(wildcardValues)-1] - strs := strings.SplitN(lastone, ".", 2) - if len(strs) == 2 { - ctx.Input.SetParam(":ext", strs[1]) - } - ctx.Input.SetParam(":path", path.Join(path.Join(wildcardValues[:len(wildcardValues)-1]...), strs[0])) - return true - } else if len(wildcardValues) < 2 { - return false - } - var index int - for index = 0; index < len(leaf.wildcards)-2; index++ { - ctx.Input.SetParam(leaf.wildcards[index], wildcardValues[index]) - } - lastone := wildcardValues[len(wildcardValues)-1] - strs := strings.SplitN(lastone, ".", 2) - if len(strs) == 2 { - ctx.Input.SetParam(":ext", strs[1]) - } - if index > (len(wildcardValues) - 1) { - ctx.Input.SetParam(":path", "") - } else { - ctx.Input.SetParam(":path", path.Join(path.Join(wildcardValues[index:len(wildcardValues)-1]...), strs[0])) - } - return true - } - // match :id - if len(leaf.wildcards) != len(wildcardValues) { - return false - } - for j, v := range leaf.wildcards { - ctx.Input.SetParam(v, wildcardValues[j]) - } - return true - } - - if !leaf.regexps.MatchString(path.Join(wildcardValues...)) { - return false - } - matches := leaf.regexps.FindStringSubmatch(path.Join(wildcardValues...)) - for i, match := range matches[1:] { - if i < len(leaf.wildcards) { - ctx.Input.SetParam(leaf.wildcards[i], match) - } - } - return true -} - -// "/" -> [] -// "/admin" -> ["admin"] -// "/admin/" -> ["admin"] -// "/admin/users" -> ["admin", "users"] -func splitPath(key string) []string { - key = strings.Trim(key, "/ ") - if key == "" { - return []string{} - } - return strings.Split(key, "/") -} - -// "admin" -> false, nil, "" -// ":id" -> true, [:id], "" -// "?:id" -> true, [: :id], "" : meaning can empty -// ":id:int" -> true, [:id], ([0-9]+) -// ":name:string" -> true, [:name], ([\w]+) -// ":id([0-9]+)" -> true, [:id], ([0-9]+) -// ":id([0-9]+)_:name" -> true, [:id :name], ([0-9]+)_(.+) -// "cms_:id_:page.html" -> true, [:id_ :page], cms_(.+)(.+).html -// "cms_:id(.+)_:page.html" -> true, [:id :page], cms_(.+)_(.+).html -// "*" -> true, [:splat], "" -// "*.*" -> true,[. :path :ext], "" . meaning separator -func splitSegment(key string) (bool, []string, string) { - if strings.HasPrefix(key, "*") { - if key == "*.*" { - return true, []string{".", ":path", ":ext"}, "" - } - return true, []string{":splat"}, "" - } - if strings.ContainsAny(key, ":") { - var paramsNum int - var out []rune - var start bool - var startexp bool - var param []rune - var expt []rune - var skipnum int - params := []string{} - reg := regexp.MustCompile(`[a-zA-Z0-9_]+`) - for i, v := range key { - if skipnum > 0 { - skipnum-- - continue - } - if start { - //:id:int and :name:string - if v == ':' { - if len(key) >= i+4 { - if key[i+1:i+4] == "int" { - out = append(out, []rune("([0-9]+)")...) - params = append(params, ":"+string(param)) - start = false - startexp = false - skipnum = 3 - param = make([]rune, 0) - paramsNum++ - continue - } - } - if len(key) >= i+7 { - if key[i+1:i+7] == "string" { - out = append(out, []rune(`([\w]+)`)...) - params = append(params, ":"+string(param)) - paramsNum++ - start = false - startexp = false - skipnum = 6 - param = make([]rune, 0) - continue - } - } - } - // params only support a-zA-Z0-9 - if reg.MatchString(string(v)) { - param = append(param, v) - continue - } - if v != '(' { - out = append(out, []rune(`(.+)`)...) - params = append(params, ":"+string(param)) - param = make([]rune, 0) - paramsNum++ - start = false - startexp = false - } - } - if startexp { - if v != ')' { - expt = append(expt, v) - continue - } - } - // Escape Sequence '\' - if i > 0 && key[i-1] == '\\' { - out = append(out, v) - } else if v == ':' { - param = make([]rune, 0) - start = true - } else if v == '(' { - startexp = true - start = false - if len(param) > 0 { - params = append(params, ":"+string(param)) - param = make([]rune, 0) - } - paramsNum++ - expt = make([]rune, 0) - expt = append(expt, '(') - } else if v == ')' { - startexp = false - expt = append(expt, ')') - out = append(out, expt...) - param = make([]rune, 0) - } else if v == '?' { - params = append(params, ":") - } else { - out = append(out, v) - } - } - if len(param) > 0 { - if paramsNum > 0 { - out = append(out, []rune(`(.+)`)...) - } - params = append(params, ":"+string(param)) - } - return true, params, string(out) - } - return false, nil, "" -} diff --git a/vender/github.com/astaxie/beego/tree_test.go b/vender/github.com/astaxie/beego/tree_test.go deleted file mode 100755 index 8517e66..0000000 --- a/vender/github.com/astaxie/beego/tree_test.go +++ /dev/null @@ -1,306 +0,0 @@ -// 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" - "testing" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" -) - -type testinfo struct { - url string - requesturl string - params map[string]string -} - -var routers []testinfo - -func init() { - routers = make([]testinfo, 0) - routers = append(routers, testinfo{"/topic/?:auth:int", "/topic", nil}) - routers = append(routers, testinfo{"/topic/?:auth:int", "/topic/123", map[string]string{":auth": "123"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1", map[string]string{":id": "1"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1/2", map[string]string{":id": "1", ":auth": "2"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1", map[string]string{":id": "1"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1/123", map[string]string{":id": "1", ":auth": "123"}}) - routers = append(routers, testinfo{"/:id", "/123", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/hello/?:id", "/hello", map[string]string{":id": ""}}) - routers = append(routers, testinfo{"/", "/", nil}) - routers = append(routers, testinfo{"/customer/login", "/customer/login", nil}) - routers = append(routers, testinfo{"/customer/login", "/customer/login.json", map[string]string{":ext": "json"}}) - routers = append(routers, testinfo{"/*", "/http://customer/123/", map[string]string{":splat": "http://customer/123/"}}) - routers = append(routers, testinfo{"/*", "/customer/2009/12/11", map[string]string{":splat": "customer/2009/12/11"}}) - routers = append(routers, testinfo{"/aa/*/bb", "/aa/2009/bb", map[string]string{":splat": "2009"}}) - routers = append(routers, testinfo{"/cc/*/dd", "/cc/2009/11/dd", map[string]string{":splat": "2009/11"}}) - routers = append(routers, testinfo{"/cc/:id/*", "/cc/2009/11/dd", map[string]string{":id": "2009", ":splat": "11/dd"}}) - routers = append(routers, testinfo{"/ee/:year/*/ff", "/ee/2009/11/ff", map[string]string{":year": "2009", ":splat": "11"}}) - routers = append(routers, testinfo{"/thumbnail/:size/uploads/*", - "/thumbnail/100x100/uploads/items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg", - map[string]string{":size": "100x100", ":splat": "items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg"}}) - routers = append(routers, testinfo{"/*.*", "/nice/api.json", map[string]string{":path": "nice/api", ":ext": "json"}}) - routers = append(routers, testinfo{"/:name/*.*", "/nice/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"}}) - routers = append(routers, testinfo{"/:name/test/*.*", "/nice/test/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"}}) - routers = append(routers, testinfo{"/dl/:width:int/:height:int/*.*", - "/dl/48/48/05ac66d9bda00a3acf948c43e306fc9a.jpg", - map[string]string{":width": "48", ":height": "48", ":ext": "jpg", ":path": "05ac66d9bda00a3acf948c43e306fc9a"}}) - routers = append(routers, testinfo{"/v1/shop/:id:int", "/v1/shop/123", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(a)", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(b)", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(c)", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/:year:int/:month:int/:id/:endid", "/1111/111/aaa/aaa", map[string]string{":year": "1111", ":month": "111", ":id": "aaa", ":endid": "aaa"}}) - routers = append(routers, testinfo{"/v1/shop/:id/:name", "/v1/shop/123/nike", map[string]string{":id": "123", ":name": "nike"}}) - routers = append(routers, testinfo{"/v1/shop/:id/account", "/v1/shop/123/account", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:name:string", "/v1/shop/nike", map[string]string{":name": "nike"}}) - routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)", "/v1/shop//123", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)_:name", "/v1/shop/123_nike", map[string]string{":id": "123", ":name": "nike"}}) - routers = append(routers, testinfo{"/v1/shop/:id(.+)_cms.html", "/v1/shop/123_cms.html", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/cms_:id(.+)_:page(.+).html", "/v1/shop/cms_123_1.html", map[string]string{":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/v1/:v/cms/aaa_:id(.+)_:page(.+).html", "/v1/2/cms/aaa_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/v1/:v/cms_:id(.+)_:page(.+).html", "/v1/2/cms_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", "/v1/2_cms/ttt_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/api/projects/:pid/members/?:mid", "/api/projects/1/members", map[string]string{":pid": "1"}}) - routers = append(routers, testinfo{"/api/projects/:pid/members/?:mid", "/api/projects/1/members/2", map[string]string{":pid": "1", ":mid": "2"}}) -} - -func TestTreeRouters(t *testing.T) { - for _, r := range routers { - tr := NewTree() - tr.AddRouter(r.url, "astaxie") - ctx := context.NewContext() - obj := tr.Match(r.requesturl, ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal(r.url+" can't get obj, Expect ", r.requesturl) - } - if r.params != nil { - for k, v := range r.params { - if vv := ctx.Input.Param(k); vv != v { - t.Fatal("The Rule: " + r.url + "\nThe RequestURL:" + r.requesturl + "\nThe Key is " + k + ", The Value should be: " + v + ", but get: " + vv) - } else if vv == "" && v != "" { - t.Fatal(r.url + " " + r.requesturl + " get param empty:" + k) - } - } - } - } -} - -func TestStaticPath(t *testing.T) { - tr := NewTree() - tr.AddRouter("/topic/:id", "wildcard") - tr.AddRouter("/topic", "static") - ctx := context.NewContext() - obj := tr.Match("/topic", ctx) - if obj == nil || obj.(string) != "static" { - t.Fatal("/topic is a static route") - } - obj = tr.Match("/topic/1", ctx) - if obj == nil || obj.(string) != "wildcard" { - t.Fatal("/topic/1 is a wildcard route") - } -} - -func TestAddTree(t *testing.T) { - tr := NewTree() - tr.AddRouter("/shop/:id/account", "astaxie") - tr.AddRouter("/shop/:sd/ttt_:id(.+)_:page(.+).html", "astaxie") - t1 := NewTree() - t1.AddTree("/v1/zl", tr) - ctx := context.NewContext() - obj := t1.Match("/v1/zl/shop/123/account", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/v1/zl/shop/:id/account can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":id") != "123" { - t.Fatal("get :id param error") - } - ctx.Input.Reset(ctx) - obj = t1.Match("/v1/zl/shop/123/ttt_1_12.html", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/v1/zl//shop/:sd/ttt_:id(.+)_:page(.+).html can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":sd") != "123" || ctx.Input.Param(":id") != "1" || ctx.Input.Param(":page") != "12" { - t.Fatal("get :sd :id :page param error") - } - - t2 := NewTree() - t2.AddTree("/v1/:shopid", tr) - ctx.Input.Reset(ctx) - obj = t2.Match("/v1/zl/shop/123/account", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/v1/:shopid/shop/:id/account can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":id") != "123" || ctx.Input.Param(":shopid") != "zl" { - t.Fatal("get :id :shopid param error") - } - ctx.Input.Reset(ctx) - obj = t2.Match("/v1/zl/shop/123/ttt_1_12.html", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/v1/:shopid/shop/:sd/ttt_:id(.+)_:page(.+).html can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get :shopid param error") - } - if ctx.Input.Param(":sd") != "123" || ctx.Input.Param(":id") != "1" || ctx.Input.Param(":page") != "12" || ctx.Input.Param(":shopid") != "zl" { - t.Fatal("get :sd :id :page :shopid param error") - } -} - -func TestAddTree2(t *testing.T) { - tr := NewTree() - tr.AddRouter("/shop/:id/account", "astaxie") - tr.AddRouter("/shop/:sd/ttt_:id(.+)_:page(.+).html", "astaxie") - t3 := NewTree() - t3.AddTree("/:version(v1|v2)/:prefix", tr) - ctx := context.NewContext() - obj := t3.Match("/v1/zl/shop/123/account", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/:version(v1|v2)/:prefix/shop/:id/account can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":id") != "123" || ctx.Input.Param(":prefix") != "zl" || ctx.Input.Param(":version") != "v1" { - t.Fatal("get :id :prefix :version param error") - } -} - -func TestAddTree3(t *testing.T) { - tr := NewTree() - tr.AddRouter("/create", "astaxie") - tr.AddRouter("/shop/:sd/account", "astaxie") - t3 := NewTree() - t3.AddTree("/table/:num", tr) - ctx := context.NewContext() - obj := t3.Match("/table/123/shop/123/account", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/table/:num/shop/:sd/account can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":num") != "123" || ctx.Input.Param(":sd") != "123" { - t.Fatal("get :num :sd param error") - } - ctx.Input.Reset(ctx) - obj = t3.Match("/table/123/create", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/table/:num/create can't get obj ") - } -} - -func TestAddTree4(t *testing.T) { - tr := NewTree() - tr.AddRouter("/create", "astaxie") - tr.AddRouter("/shop/:sd/:account", "astaxie") - t4 := NewTree() - t4.AddTree("/:info:int/:num/:id", tr) - ctx := context.NewContext() - obj := t4.Match("/12/123/456/shop/123/account", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/:info:int/:num/:id/shop/:sd/:account can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":info") != "12" || ctx.Input.Param(":num") != "123" || - ctx.Input.Param(":id") != "456" || ctx.Input.Param(":sd") != "123" || - ctx.Input.Param(":account") != "account" { - t.Fatal("get :info :num :id :sd :account param error") - } - ctx.Input.Reset(ctx) - obj = t4.Match("/12/123/456/create", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/:info:int/:num/:id/create can't get obj ") - } -} - -// Test for issue #1595 -func TestAddTree5(t *testing.T) { - tr := NewTree() - tr.AddRouter("/v1/shop/:id", "shopdetail") - tr.AddRouter("/v1/shop/", "shophome") - ctx := context.NewContext() - obj := tr.Match("/v1/shop/", ctx) - if obj == nil || obj.(string) != "shophome" { - t.Fatal("url /v1/shop/ need match router /v1/shop/ ") - } -} - -func TestSplitPath(t *testing.T) { - a := splitPath("") - if len(a) != 0 { - t.Fatal("/ should retrun []") - } - a = splitPath("/") - if len(a) != 0 { - t.Fatal("/ should retrun []") - } - a = splitPath("/admin") - if len(a) != 1 || a[0] != "admin" { - t.Fatal("/admin should retrun [admin]") - } - a = splitPath("/admin/") - if len(a) != 1 || a[0] != "admin" { - t.Fatal("/admin/ should retrun [admin]") - } - a = splitPath("/admin/users") - if len(a) != 2 || a[0] != "admin" || a[1] != "users" { - t.Fatal("/admin should retrun [admin users]") - } - a = splitPath("/admin/:id:int") - if len(a) != 2 || a[0] != "admin" || a[1] != ":id:int" { - t.Fatal("/admin should retrun [admin :id:int]") - } -} - -func TestSplitSegment(t *testing.T) { - - items := map[string]struct { - isReg bool - params []string - regStr string - }{ - "admin": {false, nil, ""}, - "*": {true, []string{":splat"}, ""}, - "*.*": {true, []string{".", ":path", ":ext"}, ""}, - ":id": {true, []string{":id"}, ""}, - "?:id": {true, []string{":", ":id"}, ""}, - ":id:int": {true, []string{":id"}, "([0-9]+)"}, - ":name:string": {true, []string{":name"}, `([\w]+)`}, - ":id([0-9]+)": {true, []string{":id"}, `([0-9]+)`}, - ":id([0-9]+)_:name": {true, []string{":id", ":name"}, `([0-9]+)_(.+)`}, - ":id(.+)_cms.html": {true, []string{":id"}, `(.+)_cms.html`}, - "cms_:id(.+)_:page(.+).html": {true, []string{":id", ":page"}, `cms_(.+)_(.+).html`}, - `:app(a|b|c)`: {true, []string{":app"}, `(a|b|c)`}, - `:app\((a|b|c)\)`: {true, []string{":app"}, `(.+)\((a|b|c)\)`}, - } - - for pattern, v := range items { - b, w, r := splitSegment(pattern) - if b != v.isReg || r != v.regStr || strings.Join(w, ",") != strings.Join(v.params, ",") { - t.Fatalf("%s should return %t,%s,%q, got %t,%s,%q", pattern, v.isReg, v.params, v.regStr, b, w, r) - } - } -} diff --git a/vender/github.com/astaxie/beego/unregroute_test.go b/vender/github.com/astaxie/beego/unregroute_test.go deleted file mode 100755 index 08b1b77..0000000 --- a/vender/github.com/astaxie/beego/unregroute_test.go +++ /dev/null @@ -1,226 +0,0 @@ -// 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" -) - -// -// The unregroute_test.go contains tests for the unregister route -// functionality, that allows overriding route paths in children project -// that embed parent routers. -// - -const contentRootOriginal = "ok-original-root" -const contentLevel1Original = "ok-original-level1" -const contentLevel2Original = "ok-original-level2" - -const contentRootReplacement = "ok-replacement-root" -const contentLevel1Replacement = "ok-replacement-level1" -const contentLevel2Replacement = "ok-replacement-level2" - -// TestPreUnregController will supply content for the original routes, -// before unregistration -type TestPreUnregController struct { - Controller -} - -func (tc *TestPreUnregController) GetFixedRoot() { - tc.Ctx.Output.Body([]byte(contentRootOriginal)) -} -func (tc *TestPreUnregController) GetFixedLevel1() { - tc.Ctx.Output.Body([]byte(contentLevel1Original)) -} -func (tc *TestPreUnregController) GetFixedLevel2() { - tc.Ctx.Output.Body([]byte(contentLevel2Original)) -} - -// TestPostUnregController will supply content for the overriding routes, -// after the original ones are unregistered. -type TestPostUnregController struct { - Controller -} - -func (tc *TestPostUnregController) GetFixedRoot() { - tc.Ctx.Output.Body([]byte(contentRootReplacement)) -} -func (tc *TestPostUnregController) GetFixedLevel1() { - tc.Ctx.Output.Body([]byte(contentLevel1Replacement)) -} -func (tc *TestPostUnregController) GetFixedLevel2() { - tc.Ctx.Output.Body([]byte(contentLevel2Replacement)) -} - -// TestUnregisterFixedRouteRoot replaces just the root fixed route path. -// In this case, for a path like "/level1/level2" or "/level1", those actions -// should remain intact, and continue to serve the original content. -func TestUnregisterFixedRouteRoot(t *testing.T) { - - var method = "GET" - - handler := NewControllerRegister() - handler.Add("/", &TestPreUnregController{}, "get:GetFixedRoot") - handler.Add("/level1", &TestPreUnregController{}, "get:GetFixedLevel1") - handler.Add("/level1/level2", &TestPreUnregController{}, "get:GetFixedLevel2") - - // Test original root - testHelperFnContentCheck(t, handler, "Test original root", - method, "/", contentRootOriginal) - - // Test original level 1 - testHelperFnContentCheck(t, handler, "Test original level 1", - method, "/level1", contentLevel1Original) - - // Test original level 2 - testHelperFnContentCheck(t, handler, "Test original level 2", - method, "/level1/level2", contentLevel2Original) - - // Remove only the root path - findAndRemoveSingleTree(handler.routers[method]) - - // Replace the root path TestPreUnregController action with the action from - // TestPostUnregController - handler.Add("/", &TestPostUnregController{}, "get:GetFixedRoot") - - // Test replacement root (expect change) - testHelperFnContentCheck(t, handler, "Test replacement root (expect change)", method, "/", contentRootReplacement) - - // Test level 1 (expect no change from the original) - testHelperFnContentCheck(t, handler, "Test level 1 (expect no change from the original)", method, "/level1", contentLevel1Original) - - // Test level 2 (expect no change from the original) - testHelperFnContentCheck(t, handler, "Test level 2 (expect no change from the original)", method, "/level1/level2", contentLevel2Original) - -} - -// TestUnregisterFixedRouteLevel1 replaces just the "/level1" fixed route path. -// In this case, for a path like "/level1/level2" or "/", those actions -// should remain intact, and continue to serve the original content. -func TestUnregisterFixedRouteLevel1(t *testing.T) { - - var method = "GET" - - handler := NewControllerRegister() - handler.Add("/", &TestPreUnregController{}, "get:GetFixedRoot") - handler.Add("/level1", &TestPreUnregController{}, "get:GetFixedLevel1") - handler.Add("/level1/level2", &TestPreUnregController{}, "get:GetFixedLevel2") - - // Test original root - testHelperFnContentCheck(t, handler, - "TestUnregisterFixedRouteLevel1.Test original root", - method, "/", contentRootOriginal) - - // Test original level 1 - testHelperFnContentCheck(t, handler, - "TestUnregisterFixedRouteLevel1.Test original level 1", - method, "/level1", contentLevel1Original) - - // Test original level 2 - testHelperFnContentCheck(t, handler, - "TestUnregisterFixedRouteLevel1.Test original level 2", - method, "/level1/level2", contentLevel2Original) - - // Remove only the level1 path - subPaths := splitPath("/level1") - if handler.routers[method].prefix == strings.Trim("/level1", "/ ") { - findAndRemoveSingleTree(handler.routers[method]) - } else { - findAndRemoveTree(subPaths, handler.routers[method], method) - } - - // Replace the "level1" path TestPreUnregController action with the action from - // TestPostUnregController - handler.Add("/level1", &TestPostUnregController{}, "get:GetFixedLevel1") - - // Test replacement root (expect no change from the original) - testHelperFnContentCheck(t, handler, "Test replacement root (expect no change from the original)", method, "/", contentRootOriginal) - - // Test level 1 (expect change) - testHelperFnContentCheck(t, handler, "Test level 1 (expect change)", method, "/level1", contentLevel1Replacement) - - // Test level 2 (expect no change from the original) - testHelperFnContentCheck(t, handler, "Test level 2 (expect no change from the original)", method, "/level1/level2", contentLevel2Original) - -} - -// TestUnregisterFixedRouteLevel2 unregisters just the "/level1/level2" fixed -// route path. In this case, for a path like "/level1" or "/", those actions -// should remain intact, and continue to serve the original content. -func TestUnregisterFixedRouteLevel2(t *testing.T) { - - var method = "GET" - - handler := NewControllerRegister() - handler.Add("/", &TestPreUnregController{}, "get:GetFixedRoot") - handler.Add("/level1", &TestPreUnregController{}, "get:GetFixedLevel1") - handler.Add("/level1/level2", &TestPreUnregController{}, "get:GetFixedLevel2") - - // Test original root - testHelperFnContentCheck(t, handler, - "TestUnregisterFixedRouteLevel1.Test original root", - method, "/", contentRootOriginal) - - // Test original level 1 - testHelperFnContentCheck(t, handler, - "TestUnregisterFixedRouteLevel1.Test original level 1", - method, "/level1", contentLevel1Original) - - // Test original level 2 - testHelperFnContentCheck(t, handler, - "TestUnregisterFixedRouteLevel1.Test original level 2", - method, "/level1/level2", contentLevel2Original) - - // Remove only the level2 path - subPaths := splitPath("/level1/level2") - if handler.routers[method].prefix == strings.Trim("/level1/level2", "/ ") { - findAndRemoveSingleTree(handler.routers[method]) - } else { - findAndRemoveTree(subPaths, handler.routers[method], method) - } - - // Replace the "/level1/level2" path TestPreUnregController action with the action from - // TestPostUnregController - handler.Add("/level1/level2", &TestPostUnregController{}, "get:GetFixedLevel2") - - // Test replacement root (expect no change from the original) - testHelperFnContentCheck(t, handler, "Test replacement root (expect no change from the original)", method, "/", contentRootOriginal) - - // Test level 1 (expect no change from the original) - testHelperFnContentCheck(t, handler, "Test level 1 (expect no change from the original)", method, "/level1", contentLevel1Original) - - // Test level 2 (expect change) - testHelperFnContentCheck(t, handler, "Test level 2 (expect change)", method, "/level1/level2", contentLevel2Replacement) - -} - -func testHelperFnContentCheck(t *testing.T, handler *ControllerRegister, - testName, method, path, expectedBodyContent string) { - - r, err := http.NewRequest(method, path, nil) - if err != nil { - t.Errorf("httpRecorderBodyTest NewRequest error: %v", err) - return - } - w := httptest.NewRecorder() - handler.ServeHTTP(w, r) - body := w.Body.String() - if body != expectedBodyContent { - t.Errorf("%s: expected [%s], got [%s];", testName, expectedBodyContent, body) - } -} diff --git a/vender/github.com/astaxie/beego/utils/caller.go b/vender/github.com/astaxie/beego/utils/caller.go deleted file mode 100755 index 73c52a6..0000000 --- a/vender/github.com/astaxie/beego/utils/caller.go +++ /dev/null @@ -1,25 +0,0 @@ -// 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 utils - -import ( - "reflect" - "runtime" -) - -// GetFuncName get function name -func GetFuncName(i interface{}) string { - return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() -} diff --git a/vender/github.com/astaxie/beego/utils/caller_test.go b/vender/github.com/astaxie/beego/utils/caller_test.go deleted file mode 100755 index 0675f0a..0000000 --- a/vender/github.com/astaxie/beego/utils/caller_test.go +++ /dev/null @@ -1,28 +0,0 @@ -// 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 utils - -import ( - "strings" - "testing" -) - -func TestGetFuncName(t *testing.T) { - name := GetFuncName(TestGetFuncName) - t.Log(name) - if !strings.HasSuffix(name, ".TestGetFuncName") { - t.Error("get func name error") - } -} diff --git a/vender/github.com/astaxie/beego/utils/captcha/LICENSE b/vender/github.com/astaxie/beego/utils/captcha/LICENSE deleted file mode 100755 index 0ad73ae..0000000 --- a/vender/github.com/astaxie/beego/utils/captcha/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2011-2014 Dmitry Chestnykh - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vender/github.com/astaxie/beego/utils/captcha/README.md b/vender/github.com/astaxie/beego/utils/captcha/README.md deleted file mode 100755 index 89a57d1..0000000 --- a/vender/github.com/astaxie/beego/utils/captcha/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Captcha - -an example for use captcha - -``` -package controllers - -import ( - "github.com/cnlh/nps/vender/github.com/astaxie/beego" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/cache" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/utils/captcha" -) - -var cpt *captcha.Captcha - -func init() { - // use beego cache system store the captcha data - store := cache.NewMemoryCache() - cpt = captcha.NewWithFilter("/captcha/", store) -} - -type MainController struct { - beego.Controller -} - -func (this *MainController) Get() { - this.TplName = "index.tpl" -} - -func (this *MainController) Post() { - this.TplName = "index.tpl" - - this.Data["Success"] = cpt.VerifyReq(this.Ctx.Request) -} -``` - -template usage - -``` -{{.Success}} -
- {{create_captcha}} - -
-``` diff --git a/vender/github.com/astaxie/beego/utils/captcha/captcha.go b/vender/github.com/astaxie/beego/utils/captcha/captcha.go deleted file mode 100755 index e969577..0000000 --- a/vender/github.com/astaxie/beego/utils/captcha/captcha.go +++ /dev/null @@ -1,270 +0,0 @@ -// 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 captcha implements generation and verification of image CAPTCHAs. -// an example for use captcha -// -// ``` -// package controllers -// -// import ( -// "github.com/cnlh/nps/vender/github.com/astaxie/beego" -// "github.com/cnlh/nps/vender/github.com/astaxie/beego/cache" -// "github.com/cnlh/nps/vender/github.com/astaxie/beego/utils/captcha" -// ) -// -// var cpt *captcha.Captcha -// -// func init() { -// // use beego cache system store the captcha data -// store := cache.NewMemoryCache() -// cpt = captcha.NewWithFilter("/captcha/", store) -// } -// -// type MainController struct { -// beego.Controller -// } -// -// func (this *MainController) Get() { -// this.TplName = "index.tpl" -// } -// -// func (this *MainController) Post() { -// this.TplName = "index.tpl" -// -// this.Data["Success"] = cpt.VerifyReq(this.Ctx.Request) -// } -// ``` -// -// template usage -// -// ``` -// {{.Success}} -//
-// {{create_captcha}} -// -//
-// ``` -package captcha - -import ( - "fmt" - "html/template" - "net/http" - "path" - "strings" - "time" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/cache" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/utils" -) - -var ( - defaultChars = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} -) - -const ( - // default captcha attributes - challengeNums = 6 - expiration = 600 * time.Second - fieldIDName = "captcha_id" - fieldCaptchaName = "captcha" - cachePrefix = "captcha_" - defaultURLPrefix = "/captcha/" -) - -// Captcha struct -type Captcha struct { - // beego cache store - store cache.Cache - - // url prefix for captcha image - URLPrefix string - - // specify captcha id input field name - FieldIDName string - // specify captcha result input field name - FieldCaptchaName string - - // captcha image width and height - StdWidth int - StdHeight int - - // captcha chars nums - ChallengeNums int - - // captcha expiration seconds - Expiration time.Duration - - // cache key prefix - CachePrefix string -} - -// generate key string -func (c *Captcha) key(id string) string { - return c.CachePrefix + id -} - -// generate rand chars with default chars -func (c *Captcha) genRandChars() []byte { - return utils.RandomCreateBytes(c.ChallengeNums, defaultChars...) -} - -// Handler beego filter handler for serve captcha image -func (c *Captcha) Handler(ctx *context.Context) { - var chars []byte - - id := path.Base(ctx.Request.RequestURI) - if i := strings.Index(id, "."); i != -1 { - id = id[:i] - } - - key := c.key(id) - - if len(ctx.Input.Query("reload")) > 0 { - chars = c.genRandChars() - if err := c.store.Put(key, chars, c.Expiration); err != nil { - ctx.Output.SetStatus(500) - ctx.WriteString("captcha reload error") - logs.Error("Reload Create Captcha Error:", err) - return - } - } else { - if v, ok := c.store.Get(key).([]byte); ok { - chars = v - } else { - ctx.Output.SetStatus(404) - ctx.WriteString("captcha not found") - return - } - } - - img := NewImage(chars, c.StdWidth, c.StdHeight) - if _, err := img.WriteTo(ctx.ResponseWriter); err != nil { - logs.Error("Write Captcha Image Error:", err) - } -} - -// CreateCaptchaHTML template func for output html -func (c *Captcha) CreateCaptchaHTML() template.HTML { - value, err := c.CreateCaptcha() - if err != nil { - logs.Error("Create Captcha Error:", err) - return "" - } - - // create html - return template.HTML(fmt.Sprintf(``+ - ``+ - ``+ - ``, c.FieldIDName, value, c.URLPrefix, value, c.URLPrefix, value)) -} - -// CreateCaptcha create a new captcha id -func (c *Captcha) CreateCaptcha() (string, error) { - // generate captcha id - id := string(utils.RandomCreateBytes(15)) - - // get the captcha chars - chars := c.genRandChars() - - // save to store - if err := c.store.Put(c.key(id), chars, c.Expiration); err != nil { - return "", err - } - - return id, nil -} - -// VerifyReq verify from a request -func (c *Captcha) VerifyReq(req *http.Request) bool { - req.ParseForm() - return c.Verify(req.Form.Get(c.FieldIDName), req.Form.Get(c.FieldCaptchaName)) -} - -// Verify direct verify id and challenge string -func (c *Captcha) Verify(id string, challenge string) (success bool) { - if len(challenge) == 0 || len(id) == 0 { - return - } - - var chars []byte - - key := c.key(id) - - if v, ok := c.store.Get(key).([]byte); ok { - chars = v - } else { - return - } - - defer func() { - // finally remove it - c.store.Delete(key) - }() - - if len(chars) != len(challenge) { - return - } - // verify challenge - for i, c := range chars { - if c != challenge[i]-48 { - return - } - } - - return true -} - -// NewCaptcha create a new captcha.Captcha -func NewCaptcha(urlPrefix string, store cache.Cache) *Captcha { - cpt := &Captcha{} - cpt.store = store - cpt.FieldIDName = fieldIDName - cpt.FieldCaptchaName = fieldCaptchaName - cpt.ChallengeNums = challengeNums - cpt.Expiration = expiration - cpt.CachePrefix = cachePrefix - cpt.StdWidth = stdWidth - cpt.StdHeight = stdHeight - - if len(urlPrefix) == 0 { - urlPrefix = defaultURLPrefix - } - - if urlPrefix[len(urlPrefix)-1] != '/' { - urlPrefix += "/" - } - - cpt.URLPrefix = urlPrefix - - return cpt -} - -// NewWithFilter create a new captcha.Captcha and auto AddFilter for serve captacha image -// and add a template func for output html -func NewWithFilter(urlPrefix string, store cache.Cache) *Captcha { - cpt := NewCaptcha(urlPrefix, store) - - // create filter for serve captcha image - beego.InsertFilter(cpt.URLPrefix+"*", beego.BeforeRouter, cpt.Handler) - - // add to template func map - beego.AddFuncMap("create_captcha", cpt.CreateCaptchaHTML) - - return cpt -} diff --git a/vender/github.com/astaxie/beego/utils/captcha/image.go b/vender/github.com/astaxie/beego/utils/captcha/image.go deleted file mode 100755 index c3c9a83..0000000 --- a/vender/github.com/astaxie/beego/utils/captcha/image.go +++ /dev/null @@ -1,501 +0,0 @@ -// 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 captcha - -import ( - "bytes" - "image" - "image/color" - "image/png" - "io" - "math" -) - -const ( - fontWidth = 11 - fontHeight = 18 - blackChar = 1 - - // Standard width and height of a captcha image. - stdWidth = 240 - stdHeight = 80 - // Maximum absolute skew factor of a single digit. - maxSkew = 0.7 - // Number of background circles. - circleCount = 20 -) - -var font = [][]byte{ - { // 0 - 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, - 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, - 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, - 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, - 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, - 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, - 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, - 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, - 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, - }, - { // 1 - 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - }, - { // 2 - 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, - 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, - 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - }, - { // 3 - 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, - 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, - 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, - 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, - }, - { // 4 - 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, - 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, - 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, - 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, - 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, - 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, - 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, - 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, - }, - { // 5 - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, - 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, - 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, - }, - { // 6 - 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, - 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, - 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, - 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, - 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, - 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, - 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, - 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, - 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, - }, - { // 7 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, - }, - { // 8 - 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, - 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, - 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, - 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, - 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, - 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, - 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, - 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, - 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, - 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, - 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, - 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, - 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, - }, - { // 9 - 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, - 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, - 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, - 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, - 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, - }, -} - -// Image struct -type Image struct { - *image.Paletted - numWidth int - numHeight int - dotSize int -} - -var prng = &siprng{} - -// randIntn returns a pseudorandom non-negative int in range [0, n). -func randIntn(n int) int { - return prng.Intn(n) -} - -// randInt returns a pseudorandom int in range [from, to]. -func randInt(from, to int) int { - return prng.Intn(to+1-from) + from -} - -// randFloat returns a pseudorandom float64 in range [from, to]. -func randFloat(from, to float64) float64 { - return (to-from)*prng.Float64() + from -} - -func randomPalette() color.Palette { - p := make([]color.Color, circleCount+1) - // Transparent color. - p[0] = color.RGBA{0xFF, 0xFF, 0xFF, 0x00} - // Primary color. - prim := color.RGBA{ - uint8(randIntn(129)), - uint8(randIntn(129)), - uint8(randIntn(129)), - 0xFF, - } - p[1] = prim - // Circle colors. - for i := 2; i <= circleCount; i++ { - p[i] = randomBrightness(prim, 255) - } - return p -} - -// NewImage returns a new captcha image of the given width and height with the -// given digits, where each digit must be in range 0-9. -func NewImage(digits []byte, width, height int) *Image { - m := new(Image) - m.Paletted = image.NewPaletted(image.Rect(0, 0, width, height), randomPalette()) - m.calculateSizes(width, height, len(digits)) - // Randomly position captcha inside the image. - maxx := width - (m.numWidth+m.dotSize)*len(digits) - m.dotSize - maxy := height - m.numHeight - m.dotSize*2 - var border int - if width > height { - border = height / 5 - } else { - border = width / 5 - } - x := randInt(border, maxx-border) - y := randInt(border, maxy-border) - // Draw digits. - for _, n := range digits { - m.drawDigit(font[n], x, y) - x += m.numWidth + m.dotSize - } - // Draw strike-through line. - m.strikeThrough() - // Apply wave distortion. - m.distort(randFloat(5, 10), randFloat(100, 200)) - // Fill image with random circles. - m.fillWithCircles(circleCount, m.dotSize) - return m -} - -// encodedPNG encodes an image to PNG and returns -// the result as a byte slice. -func (m *Image) encodedPNG() []byte { - var buf bytes.Buffer - if err := png.Encode(&buf, m.Paletted); err != nil { - panic(err.Error()) - } - return buf.Bytes() -} - -// WriteTo writes captcha image in PNG format into the given writer. -func (m *Image) WriteTo(w io.Writer) (int64, error) { - n, err := w.Write(m.encodedPNG()) - return int64(n), err -} - -func (m *Image) calculateSizes(width, height, ncount int) { - // Goal: fit all digits inside the image. - var border int - if width > height { - border = height / 4 - } else { - border = width / 4 - } - // Convert everything to floats for calculations. - w := float64(width - border*2) - h := float64(height - border*2) - // fw takes into account 1-dot spacing between digits. - fw := float64(fontWidth + 1) - fh := float64(fontHeight) - nc := float64(ncount) - // Calculate the width of a single digit taking into account only the - // width of the image. - nw := w / nc - // Calculate the height of a digit from this width. - nh := nw * fh / fw - // Digit too high? - if nh > h { - // Fit digits based on height. - nh = h - nw = fw / fh * nh - } - // Calculate dot size. - m.dotSize = int(nh / fh) - if m.dotSize < 1 { - m.dotSize = 1 - } - // Save everything, making the actual width smaller by 1 dot to account - // for spacing between digits. - m.numWidth = int(nw) - m.dotSize - m.numHeight = int(nh) -} - -func (m *Image) drawHorizLine(fromX, toX, y int, colorIdx uint8) { - for x := fromX; x <= toX; x++ { - m.SetColorIndex(x, y, colorIdx) - } -} - -func (m *Image) drawCircle(x, y, radius int, colorIdx uint8) { - f := 1 - radius - dfx := 1 - dfy := -2 * radius - xo := 0 - yo := radius - - m.SetColorIndex(x, y+radius, colorIdx) - m.SetColorIndex(x, y-radius, colorIdx) - m.drawHorizLine(x-radius, x+radius, y, colorIdx) - - for xo < yo { - if f >= 0 { - yo-- - dfy += 2 - f += dfy - } - xo++ - dfx += 2 - f += dfx - m.drawHorizLine(x-xo, x+xo, y+yo, colorIdx) - m.drawHorizLine(x-xo, x+xo, y-yo, colorIdx) - m.drawHorizLine(x-yo, x+yo, y+xo, colorIdx) - m.drawHorizLine(x-yo, x+yo, y-xo, colorIdx) - } -} - -func (m *Image) fillWithCircles(n, maxradius int) { - maxx := m.Bounds().Max.X - maxy := m.Bounds().Max.Y - for i := 0; i < n; i++ { - colorIdx := uint8(randInt(1, circleCount-1)) - r := randInt(1, maxradius) - m.drawCircle(randInt(r, maxx-r), randInt(r, maxy-r), r, colorIdx) - } -} - -func (m *Image) strikeThrough() { - maxx := m.Bounds().Max.X - maxy := m.Bounds().Max.Y - y := randInt(maxy/3, maxy-maxy/3) - amplitude := randFloat(5, 20) - period := randFloat(80, 180) - dx := 2.0 * math.Pi / period - for x := 0; x < maxx; x++ { - xo := amplitude * math.Cos(float64(y)*dx) - yo := amplitude * math.Sin(float64(x)*dx) - for yn := 0; yn < m.dotSize; yn++ { - r := randInt(0, m.dotSize) - m.drawCircle(x+int(xo), y+int(yo)+(yn*m.dotSize), r/2, 1) - } - } -} - -func (m *Image) drawDigit(digit []byte, x, y int) { - skf := randFloat(-maxSkew, maxSkew) - xs := float64(x) - r := m.dotSize / 2 - y += randInt(-r, r) - for yo := 0; yo < fontHeight; yo++ { - for xo := 0; xo < fontWidth; xo++ { - if digit[yo*fontWidth+xo] != blackChar { - continue - } - m.drawCircle(x+xo*m.dotSize, y+yo*m.dotSize, r, 1) - } - xs += skf - x = int(xs) - } -} - -func (m *Image) distort(amplude float64, period float64) { - w := m.Bounds().Max.X - h := m.Bounds().Max.Y - - oldm := m.Paletted - newm := image.NewPaletted(image.Rect(0, 0, w, h), oldm.Palette) - - dx := 2.0 * math.Pi / period - for x := 0; x < w; x++ { - for y := 0; y < h; y++ { - xo := amplude * math.Sin(float64(y)*dx) - yo := amplude * math.Cos(float64(x)*dx) - newm.SetColorIndex(x, y, oldm.ColorIndexAt(x+int(xo), y+int(yo))) - } - } - m.Paletted = newm -} - -func randomBrightness(c color.RGBA, max uint8) color.RGBA { - minc := min3(c.R, c.G, c.B) - maxc := max3(c.R, c.G, c.B) - if maxc > max { - return c - } - n := randIntn(int(max-maxc)) - int(minc) - return color.RGBA{ - uint8(int(c.R) + n), - uint8(int(c.G) + n), - uint8(int(c.B) + n), - c.A, - } -} - -func min3(x, y, z uint8) (m uint8) { - m = x - if y < m { - m = y - } - if z < m { - m = z - } - return -} - -func max3(x, y, z uint8) (m uint8) { - m = x - if y > m { - m = y - } - if z > m { - m = z - } - return -} diff --git a/vender/github.com/astaxie/beego/utils/captcha/image_test.go b/vender/github.com/astaxie/beego/utils/captcha/image_test.go deleted file mode 100755 index 7782605..0000000 --- a/vender/github.com/astaxie/beego/utils/captcha/image_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// 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 captcha - -import ( - "testing" - - "github.com/cnlh/nps/vender/github.com/astaxie/beego/utils" -) - -type byteCounter struct { - n int64 -} - -func (bc *byteCounter) Write(b []byte) (int, error) { - bc.n += int64(len(b)) - return len(b), nil -} - -func BenchmarkNewImage(b *testing.B) { - b.StopTimer() - d := utils.RandomCreateBytes(challengeNums, defaultChars...) - b.StartTimer() - for i := 0; i < b.N; i++ { - NewImage(d, stdWidth, stdHeight) - } -} - -func BenchmarkImageWriteTo(b *testing.B) { - b.StopTimer() - d := utils.RandomCreateBytes(challengeNums, defaultChars...) - b.StartTimer() - counter := &byteCounter{} - for i := 0; i < b.N; i++ { - img := NewImage(d, stdWidth, stdHeight) - img.WriteTo(counter) - b.SetBytes(counter.n) - counter.n = 0 - } -} diff --git a/vender/github.com/astaxie/beego/utils/captcha/siprng.go b/vender/github.com/astaxie/beego/utils/captcha/siprng.go deleted file mode 100755 index 5e256cf..0000000 --- a/vender/github.com/astaxie/beego/utils/captcha/siprng.go +++ /dev/null @@ -1,277 +0,0 @@ -// 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 captcha - -import ( - "crypto/rand" - "encoding/binary" - "io" - "sync" -) - -// siprng is PRNG based on SipHash-2-4. -type siprng struct { - mu sync.Mutex - k0, k1, ctr uint64 -} - -// siphash implements SipHash-2-4, accepting a uint64 as a message. -func siphash(k0, k1, m uint64) uint64 { - // Initialization. - v0 := k0 ^ 0x736f6d6570736575 - v1 := k1 ^ 0x646f72616e646f6d - v2 := k0 ^ 0x6c7967656e657261 - v3 := k1 ^ 0x7465646279746573 - t := uint64(8) << 56 - - // Compression. - v3 ^= m - - // Round 1. - v0 += v1 - v1 = v1<<13 | v1>>(64-13) - v1 ^= v0 - v0 = v0<<32 | v0>>(64-32) - - v2 += v3 - v3 = v3<<16 | v3>>(64-16) - v3 ^= v2 - - v0 += v3 - v3 = v3<<21 | v3>>(64-21) - v3 ^= v0 - - v2 += v1 - v1 = v1<<17 | v1>>(64-17) - v1 ^= v2 - v2 = v2<<32 | v2>>(64-32) - - // Round 2. - v0 += v1 - v1 = v1<<13 | v1>>(64-13) - v1 ^= v0 - v0 = v0<<32 | v0>>(64-32) - - v2 += v3 - v3 = v3<<16 | v3>>(64-16) - v3 ^= v2 - - v0 += v3 - v3 = v3<<21 | v3>>(64-21) - v3 ^= v0 - - v2 += v1 - v1 = v1<<17 | v1>>(64-17) - v1 ^= v2 - v2 = v2<<32 | v2>>(64-32) - - v0 ^= m - - // Compress last block. - v3 ^= t - - // Round 1. - v0 += v1 - v1 = v1<<13 | v1>>(64-13) - v1 ^= v0 - v0 = v0<<32 | v0>>(64-32) - - v2 += v3 - v3 = v3<<16 | v3>>(64-16) - v3 ^= v2 - - v0 += v3 - v3 = v3<<21 | v3>>(64-21) - v3 ^= v0 - - v2 += v1 - v1 = v1<<17 | v1>>(64-17) - v1 ^= v2 - v2 = v2<<32 | v2>>(64-32) - - // Round 2. - v0 += v1 - v1 = v1<<13 | v1>>(64-13) - v1 ^= v0 - v0 = v0<<32 | v0>>(64-32) - - v2 += v3 - v3 = v3<<16 | v3>>(64-16) - v3 ^= v2 - - v0 += v3 - v3 = v3<<21 | v3>>(64-21) - v3 ^= v0 - - v2 += v1 - v1 = v1<<17 | v1>>(64-17) - v1 ^= v2 - v2 = v2<<32 | v2>>(64-32) - - v0 ^= t - - // Finalization. - v2 ^= 0xff - - // Round 1. - v0 += v1 - v1 = v1<<13 | v1>>(64-13) - v1 ^= v0 - v0 = v0<<32 | v0>>(64-32) - - v2 += v3 - v3 = v3<<16 | v3>>(64-16) - v3 ^= v2 - - v0 += v3 - v3 = v3<<21 | v3>>(64-21) - v3 ^= v0 - - v2 += v1 - v1 = v1<<17 | v1>>(64-17) - v1 ^= v2 - v2 = v2<<32 | v2>>(64-32) - - // Round 2. - v0 += v1 - v1 = v1<<13 | v1>>(64-13) - v1 ^= v0 - v0 = v0<<32 | v0>>(64-32) - - v2 += v3 - v3 = v3<<16 | v3>>(64-16) - v3 ^= v2 - - v0 += v3 - v3 = v3<<21 | v3>>(64-21) - v3 ^= v0 - - v2 += v1 - v1 = v1<<17 | v1>>(64-17) - v1 ^= v2 - v2 = v2<<32 | v2>>(64-32) - - // Round 3. - v0 += v1 - v1 = v1<<13 | v1>>(64-13) - v1 ^= v0 - v0 = v0<<32 | v0>>(64-32) - - v2 += v3 - v3 = v3<<16 | v3>>(64-16) - v3 ^= v2 - - v0 += v3 - v3 = v3<<21 | v3>>(64-21) - v3 ^= v0 - - v2 += v1 - v1 = v1<<17 | v1>>(64-17) - v1 ^= v2 - v2 = v2<<32 | v2>>(64-32) - - // Round 4. - v0 += v1 - v1 = v1<<13 | v1>>(64-13) - v1 ^= v0 - v0 = v0<<32 | v0>>(64-32) - - v2 += v3 - v3 = v3<<16 | v3>>(64-16) - v3 ^= v2 - - v0 += v3 - v3 = v3<<21 | v3>>(64-21) - v3 ^= v0 - - v2 += v1 - v1 = v1<<17 | v1>>(64-17) - v1 ^= v2 - v2 = v2<<32 | v2>>(64-32) - - return v0 ^ v1 ^ v2 ^ v3 -} - -// rekey sets a new PRNG key, which is read from crypto/rand. -func (p *siprng) rekey() { - var k [16]byte - if _, err := io.ReadFull(rand.Reader, k[:]); err != nil { - panic(err.Error()) - } - p.k0 = binary.LittleEndian.Uint64(k[0:8]) - p.k1 = binary.LittleEndian.Uint64(k[8:16]) - p.ctr = 1 -} - -// Uint64 returns a new pseudorandom uint64. -// It rekeys PRNG on the first call and every 64 MB of generated data. -func (p *siprng) Uint64() uint64 { - p.mu.Lock() - if p.ctr == 0 || p.ctr > 8*1024*1024 { - p.rekey() - } - v := siphash(p.k0, p.k1, p.ctr) - p.ctr++ - p.mu.Unlock() - return v -} - -func (p *siprng) Int63() int64 { - return int64(p.Uint64() & 0x7fffffffffffffff) -} - -func (p *siprng) Uint32() uint32 { - return uint32(p.Uint64()) -} - -func (p *siprng) Int31() int32 { - return int32(p.Uint32() & 0x7fffffff) -} - -func (p *siprng) Intn(n int) int { - if n <= 0 { - panic("invalid argument to Intn") - } - if n <= 1<<31-1 { - return int(p.Int31n(int32(n))) - } - return int(p.Int63n(int64(n))) -} - -func (p *siprng) Int63n(n int64) int64 { - if n <= 0 { - panic("invalid argument to Int63n") - } - max := int64((1 << 63) - 1 - (1<<63)%uint64(n)) - v := p.Int63() - for v > max { - v = p.Int63() - } - return v % n -} - -func (p *siprng) Int31n(n int32) int32 { - if n <= 0 { - panic("invalid argument to Int31n") - } - max := int32((1 << 31) - 1 - (1<<31)%uint32(n)) - v := p.Int31() - for v > max { - v = p.Int31() - } - return v % n -} - -func (p *siprng) Float64() float64 { return float64(p.Int63()) / (1 << 63) } diff --git a/vender/github.com/astaxie/beego/utils/captcha/siprng_test.go b/vender/github.com/astaxie/beego/utils/captcha/siprng_test.go deleted file mode 100755 index 189d3d3..0000000 --- a/vender/github.com/astaxie/beego/utils/captcha/siprng_test.go +++ /dev/null @@ -1,33 +0,0 @@ -// 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 captcha - -import "testing" - -func TestSiphash(t *testing.T) { - good := uint64(0xe849e8bb6ffe2567) - cur := siphash(0, 0, 0) - if cur != good { - t.Fatalf("siphash: expected %x, got %x", good, cur) - } -} - -func BenchmarkSiprng(b *testing.B) { - b.SetBytes(8) - p := &siprng{} - for i := 0; i < b.N; i++ { - p.Uint64() - } -} diff --git a/vender/github.com/astaxie/beego/utils/debug.go b/vender/github.com/astaxie/beego/utils/debug.go deleted file mode 100755 index 93c27b7..0000000 --- a/vender/github.com/astaxie/beego/utils/debug.go +++ /dev/null @@ -1,478 +0,0 @@ -// 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 utils - -import ( - "bytes" - "fmt" - "log" - "reflect" - "runtime" -) - -var ( - dunno = []byte("???") - centerDot = []byte("·") - dot = []byte(".") -) - -type pointerInfo struct { - prev *pointerInfo - n int - addr uintptr - pos int - used []int -} - -// Display print the data in console -func Display(data ...interface{}) { - display(true, data...) -} - -// GetDisplayString return data print string -func GetDisplayString(data ...interface{}) string { - return display(false, data...) -} - -func display(displayed bool, data ...interface{}) string { - var pc, file, line, ok = runtime.Caller(2) - - if !ok { - return "" - } - - var buf = new(bytes.Buffer) - - fmt.Fprintf(buf, "[Debug] at %s() [%s:%d]\n", function(pc), file, line) - - fmt.Fprintf(buf, "\n[Variables]\n") - - for i := 0; i < len(data); i += 2 { - var output = fomateinfo(len(data[i].(string))+3, data[i+1]) - fmt.Fprintf(buf, "%s = %s", data[i], output) - } - - if displayed { - log.Print(buf) - } - return buf.String() -} - -// return data dump and format bytes -func fomateinfo(headlen int, data ...interface{}) []byte { - var buf = new(bytes.Buffer) - - if len(data) > 1 { - fmt.Fprint(buf, " ") - - fmt.Fprint(buf, "[") - - fmt.Fprintln(buf) - } - - for k, v := range data { - var buf2 = new(bytes.Buffer) - var pointers *pointerInfo - var interfaces = make([]reflect.Value, 0, 10) - - printKeyValue(buf2, reflect.ValueOf(v), &pointers, &interfaces, nil, true, " ", 1) - - if k < len(data)-1 { - fmt.Fprint(buf2, ", ") - } - - fmt.Fprintln(buf2) - - buf.Write(buf2.Bytes()) - } - - if len(data) > 1 { - fmt.Fprintln(buf) - - fmt.Fprint(buf, " ") - - fmt.Fprint(buf, "]") - } - - return buf.Bytes() -} - -// check data is golang basic type -func isSimpleType(val reflect.Value, kind reflect.Kind, pointers **pointerInfo, interfaces *[]reflect.Value) bool { - switch kind { - case reflect.Bool: - return true - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return true - case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64: - return true - case reflect.Float32, reflect.Float64: - return true - case reflect.Complex64, reflect.Complex128: - return true - case reflect.String: - return true - case reflect.Chan: - return true - case reflect.Invalid: - return true - case reflect.Interface: - for _, in := range *interfaces { - if reflect.DeepEqual(in, val) { - return true - } - } - return false - case reflect.UnsafePointer: - if val.IsNil() { - return true - } - - var elem = val.Elem() - - if isSimpleType(elem, elem.Kind(), pointers, interfaces) { - return true - } - - var addr = val.Elem().UnsafeAddr() - - for p := *pointers; p != nil; p = p.prev { - if addr == p.addr { - return true - } - } - - return false - } - - return false -} - -// dump value -func printKeyValue(buf *bytes.Buffer, val reflect.Value, pointers **pointerInfo, interfaces *[]reflect.Value, structFilter func(string, string) bool, formatOutput bool, indent string, level int) { - var t = val.Kind() - - switch t { - case reflect.Bool: - fmt.Fprint(buf, val.Bool()) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - fmt.Fprint(buf, val.Int()) - case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64: - fmt.Fprint(buf, val.Uint()) - case reflect.Float32, reflect.Float64: - fmt.Fprint(buf, val.Float()) - case reflect.Complex64, reflect.Complex128: - fmt.Fprint(buf, val.Complex()) - case reflect.UnsafePointer: - fmt.Fprintf(buf, "unsafe.Pointer(0x%X)", val.Pointer()) - case reflect.Ptr: - if val.IsNil() { - fmt.Fprint(buf, "nil") - return - } - - var addr = val.Elem().UnsafeAddr() - - for p := *pointers; p != nil; p = p.prev { - if addr == p.addr { - p.used = append(p.used, buf.Len()) - fmt.Fprintf(buf, "0x%X", addr) - return - } - } - - *pointers = &pointerInfo{ - prev: *pointers, - addr: addr, - pos: buf.Len(), - used: make([]int, 0), - } - - fmt.Fprint(buf, "&") - - printKeyValue(buf, val.Elem(), pointers, interfaces, structFilter, formatOutput, indent, level) - case reflect.String: - fmt.Fprint(buf, "\"", val.String(), "\"") - case reflect.Interface: - var value = val.Elem() - - if !value.IsValid() { - fmt.Fprint(buf, "nil") - } else { - for _, in := range *interfaces { - if reflect.DeepEqual(in, val) { - fmt.Fprint(buf, "repeat") - return - } - } - - *interfaces = append(*interfaces, val) - - printKeyValue(buf, value, pointers, interfaces, structFilter, formatOutput, indent, level+1) - } - case reflect.Struct: - var t = val.Type() - - fmt.Fprint(buf, t) - fmt.Fprint(buf, "{") - - for i := 0; i < val.NumField(); i++ { - if formatOutput { - fmt.Fprintln(buf) - } else { - fmt.Fprint(buf, " ") - } - - var name = t.Field(i).Name - - if formatOutput { - for ind := 0; ind < level; ind++ { - fmt.Fprint(buf, indent) - } - } - - fmt.Fprint(buf, name) - fmt.Fprint(buf, ": ") - - if structFilter != nil && structFilter(t.String(), name) { - fmt.Fprint(buf, "ignore") - } else { - printKeyValue(buf, val.Field(i), pointers, interfaces, structFilter, formatOutput, indent, level+1) - } - - fmt.Fprint(buf, ",") - } - - if formatOutput { - fmt.Fprintln(buf) - - for ind := 0; ind < level-1; ind++ { - fmt.Fprint(buf, indent) - } - } else { - fmt.Fprint(buf, " ") - } - - fmt.Fprint(buf, "}") - case reflect.Array, reflect.Slice: - fmt.Fprint(buf, val.Type()) - fmt.Fprint(buf, "{") - - var allSimple = true - - for i := 0; i < val.Len(); i++ { - var elem = val.Index(i) - - var isSimple = isSimpleType(elem, elem.Kind(), pointers, interfaces) - - if !isSimple { - allSimple = false - } - - if formatOutput && !isSimple { - fmt.Fprintln(buf) - } else { - fmt.Fprint(buf, " ") - } - - if formatOutput && !isSimple { - for ind := 0; ind < level; ind++ { - fmt.Fprint(buf, indent) - } - } - - printKeyValue(buf, elem, pointers, interfaces, structFilter, formatOutput, indent, level+1) - - if i != val.Len()-1 || !allSimple { - fmt.Fprint(buf, ",") - } - } - - if formatOutput && !allSimple { - fmt.Fprintln(buf) - - for ind := 0; ind < level-1; ind++ { - fmt.Fprint(buf, indent) - } - } else { - fmt.Fprint(buf, " ") - } - - fmt.Fprint(buf, "}") - case reflect.Map: - var t = val.Type() - var keys = val.MapKeys() - - fmt.Fprint(buf, t) - fmt.Fprint(buf, "{") - - var allSimple = true - - for i := 0; i < len(keys); i++ { - var elem = val.MapIndex(keys[i]) - - var isSimple = isSimpleType(elem, elem.Kind(), pointers, interfaces) - - if !isSimple { - allSimple = false - } - - if formatOutput && !isSimple { - fmt.Fprintln(buf) - } else { - fmt.Fprint(buf, " ") - } - - if formatOutput && !isSimple { - for ind := 0; ind <= level; ind++ { - fmt.Fprint(buf, indent) - } - } - - printKeyValue(buf, keys[i], pointers, interfaces, structFilter, formatOutput, indent, level+1) - fmt.Fprint(buf, ": ") - printKeyValue(buf, elem, pointers, interfaces, structFilter, formatOutput, indent, level+1) - - if i != val.Len()-1 || !allSimple { - fmt.Fprint(buf, ",") - } - } - - if formatOutput && !allSimple { - fmt.Fprintln(buf) - - for ind := 0; ind < level-1; ind++ { - fmt.Fprint(buf, indent) - } - } else { - fmt.Fprint(buf, " ") - } - - fmt.Fprint(buf, "}") - case reflect.Chan: - fmt.Fprint(buf, val.Type()) - case reflect.Invalid: - fmt.Fprint(buf, "invalid") - default: - fmt.Fprint(buf, "unknow") - } -} - -// PrintPointerInfo dump pointer value -func PrintPointerInfo(buf *bytes.Buffer, headlen int, pointers *pointerInfo) { - var anyused = false - var pointerNum = 0 - - for p := pointers; p != nil; p = p.prev { - if len(p.used) > 0 { - anyused = true - } - pointerNum++ - p.n = pointerNum - } - - if anyused { - var pointerBufs = make([][]rune, pointerNum+1) - - for i := 0; i < len(pointerBufs); i++ { - var pointerBuf = make([]rune, buf.Len()+headlen) - - for j := 0; j < len(pointerBuf); j++ { - pointerBuf[j] = ' ' - } - - pointerBufs[i] = pointerBuf - } - - for pn := 0; pn <= pointerNum; pn++ { - for p := pointers; p != nil; p = p.prev { - if len(p.used) > 0 && p.n >= pn { - if pn == p.n { - pointerBufs[pn][p.pos+headlen] = '└' - - var maxpos = 0 - - for i, pos := range p.used { - if i < len(p.used)-1 { - pointerBufs[pn][pos+headlen] = '┴' - } else { - pointerBufs[pn][pos+headlen] = '┘' - } - - maxpos = pos - } - - for i := 0; i < maxpos-p.pos-1; i++ { - if pointerBufs[pn][i+p.pos+headlen+1] == ' ' { - pointerBufs[pn][i+p.pos+headlen+1] = '─' - } - } - } else { - pointerBufs[pn][p.pos+headlen] = '│' - - for _, pos := range p.used { - if pointerBufs[pn][pos+headlen] == ' ' { - pointerBufs[pn][pos+headlen] = '│' - } else { - pointerBufs[pn][pos+headlen] = '┼' - } - } - } - } - } - - buf.WriteString(string(pointerBufs[pn]) + "\n") - } - } -} - -// Stack get stack bytes -func Stack(skip int, indent string) []byte { - var buf = new(bytes.Buffer) - - for i := skip; ; i++ { - var pc, file, line, ok = runtime.Caller(i) - - if !ok { - break - } - - buf.WriteString(indent) - - fmt.Fprintf(buf, "at %s() [%s:%d]\n", function(pc), file, line) - } - - return buf.Bytes() -} - -// return the name of the function containing the PC if possible, -func function(pc uintptr) []byte { - fn := runtime.FuncForPC(pc) - if fn == nil { - return dunno - } - name := []byte(fn.Name()) - // The name includes the path name to the package, which is unnecessary - // since the file name is already included. Plus, it has center dots. - // That is, we see - // runtime/debug.*T·ptrmethod - // and want - // *T.ptrmethod - if period := bytes.Index(name, dot); period >= 0 { - name = name[period+1:] - } - name = bytes.Replace(name, centerDot, dot, -1) - return name -} diff --git a/vender/github.com/astaxie/beego/utils/debug_test.go b/vender/github.com/astaxie/beego/utils/debug_test.go deleted file mode 100755 index efb8924..0000000 --- a/vender/github.com/astaxie/beego/utils/debug_test.go +++ /dev/null @@ -1,46 +0,0 @@ -// 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 utils - -import ( - "testing" -) - -type mytype struct { - next *mytype - prev *mytype -} - -func TestPrint(t *testing.T) { - Display("v1", 1, "v2", 2, "v3", 3) -} - -func TestPrintPoint(t *testing.T) { - var v1 = new(mytype) - var v2 = new(mytype) - - v1.prev = nil - v1.next = v2 - - v2.prev = v1 - v2.next = nil - - Display("v1", v1, "v2", v2) -} - -func TestPrintString(t *testing.T) { - str := GetDisplayString("v1", 1, "v2", 2) - println(str) -} diff --git a/vender/github.com/astaxie/beego/utils/file.go b/vender/github.com/astaxie/beego/utils/file.go deleted file mode 100755 index 6090eb1..0000000 --- a/vender/github.com/astaxie/beego/utils/file.go +++ /dev/null @@ -1,101 +0,0 @@ -// 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 utils - -import ( - "bufio" - "errors" - "io" - "os" - "path/filepath" - "regexp" -) - -// SelfPath gets compiled executable file absolute path -func SelfPath() string { - path, _ := filepath.Abs(os.Args[0]) - return path -} - -// SelfDir gets compiled executable file directory -func SelfDir() string { - return filepath.Dir(SelfPath()) -} - -// FileExists reports whether the named file or directory exists. -func FileExists(name string) bool { - if _, err := os.Stat(name); err != nil { - if os.IsNotExist(err) { - return false - } - } - return true -} - -// SearchFile Search a file in paths. -// this is often used in search config file in /etc ~/ -func SearchFile(filename string, paths ...string) (fullpath string, err error) { - for _, path := range paths { - if fullpath = filepath.Join(path, filename); FileExists(fullpath) { - return - } - } - err = errors.New(fullpath + " not found in paths") - return -} - -// GrepFile like command grep -E -// for example: GrepFile(`^hello`, "hello.txt") -// \n is striped while read -func GrepFile(patten string, filename string) (lines []string, err error) { - re, err := regexp.Compile(patten) - if err != nil { - return - } - - fd, err := os.Open(filename) - if err != nil { - return - } - lines = make([]string, 0) - reader := bufio.NewReader(fd) - prefix := "" - var isLongLine bool - for { - byteLine, isPrefix, er := reader.ReadLine() - if er != nil && er != io.EOF { - return nil, er - } - if er == io.EOF { - break - } - line := string(byteLine) - if isPrefix { - prefix += line - continue - } else { - isLongLine = true - } - - line = prefix + line - if isLongLine { - prefix = "" - } - if re.MatchString(line) { - lines = append(lines, line) - } - } - return lines, nil -} diff --git a/vender/github.com/astaxie/beego/utils/file_test.go b/vender/github.com/astaxie/beego/utils/file_test.go deleted file mode 100755 index b264415..0000000 --- a/vender/github.com/astaxie/beego/utils/file_test.go +++ /dev/null @@ -1,75 +0,0 @@ -// 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 utils - -import ( - "path/filepath" - "reflect" - "testing" -) - -var noExistedFile = "/tmp/not_existed_file" - -func TestSelfPath(t *testing.T) { - path := SelfPath() - if path == "" { - t.Error("path cannot be empty") - } - t.Logf("SelfPath: %s", path) -} - -func TestSelfDir(t *testing.T) { - dir := SelfDir() - t.Logf("SelfDir: %s", dir) -} - -func TestFileExists(t *testing.T) { - if !FileExists("./file.go") { - t.Errorf("./file.go should exists, but it didn't") - } - - if FileExists(noExistedFile) { - t.Errorf("Weird, how could this file exists: %s", noExistedFile) - } -} - -func TestSearchFile(t *testing.T) { - path, err := SearchFile(filepath.Base(SelfPath()), SelfDir()) - if err != nil { - t.Error(err) - } - t.Log(path) - - _, err = SearchFile(noExistedFile, ".") - if err == nil { - t.Errorf("err shouldnt be nil, got path: %s", SelfDir()) - } -} - -func TestGrepFile(t *testing.T) { - _, err := GrepFile("", noExistedFile) - if err == nil { - t.Error("expect file-not-existed error, but got nothing") - } - - path := filepath.Join(".", "testdata", "grepe.test") - lines, err := GrepFile(`^\s*[^#]+`, path) - if err != nil { - t.Error(err) - } - if !reflect.DeepEqual(lines, []string{"hello", "world"}) { - t.Errorf("expect [hello world], but receive %v", lines) - } -} diff --git a/vender/github.com/astaxie/beego/utils/mail.go b/vender/github.com/astaxie/beego/utils/mail.go deleted file mode 100755 index e3fa1c9..0000000 --- a/vender/github.com/astaxie/beego/utils/mail.go +++ /dev/null @@ -1,423 +0,0 @@ -// 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 utils - -import ( - "bytes" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "io" - "mime" - "mime/multipart" - "net/mail" - "net/smtp" - "net/textproto" - "os" - "path" - "path/filepath" - "strconv" - "strings" - "sync" -) - -const ( - maxLineLength = 76 - - upperhex = "0123456789ABCDEF" -) - -// Email is the type used for email messages -type Email struct { - Auth smtp.Auth - Identity string `json:"identity"` - Username string `json:"username"` - Password string `json:"password"` - Host string `json:"host"` - Port int `json:"port"` - From string `json:"from"` - To []string - Bcc []string - Cc []string - Subject string - Text string // Plaintext message (optional) - HTML string // Html message (optional) - Headers textproto.MIMEHeader - Attachments []*Attachment - ReadReceipt []string -} - -// Attachment is a struct representing an email attachment. -// Based on the mime/multipart.FileHeader struct, Attachment contains the name, MIMEHeader, and content of the attachment in question -type Attachment struct { - Filename string - Header textproto.MIMEHeader - Content []byte -} - -// NewEMail create new Email struct with config json. -// config json is followed from Email struct fields. -func NewEMail(config string) *Email { - e := new(Email) - e.Headers = textproto.MIMEHeader{} - err := json.Unmarshal([]byte(config), e) - if err != nil { - return nil - } - return e -} - -// Bytes Make all send information to byte -func (e *Email) Bytes() ([]byte, error) { - buff := &bytes.Buffer{} - w := multipart.NewWriter(buff) - // Set the appropriate headers (overwriting any conflicts) - // Leave out Bcc (only included in envelope headers) - e.Headers.Set("To", strings.Join(e.To, ",")) - if e.Cc != nil { - e.Headers.Set("Cc", strings.Join(e.Cc, ",")) - } - e.Headers.Set("From", e.From) - e.Headers.Set("Subject", e.Subject) - if len(e.ReadReceipt) != 0 { - e.Headers.Set("Disposition-Notification-To", strings.Join(e.ReadReceipt, ",")) - } - e.Headers.Set("MIME-Version", "1.0") - - // Write the envelope headers (including any custom headers) - if err := headerToBytes(buff, e.Headers); err != nil { - return nil, fmt.Errorf("Failed to render message headers: %s", err) - } - - e.Headers.Set("Content-Type", fmt.Sprintf("multipart/mixed;\r\n boundary=%s\r\n", w.Boundary())) - fmt.Fprintf(buff, "%s:", "Content-Type") - fmt.Fprintf(buff, " %s\r\n", fmt.Sprintf("multipart/mixed;\r\n boundary=%s\r\n", w.Boundary())) - - // Start the multipart/mixed part - fmt.Fprintf(buff, "--%s\r\n", w.Boundary()) - header := textproto.MIMEHeader{} - // Check to see if there is a Text or HTML field - if e.Text != "" || e.HTML != "" { - subWriter := multipart.NewWriter(buff) - // Create the multipart alternative part - header.Set("Content-Type", fmt.Sprintf("multipart/alternative;\r\n boundary=%s\r\n", subWriter.Boundary())) - // Write the header - if err := headerToBytes(buff, header); err != nil { - return nil, fmt.Errorf("Failed to render multipart message headers: %s", err) - } - // Create the body sections - if e.Text != "" { - header.Set("Content-Type", fmt.Sprintf("text/plain; charset=UTF-8")) - header.Set("Content-Transfer-Encoding", "quoted-printable") - if _, err := subWriter.CreatePart(header); err != nil { - return nil, err - } - // Write the text - if err := quotePrintEncode(buff, e.Text); err != nil { - return nil, err - } - } - if e.HTML != "" { - header.Set("Content-Type", fmt.Sprintf("text/html; charset=UTF-8")) - header.Set("Content-Transfer-Encoding", "quoted-printable") - if _, err := subWriter.CreatePart(header); err != nil { - return nil, err - } - // Write the text - if err := quotePrintEncode(buff, e.HTML); err != nil { - return nil, err - } - } - if err := subWriter.Close(); err != nil { - return nil, err - } - } - // Create attachment part, if necessary - for _, a := range e.Attachments { - ap, err := w.CreatePart(a.Header) - if err != nil { - return nil, err - } - // Write the base64Wrapped content to the part - base64Wrap(ap, a.Content) - } - if err := w.Close(); err != nil { - return nil, err - } - return buff.Bytes(), nil -} - -// AttachFile Add attach file to the send mail -func (e *Email) AttachFile(args ...string) (a *Attachment, err error) { - if len(args) < 1 && len(args) > 2 { - err = errors.New("Must specify a file name and number of parameters can not exceed at least two") - return - } - filename := args[0] - id := "" - if len(args) > 1 { - id = args[1] - } - f, err := os.Open(filename) - if err != nil { - return - } - ct := mime.TypeByExtension(filepath.Ext(filename)) - basename := path.Base(filename) - return e.Attach(f, basename, ct, id) -} - -// Attach is used to attach content from an io.Reader to the email. -// Parameters include an io.Reader, the desired filename for the attachment, and the Content-Type. -func (e *Email) Attach(r io.Reader, filename string, args ...string) (a *Attachment, err error) { - if len(args) < 1 && len(args) > 2 { - err = errors.New("Must specify the file type and number of parameters can not exceed at least two") - return - } - c := args[0] //Content-Type - id := "" - if len(args) > 1 { - id = args[1] //Content-ID - } - var buffer bytes.Buffer - if _, err = io.Copy(&buffer, r); err != nil { - return - } - at := &Attachment{ - Filename: filename, - Header: textproto.MIMEHeader{}, - Content: buffer.Bytes(), - } - // Get the Content-Type to be used in the MIMEHeader - if c != "" { - at.Header.Set("Content-Type", c) - } else { - // If the Content-Type is blank, set the Content-Type to "application/octet-stream" - at.Header.Set("Content-Type", "application/octet-stream") - } - if id != "" { - at.Header.Set("Content-Disposition", fmt.Sprintf("inline;\r\n filename=\"%s\"", filename)) - at.Header.Set("Content-ID", fmt.Sprintf("<%s>", id)) - } else { - at.Header.Set("Content-Disposition", fmt.Sprintf("attachment;\r\n filename=\"%s\"", filename)) - } - at.Header.Set("Content-Transfer-Encoding", "base64") - e.Attachments = append(e.Attachments, at) - return at, nil -} - -// Send will send out the mail -func (e *Email) Send() error { - if e.Auth == nil { - e.Auth = smtp.PlainAuth(e.Identity, e.Username, e.Password, e.Host) - } - // Merge the To, Cc, and Bcc fields - to := make([]string, 0, len(e.To)+len(e.Cc)+len(e.Bcc)) - to = append(append(append(to, e.To...), e.Cc...), e.Bcc...) - // Check to make sure there is at least one recipient and one "From" address - if len(to) == 0 { - return errors.New("Must specify at least one To address") - } - - // Use the username if no From is provided - if len(e.From) == 0 { - e.From = e.Username - } - - from, err := mail.ParseAddress(e.From) - if err != nil { - return err - } - - // use mail's RFC 2047 to encode any string - e.Subject = qEncode("utf-8", e.Subject) - - raw, err := e.Bytes() - if err != nil { - return err - } - return smtp.SendMail(e.Host+":"+strconv.Itoa(e.Port), e.Auth, from.Address, to, raw) -} - -// quotePrintEncode writes the quoted-printable text to the IO Writer (according to RFC 2045) -func quotePrintEncode(w io.Writer, s string) error { - var buf [3]byte - mc := 0 - for i := 0; i < len(s); i++ { - c := s[i] - // We're assuming Unix style text formats as input (LF line break), and - // quoted-printble uses CRLF line breaks. (Literal CRs will become - // "=0D", but probably shouldn't be there to begin with!) - if c == '\n' { - io.WriteString(w, "\r\n") - mc = 0 - continue - } - - var nextOut []byte - if isPrintable(c) { - nextOut = append(buf[:0], c) - } else { - nextOut = buf[:] - qpEscape(nextOut, c) - } - - // Add a soft line break if the next (encoded) byte would push this line - // to or past the limit. - if mc+len(nextOut) >= maxLineLength { - if _, err := io.WriteString(w, "=\r\n"); err != nil { - return err - } - mc = 0 - } - - if _, err := w.Write(nextOut); err != nil { - return err - } - mc += len(nextOut) - } - // No trailing end-of-line?? Soft line break, then. TODO: is this sane? - if mc > 0 { - io.WriteString(w, "=\r\n") - } - return nil -} - -// isPrintable returns true if the rune given is "printable" according to RFC 2045, false otherwise -func isPrintable(c byte) bool { - return (c >= '!' && c <= '<') || (c >= '>' && c <= '~') || (c == ' ' || c == '\n' || c == '\t') -} - -// qpEscape is a helper function for quotePrintEncode which escapes a -// non-printable byte. Expects len(dest) == 3. -func qpEscape(dest []byte, c byte) { - const nums = "0123456789ABCDEF" - dest[0] = '=' - dest[1] = nums[(c&0xf0)>>4] - dest[2] = nums[(c & 0xf)] -} - -// headerToBytes enumerates the key and values in the header, and writes the results to the IO Writer -func headerToBytes(w io.Writer, t textproto.MIMEHeader) error { - for k, v := range t { - // Write the header key - _, err := fmt.Fprintf(w, "%s:", k) - if err != nil { - return err - } - // Write each value in the header - for _, c := range v { - _, err := fmt.Fprintf(w, " %s\r\n", c) - if err != nil { - return err - } - } - } - return nil -} - -// base64Wrap encodes the attachment content, and wraps it according to RFC 2045 standards (every 76 chars) -// The output is then written to the specified io.Writer -func base64Wrap(w io.Writer, b []byte) { - // 57 raw bytes per 76-byte base64 line. - const maxRaw = 57 - // Buffer for each line, including trailing CRLF. - var buffer [maxLineLength + len("\r\n")]byte - copy(buffer[maxLineLength:], "\r\n") - // Process raw chunks until there's no longer enough to fill a line. - for len(b) >= maxRaw { - base64.StdEncoding.Encode(buffer[:], b[:maxRaw]) - w.Write(buffer[:]) - b = b[maxRaw:] - } - // Handle the last chunk of bytes. - if len(b) > 0 { - out := buffer[:base64.StdEncoding.EncodedLen(len(b))] - base64.StdEncoding.Encode(out, b) - out = append(out, "\r\n"...) - w.Write(out) - } -} - -// Encode returns the encoded-word form of s. If s is ASCII without special -// characters, it is returned unchanged. The provided charset is the IANA -// charset name of s. It is case insensitive. -// RFC 2047 encoded-word -func qEncode(charset, s string) string { - if !needsEncoding(s) { - return s - } - return encodeWord(charset, s) -} - -func needsEncoding(s string) bool { - for _, b := range s { - if (b < ' ' || b > '~') && b != '\t' { - return true - } - } - return false -} - -// encodeWord encodes a string into an encoded-word. -func encodeWord(charset, s string) string { - buf := getBuffer() - - buf.WriteString("=?") - buf.WriteString(charset) - buf.WriteByte('?') - buf.WriteByte('q') - buf.WriteByte('?') - - enc := make([]byte, 3) - for i := 0; i < len(s); i++ { - b := s[i] - switch { - case b == ' ': - buf.WriteByte('_') - case b <= '~' && b >= '!' && b != '=' && b != '?' && b != '_': - buf.WriteByte(b) - default: - enc[0] = '=' - enc[1] = upperhex[b>>4] - enc[2] = upperhex[b&0x0f] - buf.Write(enc) - } - } - buf.WriteString("?=") - - es := buf.String() - putBuffer(buf) - return es -} - -var bufPool = sync.Pool{ - New: func() interface{} { - return new(bytes.Buffer) - }, -} - -func getBuffer() *bytes.Buffer { - return bufPool.Get().(*bytes.Buffer) -} - -func putBuffer(buf *bytes.Buffer) { - if buf.Len() > 1024 { - return - } - buf.Reset() - bufPool.Put(buf) -} diff --git a/vender/github.com/astaxie/beego/utils/mail_test.go b/vender/github.com/astaxie/beego/utils/mail_test.go deleted file mode 100755 index c38356a..0000000 --- a/vender/github.com/astaxie/beego/utils/mail_test.go +++ /dev/null @@ -1,41 +0,0 @@ -// 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 utils - -import "testing" - -func TestMail(t *testing.T) { - config := `{"username":"astaxie@gmail.com","password":"astaxie","host":"smtp.gmail.com","port":587}` - mail := NewEMail(config) - if mail.Username != "astaxie@gmail.com" { - t.Fatal("email parse get username error") - } - if mail.Password != "astaxie" { - t.Fatal("email parse get password error") - } - if mail.Host != "smtp.gmail.com" { - t.Fatal("email parse get host error") - } - if mail.Port != 587 { - t.Fatal("email parse get port error") - } - mail.To = []string{"xiemengjun@gmail.com"} - mail.From = "astaxie@gmail.com" - mail.Subject = "hi, just from beego!" - mail.Text = "Text Body is, of course, supported!" - mail.HTML = "

Fancy Html is supported, too!

" - mail.AttachFile("/Users/astaxie/github/beego/beego.go") - mail.Send() -} diff --git a/vender/github.com/astaxie/beego/utils/pagination/controller.go b/vender/github.com/astaxie/beego/utils/pagination/controller.go deleted file mode 100755 index 0335061..0000000 --- a/vender/github.com/astaxie/beego/utils/pagination/controller.go +++ /dev/null @@ -1,26 +0,0 @@ -// 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 pagination - -import ( - "github.com/cnlh/nps/vender/github.com/astaxie/beego/context" -) - -// SetPaginator Instantiates a Paginator and assigns it to context.Input.Data("paginator"). -func SetPaginator(context *context.Context, per int, nums int64) (paginator *Paginator) { - paginator = NewPaginator(context.Request, per, nums) - context.Input.SetData("paginator", &paginator) - return -} diff --git a/vender/github.com/astaxie/beego/utils/pagination/doc.go b/vender/github.com/astaxie/beego/utils/pagination/doc.go deleted file mode 100755 index 902f8da..0000000 --- a/vender/github.com/astaxie/beego/utils/pagination/doc.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Package pagination provides utilities to setup a paginator within the -context of a http request. - -Usage - -In your beego.Controller: - - package controllers - - import "github.com/cnlh/nps/vender/github.com/astaxie/beego/utils/pagination" - - type PostsController struct { - beego.Controller - } - - func (this *PostsController) ListAllPosts() { - // sets this.Data["paginator"] with the current offset (from the url query param) - postsPerPage := 20 - paginator := pagination.SetPaginator(this.Ctx, postsPerPage, CountPosts()) - - // fetch the next 20 posts - this.Data["posts"] = ListPostsByOffsetAndLimit(paginator.Offset(), postsPerPage) - } - - -In your view templates: - - {{if .paginator.HasPages}} - - {{end}} - -See also - -http://beego.me/docs/mvc/view/page.md - -*/ -package pagination diff --git a/vender/github.com/astaxie/beego/utils/pagination/paginator.go b/vender/github.com/astaxie/beego/utils/pagination/paginator.go deleted file mode 100755 index c6db31e..0000000 --- a/vender/github.com/astaxie/beego/utils/pagination/paginator.go +++ /dev/null @@ -1,189 +0,0 @@ -// 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 pagination - -import ( - "math" - "net/http" - "net/url" - "strconv" -) - -// Paginator within the state of a http request. -type Paginator struct { - Request *http.Request - PerPageNums int - MaxPages int - - nums int64 - pageRange []int - pageNums int - page int -} - -// PageNums Returns the total number of pages. -func (p *Paginator) PageNums() int { - if p.pageNums != 0 { - return p.pageNums - } - pageNums := math.Ceil(float64(p.nums) / float64(p.PerPageNums)) - if p.MaxPages > 0 { - pageNums = math.Min(pageNums, float64(p.MaxPages)) - } - p.pageNums = int(pageNums) - return p.pageNums -} - -// Nums Returns the total number of items (e.g. from doing SQL count). -func (p *Paginator) Nums() int64 { - return p.nums -} - -// SetNums Sets the total number of items. -func (p *Paginator) SetNums(nums interface{}) { - p.nums, _ = toInt64(nums) -} - -// Page Returns the current page. -func (p *Paginator) Page() int { - if p.page != 0 { - return p.page - } - if p.Request.Form == nil { - p.Request.ParseForm() - } - p.page, _ = strconv.Atoi(p.Request.Form.Get("p")) - if p.page > p.PageNums() { - p.page = p.PageNums() - } - if p.page <= 0 { - p.page = 1 - } - return p.page -} - -// Pages Returns a list of all pages. -// -// Usage (in a view template): -// -// {{range $index, $page := .paginator.Pages}} -// -// {{$page}} -// -// {{end}} -func (p *Paginator) Pages() []int { - if p.pageRange == nil && p.nums > 0 { - var pages []int - pageNums := p.PageNums() - page := p.Page() - switch { - case page >= pageNums-4 && pageNums > 9: - start := pageNums - 9 + 1 - pages = make([]int, 9) - for i := range pages { - pages[i] = start + i - } - case page >= 5 && pageNums > 9: - start := page - 5 + 1 - pages = make([]int, int(math.Min(9, float64(page+4+1)))) - for i := range pages { - pages[i] = start + i - } - default: - pages = make([]int, int(math.Min(9, float64(pageNums)))) - for i := range pages { - pages[i] = i + 1 - } - } - p.pageRange = pages - } - return p.pageRange -} - -// PageLink Returns URL for a given page index. -func (p *Paginator) PageLink(page int) string { - link, _ := url.ParseRequestURI(p.Request.URL.String()) - values := link.Query() - if page == 1 { - values.Del("p") - } else { - values.Set("p", strconv.Itoa(page)) - } - link.RawQuery = values.Encode() - return link.String() -} - -// PageLinkPrev Returns URL to the previous page. -func (p *Paginator) PageLinkPrev() (link string) { - if p.HasPrev() { - link = p.PageLink(p.Page() - 1) - } - return -} - -// PageLinkNext Returns URL to the next page. -func (p *Paginator) PageLinkNext() (link string) { - if p.HasNext() { - link = p.PageLink(p.Page() + 1) - } - return -} - -// PageLinkFirst Returns URL to the first page. -func (p *Paginator) PageLinkFirst() (link string) { - return p.PageLink(1) -} - -// PageLinkLast Returns URL to the last page. -func (p *Paginator) PageLinkLast() (link string) { - return p.PageLink(p.PageNums()) -} - -// HasPrev Returns true if the current page has a predecessor. -func (p *Paginator) HasPrev() bool { - return p.Page() > 1 -} - -// HasNext Returns true if the current page has a successor. -func (p *Paginator) HasNext() bool { - return p.Page() < p.PageNums() -} - -// IsActive Returns true if the given page index points to the current page. -func (p *Paginator) IsActive(page int) bool { - return p.Page() == page -} - -// Offset Returns the current offset. -func (p *Paginator) Offset() int { - return (p.Page() - 1) * p.PerPageNums -} - -// HasPages Returns true if there is more than one page. -func (p *Paginator) HasPages() bool { - return p.PageNums() > 1 -} - -// NewPaginator Instantiates a paginator struct for the current http request. -func NewPaginator(req *http.Request, per int, nums interface{}) *Paginator { - p := Paginator{} - p.Request = req - if per <= 0 { - per = 10 - } - p.PerPageNums = per - p.SetNums(nums) - return &p -} diff --git a/vender/github.com/astaxie/beego/utils/pagination/utils.go b/vender/github.com/astaxie/beego/utils/pagination/utils.go deleted file mode 100755 index 686e68b..0000000 --- a/vender/github.com/astaxie/beego/utils/pagination/utils.go +++ /dev/null @@ -1,34 +0,0 @@ -// 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 pagination - -import ( - "fmt" - "reflect" -) - -// ToInt64 convert any numeric value to int64 -func toInt64(value interface{}) (d int64, err error) { - val := reflect.ValueOf(value) - switch value.(type) { - case int, int8, int16, int32, int64: - d = val.Int() - case uint, uint8, uint16, uint32, uint64: - d = int64(val.Uint()) - default: - err = fmt.Errorf("ToInt64 need numeric not `%T`", value) - } - return -} diff --git a/vender/github.com/astaxie/beego/utils/rand.go b/vender/github.com/astaxie/beego/utils/rand.go deleted file mode 100755 index 344d1cd..0000000 --- a/vender/github.com/astaxie/beego/utils/rand.go +++ /dev/null @@ -1,44 +0,0 @@ -// 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 utils - -import ( - "crypto/rand" - r "math/rand" - "time" -) - -var alphaNum = []byte(`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`) - -// RandomCreateBytes generate random []byte by specify chars. -func RandomCreateBytes(n int, alphabets ...byte) []byte { - if len(alphabets) == 0 { - alphabets = alphaNum - } - var bytes = make([]byte, n) - var randBy bool - if num, err := rand.Read(bytes); num != n || err != nil { - r.Seed(time.Now().UnixNano()) - randBy = true - } - for i, b := range bytes { - if randBy { - bytes[i] = alphabets[r.Intn(len(alphabets))] - } else { - bytes[i] = alphabets[b%byte(len(alphabets))] - } - } - return bytes -} diff --git a/vender/github.com/astaxie/beego/utils/rand_test.go b/vender/github.com/astaxie/beego/utils/rand_test.go deleted file mode 100755 index 6c238b5..0000000 --- a/vender/github.com/astaxie/beego/utils/rand_test.go +++ /dev/null @@ -1,33 +0,0 @@ -// 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 utils - -import "testing" - -func TestRand_01(t *testing.T) { - bs0 := RandomCreateBytes(16) - bs1 := RandomCreateBytes(16) - - t.Log(string(bs0), string(bs1)) - if string(bs0) == string(bs1) { - t.FailNow() - } - - bs0 = RandomCreateBytes(4, []byte(`a`)...) - - if string(bs0) != "aaaa" { - t.FailNow() - } -} diff --git a/vender/github.com/astaxie/beego/utils/safemap.go b/vender/github.com/astaxie/beego/utils/safemap.go deleted file mode 100755 index 1793030..0000000 --- a/vender/github.com/astaxie/beego/utils/safemap.go +++ /dev/null @@ -1,91 +0,0 @@ -// 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 utils - -import ( - "sync" -) - -// BeeMap is a map with lock -type BeeMap struct { - lock *sync.RWMutex - bm map[interface{}]interface{} -} - -// NewBeeMap return new safemap -func NewBeeMap() *BeeMap { - return &BeeMap{ - lock: new(sync.RWMutex), - bm: make(map[interface{}]interface{}), - } -} - -// Get from maps return the k's value -func (m *BeeMap) Get(k interface{}) interface{} { - m.lock.RLock() - defer m.lock.RUnlock() - if val, ok := m.bm[k]; ok { - return val - } - return nil -} - -// Set Maps the given key and value. Returns false -// if the key is already in the map and changes nothing. -func (m *BeeMap) Set(k interface{}, v interface{}) bool { - m.lock.Lock() - defer m.lock.Unlock() - if val, ok := m.bm[k]; !ok { - m.bm[k] = v - } else if val != v { - m.bm[k] = v - } else { - return false - } - return true -} - -// Check Returns true if k is exist in the map. -func (m *BeeMap) Check(k interface{}) bool { - m.lock.RLock() - defer m.lock.RUnlock() - _, ok := m.bm[k] - return ok -} - -// Delete the given key and value. -func (m *BeeMap) Delete(k interface{}) { - m.lock.Lock() - defer m.lock.Unlock() - delete(m.bm, k) -} - -// Items returns all items in safemap. -func (m *BeeMap) Items() map[interface{}]interface{} { - m.lock.RLock() - defer m.lock.RUnlock() - r := make(map[interface{}]interface{}) - for k, v := range m.bm { - r[k] = v - } - return r -} - -// Count returns the number of items within the map. -func (m *BeeMap) Count() int { - m.lock.RLock() - defer m.lock.RUnlock() - return len(m.bm) -} diff --git a/vender/github.com/astaxie/beego/utils/safemap_test.go b/vender/github.com/astaxie/beego/utils/safemap_test.go deleted file mode 100755 index 6508519..0000000 --- a/vender/github.com/astaxie/beego/utils/safemap_test.go +++ /dev/null @@ -1,89 +0,0 @@ -// 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 utils - -import "testing" - -var safeMap *BeeMap - -func TestNewBeeMap(t *testing.T) { - safeMap = NewBeeMap() - if safeMap == nil { - t.Fatal("expected to return non-nil BeeMap", "got", safeMap) - } -} - -func TestSet(t *testing.T) { - safeMap = NewBeeMap() - if ok := safeMap.Set("astaxie", 1); !ok { - t.Error("expected", true, "got", false) - } -} - -func TestReSet(t *testing.T) { - safeMap := NewBeeMap() - if ok := safeMap.Set("astaxie", 1); !ok { - t.Error("expected", true, "got", false) - } - // set diff value - if ok := safeMap.Set("astaxie", -1); !ok { - t.Error("expected", true, "got", false) - } - - // set same value - if ok := safeMap.Set("astaxie", -1); ok { - t.Error("expected", false, "got", true) - } -} - -func TestCheck(t *testing.T) { - if exists := safeMap.Check("astaxie"); !exists { - t.Error("expected", true, "got", false) - } -} - -func TestGet(t *testing.T) { - if val := safeMap.Get("astaxie"); val.(int) != 1 { - t.Error("expected value", 1, "got", val) - } -} - -func TestDelete(t *testing.T) { - safeMap.Delete("astaxie") - if exists := safeMap.Check("astaxie"); exists { - t.Error("expected element to be deleted") - } -} - -func TestItems(t *testing.T) { - safeMap := NewBeeMap() - safeMap.Set("astaxie", "hello") - for k, v := range safeMap.Items() { - key := k.(string) - value := v.(string) - if key != "astaxie" { - t.Error("expected the key should be astaxie") - } - if value != "hello" { - t.Error("expected the value should be hello") - } - } -} - -func TestCount(t *testing.T) { - if count := safeMap.Count(); count != 0 { - t.Error("expected count to be", 0, "got", count) - } -} diff --git a/vender/github.com/astaxie/beego/utils/slice.go b/vender/github.com/astaxie/beego/utils/slice.go deleted file mode 100755 index 8f2cef9..0000000 --- a/vender/github.com/astaxie/beego/utils/slice.go +++ /dev/null @@ -1,170 +0,0 @@ -// 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 utils - -import ( - "math/rand" - "time" -) - -type reducetype func(interface{}) interface{} -type filtertype func(interface{}) bool - -// InSlice checks given string in string slice or not. -func InSlice(v string, sl []string) bool { - for _, vv := range sl { - if vv == v { - return true - } - } - return false -} - -// InSliceIface checks given interface in interface slice. -func InSliceIface(v interface{}, sl []interface{}) bool { - for _, vv := range sl { - if vv == v { - return true - } - } - return false -} - -// SliceRandList generate an int slice from min to max. -func SliceRandList(min, max int) []int { - if max < min { - min, max = max, min - } - length := max - min + 1 - t0 := time.Now() - rand.Seed(int64(t0.Nanosecond())) - list := rand.Perm(length) - for index := range list { - list[index] += min - } - return list -} - -// SliceMerge merges interface slices to one slice. -func SliceMerge(slice1, slice2 []interface{}) (c []interface{}) { - c = append(slice1, slice2...) - return -} - -// SliceReduce generates a new slice after parsing every value by reduce function -func SliceReduce(slice []interface{}, a reducetype) (dslice []interface{}) { - for _, v := range slice { - dslice = append(dslice, a(v)) - } - return -} - -// SliceRand returns random one from slice. -func SliceRand(a []interface{}) (b interface{}) { - randnum := rand.Intn(len(a)) - b = a[randnum] - return -} - -// SliceSum sums all values in int64 slice. -func SliceSum(intslice []int64) (sum int64) { - for _, v := range intslice { - sum += v - } - return -} - -// SliceFilter generates a new slice after filter function. -func SliceFilter(slice []interface{}, a filtertype) (ftslice []interface{}) { - for _, v := range slice { - if a(v) { - ftslice = append(ftslice, v) - } - } - return -} - -// SliceDiff returns diff slice of slice1 - slice2. -func SliceDiff(slice1, slice2 []interface{}) (diffslice []interface{}) { - for _, v := range slice1 { - if !InSliceIface(v, slice2) { - diffslice = append(diffslice, v) - } - } - return -} - -// SliceIntersect returns slice that are present in all the slice1 and slice2. -func SliceIntersect(slice1, slice2 []interface{}) (diffslice []interface{}) { - for _, v := range slice1 { - if InSliceIface(v, slice2) { - diffslice = append(diffslice, v) - } - } - return -} - -// SliceChunk separates one slice to some sized slice. -func SliceChunk(slice []interface{}, size int) (chunkslice [][]interface{}) { - if size >= len(slice) { - chunkslice = append(chunkslice, slice) - return - } - end := size - for i := 0; i <= (len(slice) - size); i += size { - chunkslice = append(chunkslice, slice[i:end]) - end += size - } - return -} - -// SliceRange generates a new slice from begin to end with step duration of int64 number. -func SliceRange(start, end, step int64) (intslice []int64) { - for i := start; i <= end; i += step { - intslice = append(intslice, i) - } - return -} - -// SlicePad prepends size number of val into slice. -func SlicePad(slice []interface{}, size int, val interface{}) []interface{} { - if size <= len(slice) { - return slice - } - for i := 0; i < (size - len(slice)); i++ { - slice = append(slice, val) - } - return slice -} - -// SliceUnique cleans repeated values in slice. -func SliceUnique(slice []interface{}) (uniqueslice []interface{}) { - for _, v := range slice { - if !InSliceIface(v, uniqueslice) { - uniqueslice = append(uniqueslice, v) - } - } - return -} - -// SliceShuffle shuffles a slice. -func SliceShuffle(slice []interface{}) []interface{} { - for i := 0; i < len(slice); i++ { - a := rand.Intn(len(slice)) - b := rand.Intn(len(slice)) - slice[a], slice[b] = slice[b], slice[a] - } - return slice -} diff --git a/vender/github.com/astaxie/beego/utils/slice_test.go b/vender/github.com/astaxie/beego/utils/slice_test.go deleted file mode 100755 index 142dec9..0000000 --- a/vender/github.com/astaxie/beego/utils/slice_test.go +++ /dev/null @@ -1,29 +0,0 @@ -// 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 utils - -import ( - "testing" -) - -func TestInSlice(t *testing.T) { - sl := []string{"A", "b"} - if !InSlice("A", sl) { - t.Error("should be true") - } - if InSlice("B", sl) { - t.Error("should be false") - } -} diff --git a/vender/github.com/astaxie/beego/utils/testdata/grepe.test b/vender/github.com/astaxie/beego/utils/testdata/grepe.test deleted file mode 100755 index 6c014c4..0000000 --- a/vender/github.com/astaxie/beego/utils/testdata/grepe.test +++ /dev/null @@ -1,7 +0,0 @@ -# empty lines - - - -hello -# comment -world diff --git a/vender/github.com/astaxie/beego/utils/utils.go b/vender/github.com/astaxie/beego/utils/utils.go deleted file mode 100755 index ed88578..0000000 --- a/vender/github.com/astaxie/beego/utils/utils.go +++ /dev/null @@ -1,30 +0,0 @@ -package utils - -import ( - "os" - "path/filepath" - "runtime" - "strings" -) - -// GetGOPATHs returns all paths in GOPATH variable. -func GetGOPATHs() []string { - gopath := os.Getenv("GOPATH") - if gopath == "" && strings.Compare(runtime.Version(), "go1.8") >= 0 { - gopath = defaultGOPATH() - } - return filepath.SplitList(gopath) -} - -func defaultGOPATH() string { - env := "HOME" - if runtime.GOOS == "windows" { - env = "USERPROFILE" - } else if runtime.GOOS == "plan9" { - env = "home" - } - if home := os.Getenv(env); home != "" { - return filepath.Join(home, "go") - } - return "" -} diff --git a/vender/github.com/astaxie/beego/validation/README.md b/vender/github.com/astaxie/beego/validation/README.md deleted file mode 100755 index f8ccf93..0000000 --- a/vender/github.com/astaxie/beego/validation/README.md +++ /dev/null @@ -1,147 +0,0 @@ -validation -============== - -validation is a form validation for a data validation and error collecting using Go. - -## Installation and tests - -Install: - - go get github.com/cnlh/nps/vender/github.com/astaxie/beego/validation - -Test: - - go test github.com/cnlh/nps/vender/github.com/astaxie/beego/validation - -## Example - -Direct Use: - - import ( - "github.com/cnlh/nps/vender/github.com/astaxie/beego/validation" - "log" - ) - - type User struct { - Name string - Age int - } - - func main() { - u := User{"man", 40} - valid := validation.Validation{} - valid.Required(u.Name, "name") - valid.MaxSize(u.Name, 15, "nameMax") - valid.Range(u.Age, 0, 140, "age") - if valid.HasErrors() { - // validation does not pass - // print invalid message - for _, err := range valid.Errors { - log.Println(err.Key, err.Message) - } - } - // or use like this - if v := valid.Max(u.Age, 140, "ageMax"); !v.Ok { - log.Println(v.Error.Key, v.Error.Message) - } - } - -Struct Tag Use: - - import ( - "github.com/cnlh/nps/vender/github.com/astaxie/beego/validation" - ) - - // validation function follow with "valid" tag - // functions divide with ";" - // parameters in parentheses "()" and divide with "," - // Match function's pattern string must in "//" - type user struct { - Id int - Name string `valid:"Required;Match(/^(test)?\\w*@;com$/)"` - Age int `valid:"Required;Range(1, 140)"` - } - - func main() { - valid := validation.Validation{} - // ignore empty field valid - // see CanSkipFuncs - // valid := validation.Validation{RequiredFirst:true} - u := user{Name: "test", Age: 40} - b, err := valid.Valid(u) - if err != nil { - // handle error - } - if !b { - // validation does not pass - // blabla... - } - } - -Use custom function: - - import ( - "github.com/cnlh/nps/vender/github.com/astaxie/beego/validation" - ) - - type user struct { - Id int - Name string `valid:"Required;IsMe"` - Age int `valid:"Required;Range(1, 140)"` - } - - func IsMe(v *validation.Validation, obj interface{}, key string) { - name, ok:= obj.(string) - if !ok { - // wrong use case? - return - } - - if name != "me" { - // valid false - v.SetError("Name", "is not me!") - } - } - - func main() { - valid := validation.Validation{} - if err := validation.AddCustomFunc("IsMe", IsMe); err != nil { - // hadle error - } - u := user{Name: "test", Age: 40} - b, err := valid.Valid(u) - if err != nil { - // handle error - } - if !b { - // validation does not pass - // blabla... - } - } - -Struct Tag Functions: - - Required - Min(min int) - Max(max int) - Range(min, max int) - MinSize(min int) - MaxSize(max int) - Length(length int) - Alpha - Numeric - AlphaNumeric - Match(pattern string) - AlphaDash - Email - IP - Base64 - Mobile - Tel - Phone - ZipCode - - -## LICENSE - -BSD License http://creativecommons.org/licenses/BSD/ diff --git a/vender/github.com/astaxie/beego/validation/util.go b/vender/github.com/astaxie/beego/validation/util.go deleted file mode 100755 index 66fce28..0000000 --- a/vender/github.com/astaxie/beego/validation/util.go +++ /dev/null @@ -1,295 +0,0 @@ -// 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 validation - -import ( - "fmt" - "reflect" - "regexp" - "strconv" - "strings" -) - -const ( - // ValidTag struct tag - ValidTag = "valid" - - wordsize = 32 << (^uint(0) >> 32 & 1) -) - -var ( - // key: function name - // value: the number of parameters - funcs = make(Funcs) - - // doesn't belong to validation functions - unFuncs = map[string]bool{ - "Clear": true, - "HasErrors": true, - "ErrorMap": true, - "Error": true, - "apply": true, - "Check": true, - "Valid": true, - "NoMatch": true, - } - // ErrInt64On32 show 32 bit platform not support int64 - ErrInt64On32 = fmt.Errorf("not support int64 on 32-bit platform") -) - -func init() { - v := &Validation{} - t := reflect.TypeOf(v) - for i := 0; i < t.NumMethod(); i++ { - m := t.Method(i) - if !unFuncs[m.Name] { - funcs[m.Name] = m.Func - } - } -} - -// CustomFunc is for custom validate function -type CustomFunc func(v *Validation, obj interface{}, key string) - -// AddCustomFunc Add a custom function to validation -// The name can not be: -// Clear -// HasErrors -// ErrorMap -// Error -// Check -// Valid -// NoMatch -// If the name is same with exists function, it will replace the origin valid function -func AddCustomFunc(name string, f CustomFunc) error { - if unFuncs[name] { - return fmt.Errorf("invalid function name: %s", name) - } - - funcs[name] = reflect.ValueOf(f) - return nil -} - -// ValidFunc Valid function type -type ValidFunc struct { - Name string - Params []interface{} -} - -// Funcs Validate function map -type Funcs map[string]reflect.Value - -// Call validate values with named type string -func (f Funcs) Call(name string, params ...interface{}) (result []reflect.Value, err error) { - defer func() { - if r := recover(); r != nil { - err = fmt.Errorf("%v", r) - } - }() - if _, ok := f[name]; !ok { - err = fmt.Errorf("%s does not exist", name) - return - } - if len(params) != f[name].Type().NumIn() { - err = fmt.Errorf("The number of params is not adapted") - return - } - in := make([]reflect.Value, len(params)) - for k, param := range params { - in[k] = reflect.ValueOf(param) - } - result = f[name].Call(in) - return -} - -func isStruct(t reflect.Type) bool { - return t.Kind() == reflect.Struct -} - -func isStructPtr(t reflect.Type) bool { - return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct -} - -func getValidFuncs(f reflect.StructField) (vfs []ValidFunc, err error) { - tag := f.Tag.Get(ValidTag) - if len(tag) == 0 { - return - } - if vfs, tag, err = getRegFuncs(tag, f.Name); err != nil { - return - } - fs := strings.Split(tag, ";") - for _, vfunc := range fs { - var vf ValidFunc - if len(vfunc) == 0 { - continue - } - vf, err = parseFunc(vfunc, f.Name) - if err != nil { - return - } - vfs = append(vfs, vf) - } - return -} - -// Get Match function -// May be get NoMatch function in the future -func getRegFuncs(tag, key string) (vfs []ValidFunc, str string, err error) { - tag = strings.TrimSpace(tag) - index := strings.Index(tag, "Match(/") - if index == -1 { - str = tag - return - } - end := strings.LastIndex(tag, "/)") - if end < index { - err = fmt.Errorf("invalid Match function") - return - } - reg, err := regexp.Compile(tag[index+len("Match(/") : end]) - if err != nil { - return - } - vfs = []ValidFunc{{"Match", []interface{}{reg, key + ".Match"}}} - str = strings.TrimSpace(tag[:index]) + strings.TrimSpace(tag[end+len("/)"):]) - return -} - -func parseFunc(vfunc, key string) (v ValidFunc, err error) { - defer func() { - if r := recover(); r != nil { - err = fmt.Errorf("%v", r) - } - }() - - vfunc = strings.TrimSpace(vfunc) - start := strings.Index(vfunc, "(") - var num int - - // doesn't need parameter valid function - if start == -1 { - if num, err = numIn(vfunc); err != nil { - return - } - if num != 0 { - err = fmt.Errorf("%s require %d parameters", vfunc, num) - return - } - v = ValidFunc{vfunc, []interface{}{key + "." + vfunc}} - return - } - - end := strings.Index(vfunc, ")") - if end == -1 { - err = fmt.Errorf("invalid valid function") - return - } - - name := strings.TrimSpace(vfunc[:start]) - if num, err = numIn(name); err != nil { - return - } - - params := strings.Split(vfunc[start+1:end], ",") - // the num of param must be equal - if num != len(params) { - err = fmt.Errorf("%s require %d parameters", name, num) - return - } - - tParams, err := trim(name, key+"."+name, params) - if err != nil { - return - } - v = ValidFunc{name, tParams} - return -} - -func numIn(name string) (num int, err error) { - fn, ok := funcs[name] - if !ok { - err = fmt.Errorf("doesn't exsits %s valid function", name) - return - } - // sub *Validation obj and key - num = fn.Type().NumIn() - 3 - return -} - -func trim(name, key string, s []string) (ts []interface{}, err error) { - ts = make([]interface{}, len(s), len(s)+1) - fn, ok := funcs[name] - if !ok { - err = fmt.Errorf("doesn't exsits %s valid function", name) - return - } - for i := 0; i < len(s); i++ { - var param interface{} - // skip *Validation and obj params - if param, err = parseParam(fn.Type().In(i+2), strings.TrimSpace(s[i])); err != nil { - return - } - ts[i] = param - } - ts = append(ts, key) - return -} - -// modify the parameters's type to adapt the function input parameters' type -func parseParam(t reflect.Type, s string) (i interface{}, err error) { - switch t.Kind() { - case reflect.Int: - i, err = strconv.Atoi(s) - case reflect.Int64: - if wordsize == 32 { - return nil, ErrInt64On32 - } - i, err = strconv.ParseInt(s, 10, 64) - case reflect.Int32: - var v int64 - v, err = strconv.ParseInt(s, 10, 32) - if err == nil { - i = int32(v) - } - case reflect.Int16: - var v int64 - v, err = strconv.ParseInt(s, 10, 16) - if err == nil { - i = int16(v) - } - case reflect.Int8: - var v int64 - v, err = strconv.ParseInt(s, 10, 8) - if err == nil { - i = int8(v) - } - case reflect.String: - i = s - case reflect.Ptr: - if t.Elem().String() != "regexp.Regexp" { - err = fmt.Errorf("not support %s", t.Elem().String()) - return - } - i, err = regexp.Compile(s) - default: - err = fmt.Errorf("not support %s", t.Kind().String()) - } - return -} - -func mergeParam(v *Validation, obj interface{}, params []interface{}) []interface{} { - return append([]interface{}{v, obj}, params...) -} diff --git a/vender/github.com/astaxie/beego/validation/util_test.go b/vender/github.com/astaxie/beego/validation/util_test.go deleted file mode 100755 index e74d50e..0000000 --- a/vender/github.com/astaxie/beego/validation/util_test.go +++ /dev/null @@ -1,100 +0,0 @@ -// 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 validation - -import ( - "reflect" - "testing" -) - -type user struct { - ID int - Tag string `valid:"Maxx(aa)"` - Name string `valid:"Required;"` - Age int `valid:"Required;Range(1, 140)"` - match string `valid:"Required; Match(/^(test)?\\w*@(/test/);com$/);Max(2)"` -} - -func TestGetValidFuncs(t *testing.T) { - u := user{Name: "test", Age: 1} - tf := reflect.TypeOf(u) - var vfs []ValidFunc - var err error - - f, _ := tf.FieldByName("ID") - if vfs, err = getValidFuncs(f); err != nil { - t.Fatal(err) - } - if len(vfs) != 0 { - t.Fatal("should get none ValidFunc") - } - - f, _ = tf.FieldByName("Tag") - if _, err = getValidFuncs(f); err.Error() != "doesn't exsits Maxx valid function" { - t.Fatal(err) - } - - f, _ = tf.FieldByName("Name") - if vfs, err = getValidFuncs(f); err != nil { - t.Fatal(err) - } - if len(vfs) != 1 { - t.Fatal("should get 1 ValidFunc") - } - if vfs[0].Name != "Required" && len(vfs[0].Params) != 0 { - t.Error("Required funcs should be got") - } - - f, _ = tf.FieldByName("Age") - if vfs, err = getValidFuncs(f); err != nil { - t.Fatal(err) - } - if len(vfs) != 2 { - t.Fatal("should get 2 ValidFunc") - } - if vfs[0].Name != "Required" && len(vfs[0].Params) != 0 { - t.Error("Required funcs should be got") - } - if vfs[1].Name != "Range" && len(vfs[1].Params) != 2 { - t.Error("Range funcs should be got") - } - - f, _ = tf.FieldByName("match") - if vfs, err = getValidFuncs(f); err != nil { - t.Fatal(err) - } - if len(vfs) != 3 { - t.Fatal("should get 3 ValidFunc but now is", len(vfs)) - } -} - -func TestCall(t *testing.T) { - u := user{Name: "test", Age: 180} - tf := reflect.TypeOf(u) - var vfs []ValidFunc - var err error - f, _ := tf.FieldByName("Age") - if vfs, err = getValidFuncs(f); err != nil { - t.Fatal(err) - } - valid := &Validation{} - vfs[1].Params = append([]interface{}{valid, u.Age}, vfs[1].Params...) - if _, err = funcs.Call(vfs[1].Name, vfs[1].Params...); err != nil { - t.Fatal(err) - } - if len(valid.Errors) != 1 { - t.Error("age out of range should be has an error") - } -} diff --git a/vender/github.com/astaxie/beego/validation/validation.go b/vender/github.com/astaxie/beego/validation/validation.go deleted file mode 100755 index 66366fa..0000000 --- a/vender/github.com/astaxie/beego/validation/validation.go +++ /dev/null @@ -1,446 +0,0 @@ -// 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 validation for validations -// -// import ( -// "github.com/cnlh/nps/vender/github.com/astaxie/beego/validation" -// "log" -// ) -// -// type User struct { -// Name string -// Age int -// } -// -// func main() { -// u := User{"man", 40} -// valid := validation.Validation{} -// valid.Required(u.Name, "name") -// valid.MaxSize(u.Name, 15, "nameMax") -// valid.Range(u.Age, 0, 140, "age") -// if valid.HasErrors() { -// // validation does not pass -// // print invalid message -// for _, err := range valid.Errors { -// log.Println(err.Key, err.Message) -// } -// } -// // or use like this -// if v := valid.Max(u.Age, 140, "ageMax"); !v.Ok { -// log.Println(v.Error.Key, v.Error.Message) -// } -// } -// -// more info: http://beego.me/docs/mvc/controller/validation.md -package validation - -import ( - "fmt" - "reflect" - "regexp" - "strings" -) - -// ValidFormer valid interface -type ValidFormer interface { - Valid(*Validation) -} - -// Error show the error -type Error struct { - Message, Key, Name, Field, Tmpl string - Value interface{} - LimitValue interface{} -} - -// String Returns the Message. -func (e *Error) String() string { - if e == nil { - return "" - } - return e.Message -} - -// Implement Error interface. -// Return e.String() -func (e *Error) Error() string { return e.String() } - -// Result is returned from every validation method. -// It provides an indication of success, and a pointer to the Error (if any). -type Result struct { - Error *Error - Ok bool -} - -// Key Get Result by given key string. -func (r *Result) Key(key string) *Result { - if r.Error != nil { - r.Error.Key = key - } - return r -} - -// Message Set Result message by string or format string with args -func (r *Result) Message(message string, args ...interface{}) *Result { - if r.Error != nil { - if len(args) == 0 { - r.Error.Message = message - } else { - r.Error.Message = fmt.Sprintf(message, args...) - } - } - return r -} - -// A Validation context manages data validation and error messages. -type Validation struct { - // if this field set true, in struct tag valid - // if the struct field vale is empty - // it will skip those valid functions, see CanSkipFuncs - RequiredFirst bool - - Errors []*Error - ErrorsMap map[string][]*Error -} - -// Clear Clean all ValidationError. -func (v *Validation) Clear() { - v.Errors = []*Error{} - v.ErrorsMap = nil -} - -// HasErrors Has ValidationError nor not. -func (v *Validation) HasErrors() bool { - return len(v.Errors) > 0 -} - -// ErrorMap Return the errors mapped by key. -// If there are multiple validation errors associated with a single key, the -// first one "wins". (Typically the first validation will be the more basic). -func (v *Validation) ErrorMap() map[string][]*Error { - return v.ErrorsMap -} - -// Error Add an error to the validation context. -func (v *Validation) Error(message string, args ...interface{}) *Result { - result := (&Result{ - Ok: false, - Error: &Error{}, - }).Message(message, args...) - v.Errors = append(v.Errors, result.Error) - return result -} - -// Required Test that the argument is non-nil and non-empty (if string or list) -func (v *Validation) Required(obj interface{}, key string) *Result { - return v.apply(Required{key}, obj) -} - -// Min Test that the obj is greater than min if obj's type is int -func (v *Validation) Min(obj interface{}, min int, key string) *Result { - return v.apply(Min{min, key}, obj) -} - -// Max Test that the obj is less than max if obj's type is int -func (v *Validation) Max(obj interface{}, max int, key string) *Result { - return v.apply(Max{max, key}, obj) -} - -// Range Test that the obj is between mni and max if obj's type is int -func (v *Validation) Range(obj interface{}, min, max int, key string) *Result { - return v.apply(Range{Min{Min: min}, Max{Max: max}, key}, obj) -} - -// MinSize Test that the obj is longer than min size if type is string or slice -func (v *Validation) MinSize(obj interface{}, min int, key string) *Result { - return v.apply(MinSize{min, key}, obj) -} - -// MaxSize Test that the obj is shorter than max size if type is string or slice -func (v *Validation) MaxSize(obj interface{}, max int, key string) *Result { - return v.apply(MaxSize{max, key}, obj) -} - -// Length Test that the obj is same length to n if type is string or slice -func (v *Validation) Length(obj interface{}, n int, key string) *Result { - return v.apply(Length{n, key}, obj) -} - -// Alpha Test that the obj is [a-zA-Z] if type is string -func (v *Validation) Alpha(obj interface{}, key string) *Result { - return v.apply(Alpha{key}, obj) -} - -// Numeric Test that the obj is [0-9] if type is string -func (v *Validation) Numeric(obj interface{}, key string) *Result { - return v.apply(Numeric{key}, obj) -} - -// AlphaNumeric Test that the obj is [0-9a-zA-Z] if type is string -func (v *Validation) AlphaNumeric(obj interface{}, key string) *Result { - return v.apply(AlphaNumeric{key}, obj) -} - -// Match Test that the obj matches regexp if type is string -func (v *Validation) Match(obj interface{}, regex *regexp.Regexp, key string) *Result { - return v.apply(Match{regex, key}, obj) -} - -// NoMatch Test that the obj doesn't match regexp if type is string -func (v *Validation) NoMatch(obj interface{}, regex *regexp.Regexp, key string) *Result { - return v.apply(NoMatch{Match{Regexp: regex}, key}, obj) -} - -// AlphaDash Test that the obj is [0-9a-zA-Z_-] if type is string -func (v *Validation) AlphaDash(obj interface{}, key string) *Result { - return v.apply(AlphaDash{NoMatch{Match: Match{Regexp: alphaDashPattern}}, key}, obj) -} - -// Email Test that the obj is email address if type is string -func (v *Validation) Email(obj interface{}, key string) *Result { - return v.apply(Email{Match{Regexp: emailPattern}, key}, obj) -} - -// IP Test that the obj is IP address if type is string -func (v *Validation) IP(obj interface{}, key string) *Result { - return v.apply(IP{Match{Regexp: ipPattern}, key}, obj) -} - -// Base64 Test that the obj is base64 encoded if type is string -func (v *Validation) Base64(obj interface{}, key string) *Result { - return v.apply(Base64{Match{Regexp: base64Pattern}, key}, obj) -} - -// Mobile Test that the obj is chinese mobile number if type is string -func (v *Validation) Mobile(obj interface{}, key string) *Result { - return v.apply(Mobile{Match{Regexp: mobilePattern}, key}, obj) -} - -// Tel Test that the obj is chinese telephone number if type is string -func (v *Validation) Tel(obj interface{}, key string) *Result { - return v.apply(Tel{Match{Regexp: telPattern}, key}, obj) -} - -// Phone Test that the obj is chinese mobile or telephone number if type is string -func (v *Validation) Phone(obj interface{}, key string) *Result { - return v.apply(Phone{Mobile{Match: Match{Regexp: mobilePattern}}, - Tel{Match: Match{Regexp: telPattern}}, key}, obj) -} - -// ZipCode Test that the obj is chinese zip code if type is string -func (v *Validation) ZipCode(obj interface{}, key string) *Result { - return v.apply(ZipCode{Match{Regexp: zipCodePattern}, key}, obj) -} - -func (v *Validation) apply(chk Validator, obj interface{}) *Result { - if nil == obj { - if chk.IsSatisfied(obj) { - return &Result{Ok: true} - } - } else if reflect.TypeOf(obj).Kind() == reflect.Ptr { - if reflect.ValueOf(obj).IsNil() { - if chk.IsSatisfied(nil) { - return &Result{Ok: true} - } - } else { - if chk.IsSatisfied(reflect.ValueOf(obj).Elem().Interface()) { - return &Result{Ok: true} - } - } - } else if chk.IsSatisfied(obj) { - return &Result{Ok: true} - } - - // Add the error to the validation context. - key := chk.GetKey() - Name := key - Field := "" - - parts := strings.Split(key, ".") - if len(parts) == 2 { - Field = parts[0] - Name = parts[1] - } - - err := &Error{ - Message: chk.DefaultMessage(), - Key: key, - Name: Name, - Field: Field, - Value: obj, - Tmpl: MessageTmpls[Name], - LimitValue: chk.GetLimitValue(), - } - v.setError(err) - - // Also return it in the result. - return &Result{ - Ok: false, - Error: err, - } -} - -// AddError adds independent error message for the provided key -func (v *Validation) AddError(key, message string) { - Name := key - Field := "" - - parts := strings.Split(key, ".") - if len(parts) == 2 { - Field = parts[0] - Name = parts[1] - } - - err := &Error{ - Message: message, - Key: key, - Name: Name, - Field: Field, - } - v.setError(err) -} - -func (v *Validation) setError(err *Error) { - v.Errors = append(v.Errors, err) - if v.ErrorsMap == nil { - v.ErrorsMap = make(map[string][]*Error) - } - if _, ok := v.ErrorsMap[err.Field]; !ok { - v.ErrorsMap[err.Field] = []*Error{} - } - v.ErrorsMap[err.Field] = append(v.ErrorsMap[err.Field], err) -} - -// SetError Set error message for one field in ValidationError -func (v *Validation) SetError(fieldName string, errMsg string) *Error { - err := &Error{Key: fieldName, Field: fieldName, Tmpl: errMsg, Message: errMsg} - v.setError(err) - return err -} - -// Check Apply a group of validators to a field, in order, and return the -// ValidationResult from the first one that fails, or the last one that -// succeeds. -func (v *Validation) Check(obj interface{}, checks ...Validator) *Result { - var result *Result - for _, check := range checks { - result = v.apply(check, obj) - if !result.Ok { - return result - } - } - return result -} - -// Valid Validate a struct. -// the obj parameter must be a struct or a struct pointer -func (v *Validation) Valid(obj interface{}) (b bool, err error) { - objT := reflect.TypeOf(obj) - objV := reflect.ValueOf(obj) - switch { - case isStruct(objT): - case isStructPtr(objT): - objT = objT.Elem() - objV = objV.Elem() - default: - err = fmt.Errorf("%v must be a struct or a struct pointer", obj) - return - } - - for i := 0; i < objT.NumField(); i++ { - var vfs []ValidFunc - if vfs, err = getValidFuncs(objT.Field(i)); err != nil { - return - } - - var hasRequired bool - for _, vf := range vfs { - if vf.Name == "Required" { - hasRequired = true - } - - currentField := objV.Field(i).Interface() - if objV.Field(i).Kind() == reflect.Ptr { - if objV.Field(i).IsNil() { - currentField = "" - } else { - currentField = objV.Field(i).Elem().Interface() - } - } - - chk := Required{""}.IsSatisfied(currentField) - if !hasRequired && v.RequiredFirst && !chk { - if _, ok := CanSkipFuncs[vf.Name]; ok { - continue - } - } - - if _, err = funcs.Call(vf.Name, - mergeParam(v, objV.Field(i).Interface(), vf.Params)...); err != nil { - return - } - } - } - - if !v.HasErrors() { - if form, ok := obj.(ValidFormer); ok { - form.Valid(v) - } - } - - return !v.HasErrors(), nil -} - -// RecursiveValid Recursively validate a struct. -// Step1: Validate by v.Valid -// Step2: If pass on step1, then reflect obj's fields -// Step3: Do the Recursively validation to all struct or struct pointer fields -func (v *Validation) RecursiveValid(objc interface{}) (bool, error) { - //Step 1: validate obj itself firstly - // fails if objc is not struct - pass, err := v.Valid(objc) - if err != nil || !pass { - return pass, err // Stop recursive validation - } - // Step 2: Validate struct's struct fields - objT := reflect.TypeOf(objc) - objV := reflect.ValueOf(objc) - - if isStructPtr(objT) { - objT = objT.Elem() - objV = objV.Elem() - } - - for i := 0; i < objT.NumField(); i++ { - - t := objT.Field(i).Type - - // Recursive applies to struct or pointer to structs fields - if isStruct(t) || isStructPtr(t) { - // Step 3: do the recursive validation - // Only valid the Public field recursively - if objV.Field(i).CanInterface() { - pass, err = v.RecursiveValid(objV.Field(i).Interface()) - } - } - } - return pass, err -} - -func (v *Validation) CanSkipAlso(skipFunc string) { - if _, ok := CanSkipFuncs[skipFunc]; !ok { - CanSkipFuncs[skipFunc] = struct{}{} - } -} diff --git a/vender/github.com/astaxie/beego/validation/validation_test.go b/vender/github.com/astaxie/beego/validation/validation_test.go deleted file mode 100755 index f97105f..0000000 --- a/vender/github.com/astaxie/beego/validation/validation_test.go +++ /dev/null @@ -1,563 +0,0 @@ -// 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 validation - -import ( - "regexp" - "testing" - "time" -) - -func TestRequired(t *testing.T) { - valid := Validation{} - - if valid.Required(nil, "nil").Ok { - t.Error("nil object should be false") - } - if !valid.Required(true, "bool").Ok { - t.Error("Bool value should always return true") - } - if !valid.Required(false, "bool").Ok { - t.Error("Bool value should always return true") - } - if valid.Required("", "string").Ok { - t.Error("\"'\" string should be false") - } - if valid.Required(" ", "string").Ok { - t.Error("\" \" string should be false") // For #2361 - } - if valid.Required("\n", "string").Ok { - t.Error("new line string should be false") // For #2361 - } - if !valid.Required("astaxie", "string").Ok { - t.Error("string should be true") - } - if valid.Required(0, "zero").Ok { - t.Error("Integer should not be equal 0") - } - if !valid.Required(1, "int").Ok { - t.Error("Integer except 0 should be true") - } - if !valid.Required(time.Now(), "time").Ok { - t.Error("time should be true") - } - if valid.Required([]string{}, "emptySlice").Ok { - t.Error("empty slice should be false") - } - if !valid.Required([]interface{}{"ok"}, "slice").Ok { - t.Error("slice should be true") - } -} - -func TestMin(t *testing.T) { - valid := Validation{} - - if valid.Min(-1, 0, "min0").Ok { - t.Error("-1 is less than the minimum value of 0 should be false") - } - if !valid.Min(1, 0, "min0").Ok { - t.Error("1 is greater or equal than the minimum value of 0 should be true") - } -} - -func TestMax(t *testing.T) { - valid := Validation{} - - if valid.Max(1, 0, "max0").Ok { - t.Error("1 is greater than the minimum value of 0 should be false") - } - if !valid.Max(-1, 0, "max0").Ok { - t.Error("-1 is less or equal than the maximum value of 0 should be true") - } -} - -func TestRange(t *testing.T) { - valid := Validation{} - - if valid.Range(-1, 0, 1, "range0_1").Ok { - t.Error("-1 is between 0 and 1 should be false") - } - if !valid.Range(1, 0, 1, "range0_1").Ok { - t.Error("1 is between 0 and 1 should be true") - } -} - -func TestMinSize(t *testing.T) { - valid := Validation{} - - if valid.MinSize("", 1, "minSize1").Ok { - t.Error("the length of \"\" is less than the minimum value of 1 should be false") - } - if !valid.MinSize("ok", 1, "minSize1").Ok { - t.Error("the length of \"ok\" is greater or equal than the minimum value of 1 should be true") - } - if valid.MinSize([]string{}, 1, "minSize1").Ok { - t.Error("the length of empty slice is less than the minimum value of 1 should be false") - } - if !valid.MinSize([]interface{}{"ok"}, 1, "minSize1").Ok { - t.Error("the length of [\"ok\"] is greater or equal than the minimum value of 1 should be true") - } -} - -func TestMaxSize(t *testing.T) { - valid := Validation{} - - if valid.MaxSize("ok", 1, "maxSize1").Ok { - t.Error("the length of \"ok\" is greater than the maximum value of 1 should be false") - } - if !valid.MaxSize("", 1, "maxSize1").Ok { - t.Error("the length of \"\" is less or equal than the maximum value of 1 should be true") - } - if valid.MaxSize([]interface{}{"ok", false}, 1, "maxSize1").Ok { - t.Error("the length of [\"ok\", false] is greater than the maximum value of 1 should be false") - } - if !valid.MaxSize([]string{}, 1, "maxSize1").Ok { - t.Error("the length of empty slice is less or equal than the maximum value of 1 should be true") - } -} - -func TestLength(t *testing.T) { - valid := Validation{} - - if valid.Length("", 1, "length1").Ok { - t.Error("the length of \"\" must equal 1 should be false") - } - if !valid.Length("1", 1, "length1").Ok { - t.Error("the length of \"1\" must equal 1 should be true") - } - if valid.Length([]string{}, 1, "length1").Ok { - t.Error("the length of empty slice must equal 1 should be false") - } - if !valid.Length([]interface{}{"ok"}, 1, "length1").Ok { - t.Error("the length of [\"ok\"] must equal 1 should be true") - } -} - -func TestAlpha(t *testing.T) { - valid := Validation{} - - if valid.Alpha("a,1-@ $", "alpha").Ok { - t.Error("\"a,1-@ $\" are valid alpha characters should be false") - } - if !valid.Alpha("abCD", "alpha").Ok { - t.Error("\"abCD\" are valid alpha characters should be true") - } -} - -func TestNumeric(t *testing.T) { - valid := Validation{} - - if valid.Numeric("a,1-@ $", "numeric").Ok { - t.Error("\"a,1-@ $\" are valid numeric characters should be false") - } - if !valid.Numeric("1234", "numeric").Ok { - t.Error("\"1234\" are valid numeric characters should be true") - } -} - -func TestAlphaNumeric(t *testing.T) { - valid := Validation{} - - if valid.AlphaNumeric("a,1-@ $", "alphaNumeric").Ok { - t.Error("\"a,1-@ $\" are valid alpha or numeric characters should be false") - } - if !valid.AlphaNumeric("1234aB", "alphaNumeric").Ok { - t.Error("\"1234aB\" are valid alpha or numeric characters should be true") - } -} - -func TestMatch(t *testing.T) { - valid := Validation{} - - if valid.Match("suchuangji@gmail", regexp.MustCompile(`^\w+@\w+\.\w+$`), "match").Ok { - t.Error("\"suchuangji@gmail\" match \"^\\w+@\\w+\\.\\w+$\" should be false") - } - if !valid.Match("suchuangji@gmail.com", regexp.MustCompile(`^\w+@\w+\.\w+$`), "match").Ok { - t.Error("\"suchuangji@gmail\" match \"^\\w+@\\w+\\.\\w+$\" should be true") - } -} - -func TestNoMatch(t *testing.T) { - valid := Validation{} - - if valid.NoMatch("123@gmail", regexp.MustCompile(`[^\w\d]`), "nomatch").Ok { - t.Error("\"123@gmail\" not match \"[^\\w\\d]\" should be false") - } - if !valid.NoMatch("123gmail", regexp.MustCompile(`[^\w\d]`), "match").Ok { - t.Error("\"123@gmail\" not match \"[^\\w\\d@]\" should be true") - } -} - -func TestAlphaDash(t *testing.T) { - valid := Validation{} - - if valid.AlphaDash("a,1-@ $", "alphaDash").Ok { - t.Error("\"a,1-@ $\" are valid alpha or numeric or dash(-_) characters should be false") - } - if !valid.AlphaDash("1234aB-_", "alphaDash").Ok { - t.Error("\"1234aB\" are valid alpha or numeric or dash(-_) characters should be true") - } -} - -func TestEmail(t *testing.T) { - valid := Validation{} - - if valid.Email("not@a email", "email").Ok { - t.Error("\"not@a email\" is a valid email address should be false") - } - if !valid.Email("suchuangji@gmail.com", "email").Ok { - t.Error("\"suchuangji@gmail.com\" is a valid email address should be true") - } - if valid.Email("@suchuangji@gmail.com", "email").Ok { - t.Error("\"@suchuangji@gmail.com\" is a valid email address should be false") - } - if valid.Email("suchuangji@gmail.com ok", "email").Ok { - t.Error("\"suchuangji@gmail.com ok\" is a valid email address should be false") - } -} - -func TestIP(t *testing.T) { - valid := Validation{} - - if valid.IP("11.255.255.256", "IP").Ok { - t.Error("\"11.255.255.256\" is a valid ip address should be false") - } - if !valid.IP("01.11.11.11", "IP").Ok { - t.Error("\"suchuangji@gmail.com\" is a valid ip address should be true") - } -} - -func TestBase64(t *testing.T) { - valid := Validation{} - - if valid.Base64("suchuangji@gmail.com", "base64").Ok { - t.Error("\"suchuangji@gmail.com\" are a valid base64 characters should be false") - } - if !valid.Base64("c3VjaHVhbmdqaUBnbWFpbC5jb20=", "base64").Ok { - t.Error("\"c3VjaHVhbmdqaUBnbWFpbC5jb20=\" are a valid base64 characters should be true") - } -} - -func TestMobile(t *testing.T) { - valid := Validation{} - - if valid.Mobile("19800008888", "mobile").Ok { - t.Error("\"19800008888\" is a valid mobile phone number should be false") - } - if !valid.Mobile("18800008888", "mobile").Ok { - t.Error("\"18800008888\" is a valid mobile phone number should be true") - } - if !valid.Mobile("18000008888", "mobile").Ok { - t.Error("\"18000008888\" is a valid mobile phone number should be true") - } - if !valid.Mobile("8618300008888", "mobile").Ok { - t.Error("\"8618300008888\" is a valid mobile phone number should be true") - } - if !valid.Mobile("+8614700008888", "mobile").Ok { - t.Error("\"+8614700008888\" is a valid mobile phone number should be true") - } -} - -func TestTel(t *testing.T) { - valid := Validation{} - - if valid.Tel("222-00008888", "telephone").Ok { - t.Error("\"222-00008888\" is a valid telephone number should be false") - } - if !valid.Tel("022-70008888", "telephone").Ok { - t.Error("\"022-70008888\" is a valid telephone number should be true") - } - if !valid.Tel("02270008888", "telephone").Ok { - t.Error("\"02270008888\" is a valid telephone number should be true") - } - if !valid.Tel("70008888", "telephone").Ok { - t.Error("\"70008888\" is a valid telephone number should be true") - } -} - -func TestPhone(t *testing.T) { - valid := Validation{} - - if valid.Phone("222-00008888", "phone").Ok { - t.Error("\"222-00008888\" is a valid phone number should be false") - } - if !valid.Mobile("+8614700008888", "phone").Ok { - t.Error("\"+8614700008888\" is a valid phone number should be true") - } - if !valid.Tel("02270008888", "phone").Ok { - t.Error("\"02270008888\" is a valid phone number should be true") - } -} - -func TestZipCode(t *testing.T) { - valid := Validation{} - - if valid.ZipCode("", "zipcode").Ok { - t.Error("\"00008888\" is a valid zipcode should be false") - } - if !valid.ZipCode("536000", "zipcode").Ok { - t.Error("\"536000\" is a valid zipcode should be true") - } -} - -func TestValid(t *testing.T) { - type user struct { - ID int - Name string `valid:"Required;Match(/^(test)?\\w*@(/test/);com$/)"` - Age int `valid:"Required;Range(1, 140)"` - } - valid := Validation{} - - u := user{Name: "test@/test/;com", Age: 40} - b, err := valid.Valid(u) - if err != nil { - t.Fatal(err) - } - if !b { - t.Error("validation should be passed") - } - - uptr := &user{Name: "test", Age: 40} - valid.Clear() - b, err = valid.Valid(uptr) - if err != nil { - t.Fatal(err) - } - if b { - t.Error("validation should not be passed") - } - if len(valid.Errors) != 1 { - t.Fatalf("valid errors len should be 1 but got %d", len(valid.Errors)) - } - if valid.Errors[0].Key != "Name.Match" { - t.Errorf("Message key should be `Name.Match` but got %s", valid.Errors[0].Key) - } - - u = user{Name: "test@/test/;com", Age: 180} - valid.Clear() - b, err = valid.Valid(u) - if err != nil { - t.Fatal(err) - } - if b { - t.Error("validation should not be passed") - } - if len(valid.Errors) != 1 { - t.Fatalf("valid errors len should be 1 but got %d", len(valid.Errors)) - } - if valid.Errors[0].Key != "Age.Range" { - t.Errorf("Message key should be `Name.Match` but got %s", valid.Errors[0].Key) - } -} - -func TestRecursiveValid(t *testing.T) { - type User struct { - ID int - Name string `valid:"Required;Match(/^(test)?\\w*@(/test/);com$/)"` - Age int `valid:"Required;Range(1, 140)"` - } - - type AnonymouseUser struct { - ID2 int - Name2 string `valid:"Required;Match(/^(test)?\\w*@(/test/);com$/)"` - Age2 int `valid:"Required;Range(1, 140)"` - } - - type Account struct { - Password string `valid:"Required"` - U User - AnonymouseUser - } - valid := Validation{} - - u := Account{Password: "abc123_", U: User{}} - b, err := valid.RecursiveValid(u) - if err != nil { - t.Fatal(err) - } - if b { - t.Error("validation should not be passed") - } -} - -func TestSkipValid(t *testing.T) { - type User struct { - ID int - - Email string `valid:"Email"` - ReqEmail string `valid:"Required;Email"` - - IP string `valid:"IP"` - ReqIP string `valid:"Required;IP"` - - Mobile string `valid:"Mobile"` - ReqMobile string `valid:"Required;Mobile"` - - Tel string `valid:"Tel"` - ReqTel string `valid:"Required;Tel"` - - Phone string `valid:"Phone"` - ReqPhone string `valid:"Required;Phone"` - - ZipCode string `valid:"ZipCode"` - ReqZipCode string `valid:"Required;ZipCode"` - } - - u := User{ - ReqEmail: "a@a.com", - ReqIP: "127.0.0.1", - ReqMobile: "18888888888", - ReqTel: "02088888888", - ReqPhone: "02088888888", - ReqZipCode: "510000", - } - - valid := Validation{} - b, err := valid.Valid(u) - if err != nil { - t.Fatal(err) - } - if b { - t.Fatal("validation should not be passed") - } - - valid = Validation{RequiredFirst: true} - b, err = valid.Valid(u) - if err != nil { - t.Fatal(err) - } - if !b { - t.Fatal("validation should be passed") - } -} - -func TestPointer(t *testing.T) { - type User struct { - ID int - - Email *string `valid:"Email"` - ReqEmail *string `valid:"Required;Email"` - } - - u := User{ - ReqEmail: nil, - Email: nil, - } - - valid := Validation{} - b, err := valid.Valid(u) - if err != nil { - t.Fatal(err) - } - if b { - t.Fatal("validation should not be passed") - } - - validEmail := "a@a.com" - u = User{ - ReqEmail: &validEmail, - Email: nil, - } - - valid = Validation{RequiredFirst: true} - b, err = valid.Valid(u) - if err != nil { - t.Fatal(err) - } - if !b { - t.Fatal("validation should be passed") - } - - u = User{ - ReqEmail: &validEmail, - Email: nil, - } - - valid = Validation{} - b, err = valid.Valid(u) - if err != nil { - t.Fatal(err) - } - if b { - t.Fatal("validation should not be passed") - } - - invalidEmail := "a@a" - u = User{ - ReqEmail: &validEmail, - Email: &invalidEmail, - } - - valid = Validation{RequiredFirst: true} - b, err = valid.Valid(u) - if err != nil { - t.Fatal(err) - } - if b { - t.Fatal("validation should not be passed") - } - - u = User{ - ReqEmail: &validEmail, - Email: &invalidEmail, - } - - valid = Validation{} - b, err = valid.Valid(u) - if err != nil { - t.Fatal(err) - } - if b { - t.Fatal("validation should not be passed") - } -} - - -func TestCanSkipAlso(t *testing.T) { - type User struct { - ID int - - Email string `valid:"Email"` - ReqEmail string `valid:"Required;Email"` - MatchRange int `valid:"Range(10, 20)"` - } - - u := User{ - ReqEmail: "a@a.com", - Email: "", - MatchRange: 0, - } - - valid := Validation{RequiredFirst: true} - b, err := valid.Valid(u) - if err != nil { - t.Fatal(err) - } - if b { - t.Fatal("validation should not be passed") - } - - valid = Validation{RequiredFirst: true} - valid.CanSkipAlso("Range") - b, err = valid.Valid(u) - if err != nil { - t.Fatal(err) - } - if !b { - t.Fatal("validation should be passed") - } - -} - diff --git a/vender/github.com/astaxie/beego/validation/validators.go b/vender/github.com/astaxie/beego/validation/validators.go deleted file mode 100755 index 4dff9c0..0000000 --- a/vender/github.com/astaxie/beego/validation/validators.go +++ /dev/null @@ -1,731 +0,0 @@ -// 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 validation - -import ( - "fmt" - "reflect" - "regexp" - "strings" - "time" - "unicode/utf8" -) - -// CanSkipFuncs will skip valid if RequiredFirst is true and the struct field's value is empty -var CanSkipFuncs = map[string]struct{}{ - "Email": {}, - "IP": {}, - "Mobile": {}, - "Tel": {}, - "Phone": {}, - "ZipCode": {}, -} - -// MessageTmpls store commond validate template -var MessageTmpls = map[string]string{ - "Required": "Can not be empty", - "Min": "Minimum is %d", - "Max": "Maximum is %d", - "Range": "Range is %d to %d", - "MinSize": "Minimum size is %d", - "MaxSize": "Maximum size is %d", - "Length": "Required length is %d", - "Alpha": "Must be valid alpha characters", - "Numeric": "Must be valid numeric characters", - "AlphaNumeric": "Must be valid alpha or numeric characters", - "Match": "Must match %s", - "NoMatch": "Must not match %s", - "AlphaDash": "Must be valid alpha or numeric or dash(-_) characters", - "Email": "Must be a valid email address", - "IP": "Must be a valid ip address", - "Base64": "Must be valid base64 characters", - "Mobile": "Must be valid mobile number", - "Tel": "Must be valid telephone number", - "Phone": "Must be valid telephone or mobile phone number", - "ZipCode": "Must be valid zipcode", -} - -// SetDefaultMessage set default messages -// if not set, the default messages are -// "Required": "Can not be empty", -// "Min": "Minimum is %d", -// "Max": "Maximum is %d", -// "Range": "Range is %d to %d", -// "MinSize": "Minimum size is %d", -// "MaxSize": "Maximum size is %d", -// "Length": "Required length is %d", -// "Alpha": "Must be valid alpha characters", -// "Numeric": "Must be valid numeric characters", -// "AlphaNumeric": "Must be valid alpha or numeric characters", -// "Match": "Must match %s", -// "NoMatch": "Must not match %s", -// "AlphaDash": "Must be valid alpha or numeric or dash(-_) characters", -// "Email": "Must be a valid email address", -// "IP": "Must be a valid ip address", -// "Base64": "Must be valid base64 characters", -// "Mobile": "Must be valid mobile number", -// "Tel": "Must be valid telephone number", -// "Phone": "Must be valid telephone or mobile phone number", -// "ZipCode": "Must be valid zipcode", -func SetDefaultMessage(msg map[string]string) { - if len(msg) == 0 { - return - } - - for name := range msg { - MessageTmpls[name] = msg[name] - } -} - -// Validator interface -type Validator interface { - IsSatisfied(interface{}) bool - DefaultMessage() string - GetKey() string - GetLimitValue() interface{} -} - -// Required struct -type Required struct { - Key string -} - -// IsSatisfied judge whether obj has value -func (r Required) IsSatisfied(obj interface{}) bool { - if obj == nil { - return false - } - - if str, ok := obj.(string); ok { - return len(strings.TrimSpace(str)) > 0 - } - if _, ok := obj.(bool); ok { - return true - } - if i, ok := obj.(int); ok { - return i != 0 - } - if i, ok := obj.(uint); ok { - return i != 0 - } - if i, ok := obj.(int8); ok { - return i != 0 - } - if i, ok := obj.(uint8); ok { - return i != 0 - } - if i, ok := obj.(int16); ok { - return i != 0 - } - if i, ok := obj.(uint16); ok { - return i != 0 - } - if i, ok := obj.(uint32); ok { - return i != 0 - } - if i, ok := obj.(int32); ok { - return i != 0 - } - if i, ok := obj.(int64); ok { - return i != 0 - } - if i, ok := obj.(uint64); ok { - return i != 0 - } - if t, ok := obj.(time.Time); ok { - return !t.IsZero() - } - v := reflect.ValueOf(obj) - if v.Kind() == reflect.Slice { - return v.Len() > 0 - } - return true -} - -// DefaultMessage return the default error message -func (r Required) DefaultMessage() string { - return MessageTmpls["Required"] -} - -// GetKey return the r.Key -func (r Required) GetKey() string { - return r.Key -} - -// GetLimitValue return nil now -func (r Required) GetLimitValue() interface{} { - return nil -} - -// Min check struct -type Min struct { - Min int - Key string -} - -// IsSatisfied judge whether obj is valid -// not support int64 on 32-bit platform -func (m Min) IsSatisfied(obj interface{}) bool { - var v int - switch obj.(type) { - case int64: - if wordsize == 32 { - return false - } - v = int(obj.(int64)) - case int: - v = obj.(int) - case int32: - v = int(obj.(int32)) - case int16: - v = int(obj.(int16)) - case int8: - v = int(obj.(int8)) - default: - return false - } - - return v >= m.Min -} - -// DefaultMessage return the default min error message -func (m Min) DefaultMessage() string { - return fmt.Sprintf(MessageTmpls["Min"], m.Min) -} - -// GetKey return the m.Key -func (m Min) GetKey() string { - return m.Key -} - -// GetLimitValue return the limit value, Min -func (m Min) GetLimitValue() interface{} { - return m.Min -} - -// Max validate struct -type Max struct { - Max int - Key string -} - -// IsSatisfied judge whether obj is valid -// not support int64 on 32-bit platform -func (m Max) IsSatisfied(obj interface{}) bool { - var v int - switch obj.(type) { - case int64: - if wordsize == 32 { - return false - } - v = int(obj.(int64)) - case int: - v = obj.(int) - case int32: - v = int(obj.(int32)) - case int16: - v = int(obj.(int16)) - case int8: - v = int(obj.(int8)) - default: - return false - } - - return v <= m.Max -} - -// DefaultMessage return the default max error message -func (m Max) DefaultMessage() string { - return fmt.Sprintf(MessageTmpls["Max"], m.Max) -} - -// GetKey return the m.Key -func (m Max) GetKey() string { - return m.Key -} - -// GetLimitValue return the limit value, Max -func (m Max) GetLimitValue() interface{} { - return m.Max -} - -// Range Requires an integer to be within Min, Max inclusive. -type Range struct { - Min - Max - Key string -} - -// IsSatisfied judge whether obj is valid -// not support int64 on 32-bit platform -func (r Range) IsSatisfied(obj interface{}) bool { - return r.Min.IsSatisfied(obj) && r.Max.IsSatisfied(obj) -} - -// DefaultMessage return the default Range error message -func (r Range) DefaultMessage() string { - return fmt.Sprintf(MessageTmpls["Range"], r.Min.Min, r.Max.Max) -} - -// GetKey return the m.Key -func (r Range) GetKey() string { - return r.Key -} - -// GetLimitValue return the limit value, Max -func (r Range) GetLimitValue() interface{} { - return []int{r.Min.Min, r.Max.Max} -} - -// MinSize Requires an array or string to be at least a given length. -type MinSize struct { - Min int - Key string -} - -// IsSatisfied judge whether obj is valid -func (m MinSize) IsSatisfied(obj interface{}) bool { - if str, ok := obj.(string); ok { - return utf8.RuneCountInString(str) >= m.Min - } - v := reflect.ValueOf(obj) - if v.Kind() == reflect.Slice { - return v.Len() >= m.Min - } - return false -} - -// DefaultMessage return the default MinSize error message -func (m MinSize) DefaultMessage() string { - return fmt.Sprintf(MessageTmpls["MinSize"], m.Min) -} - -// GetKey return the m.Key -func (m MinSize) GetKey() string { - return m.Key -} - -// GetLimitValue return the limit value -func (m MinSize) GetLimitValue() interface{} { - return m.Min -} - -// MaxSize Requires an array or string to be at most a given length. -type MaxSize struct { - Max int - Key string -} - -// IsSatisfied judge whether obj is valid -func (m MaxSize) IsSatisfied(obj interface{}) bool { - if str, ok := obj.(string); ok { - return utf8.RuneCountInString(str) <= m.Max - } - v := reflect.ValueOf(obj) - if v.Kind() == reflect.Slice { - return v.Len() <= m.Max - } - return false -} - -// DefaultMessage return the default MaxSize error message -func (m MaxSize) DefaultMessage() string { - return fmt.Sprintf(MessageTmpls["MaxSize"], m.Max) -} - -// GetKey return the m.Key -func (m MaxSize) GetKey() string { - return m.Key -} - -// GetLimitValue return the limit value -func (m MaxSize) GetLimitValue() interface{} { - return m.Max -} - -// Length Requires an array or string to be exactly a given length. -type Length struct { - N int - Key string -} - -// IsSatisfied judge whether obj is valid -func (l Length) IsSatisfied(obj interface{}) bool { - if str, ok := obj.(string); ok { - return utf8.RuneCountInString(str) == l.N - } - v := reflect.ValueOf(obj) - if v.Kind() == reflect.Slice { - return v.Len() == l.N - } - return false -} - -// DefaultMessage return the default Length error message -func (l Length) DefaultMessage() string { - return fmt.Sprintf(MessageTmpls["Length"], l.N) -} - -// GetKey return the m.Key -func (l Length) GetKey() string { - return l.Key -} - -// GetLimitValue return the limit value -func (l Length) GetLimitValue() interface{} { - return l.N -} - -// Alpha check the alpha -type Alpha struct { - Key string -} - -// IsSatisfied judge whether obj is valid -func (a Alpha) IsSatisfied(obj interface{}) bool { - if str, ok := obj.(string); ok { - for _, v := range str { - if ('Z' < v || v < 'A') && ('z' < v || v < 'a') { - return false - } - } - return true - } - return false -} - -// DefaultMessage return the default Length error message -func (a Alpha) DefaultMessage() string { - return MessageTmpls["Alpha"] -} - -// GetKey return the m.Key -func (a Alpha) GetKey() string { - return a.Key -} - -// GetLimitValue return the limit value -func (a Alpha) GetLimitValue() interface{} { - return nil -} - -// Numeric check number -type Numeric struct { - Key string -} - -// IsSatisfied judge whether obj is valid -func (n Numeric) IsSatisfied(obj interface{}) bool { - if str, ok := obj.(string); ok { - for _, v := range str { - if '9' < v || v < '0' { - return false - } - } - return true - } - return false -} - -// DefaultMessage return the default Length error message -func (n Numeric) DefaultMessage() string { - return MessageTmpls["Numeric"] -} - -// GetKey return the n.Key -func (n Numeric) GetKey() string { - return n.Key -} - -// GetLimitValue return the limit value -func (n Numeric) GetLimitValue() interface{} { - return nil -} - -// AlphaNumeric check alpha and number -type AlphaNumeric struct { - Key string -} - -// IsSatisfied judge whether obj is valid -func (a AlphaNumeric) IsSatisfied(obj interface{}) bool { - if str, ok := obj.(string); ok { - for _, v := range str { - if ('Z' < v || v < 'A') && ('z' < v || v < 'a') && ('9' < v || v < '0') { - return false - } - } - return true - } - return false -} - -// DefaultMessage return the default Length error message -func (a AlphaNumeric) DefaultMessage() string { - return MessageTmpls["AlphaNumeric"] -} - -// GetKey return the a.Key -func (a AlphaNumeric) GetKey() string { - return a.Key -} - -// GetLimitValue return the limit value -func (a AlphaNumeric) GetLimitValue() interface{} { - return nil -} - -// Match Requires a string to match a given regex. -type Match struct { - Regexp *regexp.Regexp - Key string -} - -// IsSatisfied judge whether obj is valid -func (m Match) IsSatisfied(obj interface{}) bool { - return m.Regexp.MatchString(fmt.Sprintf("%v", obj)) -} - -// DefaultMessage return the default Match error message -func (m Match) DefaultMessage() string { - return fmt.Sprintf(MessageTmpls["Match"], m.Regexp.String()) -} - -// GetKey return the m.Key -func (m Match) GetKey() string { - return m.Key -} - -// GetLimitValue return the limit value -func (m Match) GetLimitValue() interface{} { - return m.Regexp.String() -} - -// NoMatch Requires a string to not match a given regex. -type NoMatch struct { - Match - Key string -} - -// IsSatisfied judge whether obj is valid -func (n NoMatch) IsSatisfied(obj interface{}) bool { - return !n.Match.IsSatisfied(obj) -} - -// DefaultMessage return the default NoMatch error message -func (n NoMatch) DefaultMessage() string { - return fmt.Sprintf(MessageTmpls["NoMatch"], n.Regexp.String()) -} - -// GetKey return the n.Key -func (n NoMatch) GetKey() string { - return n.Key -} - -// GetLimitValue return the limit value -func (n NoMatch) GetLimitValue() interface{} { - return n.Regexp.String() -} - -var alphaDashPattern = regexp.MustCompile(`[^\d\w-_]`) - -// AlphaDash check not Alpha -type AlphaDash struct { - NoMatch - Key string -} - -// DefaultMessage return the default AlphaDash error message -func (a AlphaDash) DefaultMessage() string { - return MessageTmpls["AlphaDash"] -} - -// GetKey return the n.Key -func (a AlphaDash) GetKey() string { - return a.Key -} - -// GetLimitValue return the limit value -func (a AlphaDash) GetLimitValue() interface{} { - return nil -} - -var emailPattern = regexp.MustCompile(`^[\w!#$%&'*+/=?^_` + "`" + `{|}~-]+(?:\.[\w!#$%&'*+/=?^_` + "`" + `{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[a-zA-Z0-9](?:[\w-]*[\w])?$`) - -// Email check struct -type Email struct { - Match - Key string -} - -// DefaultMessage return the default Email error message -func (e Email) DefaultMessage() string { - return MessageTmpls["Email"] -} - -// GetKey return the n.Key -func (e Email) GetKey() string { - return e.Key -} - -// GetLimitValue return the limit value -func (e Email) GetLimitValue() interface{} { - return nil -} - -var ipPattern = regexp.MustCompile(`^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$`) - -// IP check struct -type IP struct { - Match - Key string -} - -// DefaultMessage return the default IP error message -func (i IP) DefaultMessage() string { - return MessageTmpls["IP"] -} - -// GetKey return the i.Key -func (i IP) GetKey() string { - return i.Key -} - -// GetLimitValue return the limit value -func (i IP) GetLimitValue() interface{} { - return nil -} - -var base64Pattern = regexp.MustCompile(`^(?:[A-Za-z0-99+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$`) - -// Base64 check struct -type Base64 struct { - Match - Key string -} - -// DefaultMessage return the default Base64 error message -func (b Base64) DefaultMessage() string { - return MessageTmpls["Base64"] -} - -// GetKey return the b.Key -func (b Base64) GetKey() string { - return b.Key -} - -// GetLimitValue return the limit value -func (b Base64) GetLimitValue() interface{} { - return nil -} - -// just for chinese mobile phone number -var mobilePattern = regexp.MustCompile(`^((\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][06789]|[4][579]))\d{8}$`) - -// Mobile check struct -type Mobile struct { - Match - Key string -} - -// DefaultMessage return the default Mobile error message -func (m Mobile) DefaultMessage() string { - return MessageTmpls["Mobile"] -} - -// GetKey return the m.Key -func (m Mobile) GetKey() string { - return m.Key -} - -// GetLimitValue return the limit value -func (m Mobile) GetLimitValue() interface{} { - return nil -} - -// just for chinese telephone number -var telPattern = regexp.MustCompile(`^(0\d{2,3}(\-)?)?\d{7,8}$`) - -// Tel check telephone struct -type Tel struct { - Match - Key string -} - -// DefaultMessage return the default Tel error message -func (t Tel) DefaultMessage() string { - return MessageTmpls["Tel"] -} - -// GetKey return the t.Key -func (t Tel) GetKey() string { - return t.Key -} - -// GetLimitValue return the limit value -func (t Tel) GetLimitValue() interface{} { - return nil -} - -// Phone just for chinese telephone or mobile phone number -type Phone struct { - Mobile - Tel - Key string -} - -// IsSatisfied judge whether obj is valid -func (p Phone) IsSatisfied(obj interface{}) bool { - return p.Mobile.IsSatisfied(obj) || p.Tel.IsSatisfied(obj) -} - -// DefaultMessage return the default Phone error message -func (p Phone) DefaultMessage() string { - return MessageTmpls["Phone"] -} - -// GetKey return the p.Key -func (p Phone) GetKey() string { - return p.Key -} - -// GetLimitValue return the limit value -func (p Phone) GetLimitValue() interface{} { - return nil -} - -// just for chinese zipcode -var zipCodePattern = regexp.MustCompile(`^[1-9]\d{5}$`) - -// ZipCode check the zip struct -type ZipCode struct { - Match - Key string -} - -// DefaultMessage return the default Zip error message -func (z ZipCode) DefaultMessage() string { - return MessageTmpls["ZipCode"] -} - -// GetKey return the z.Key -func (z ZipCode) GetKey() string { - return z.Key -} - -// GetLimitValue return the limit value -func (z ZipCode) GetLimitValue() interface{} { - return nil -} diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/LICENSE b/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/LICENSE deleted file mode 100755 index 6a66aea..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/PATENTS b/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/PATENTS deleted file mode 100755 index 7330990..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/PATENTS +++ /dev/null @@ -1,22 +0,0 @@ -Additional IP Rights Grant (Patents) - -"This implementation" means the copyrightable works distributed by -Google as part of the Go project. - -Google hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) -patent license to make, have made, use, offer to sell, sell, import, -transfer and otherwise run, modify and propagate the contents of this -implementation of Go, where such license applies only to those patent -claims, both currently owned or controlled by Google and acquired in -the future, licensable by Google that are necessarily infringed by this -implementation of Go. This grant does not include claims that would be -infringed only as a consequence of further modification of this -implementation. If you or your agent or exclusive licensee institute or -order or agree to the institution of patent litigation against any -entity (including a cross-claim or counterclaim in a lawsuit) alleging -that this implementation of Go or any code incorporated within this -implementation of Go constitutes direct or contributory patent -infringement, or inducement of patent infringement, then any patent -rights granted to you under this License for this implementation of Go -shall terminate as of the date such litigation is filed. diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/acme.go b/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/acme.go deleted file mode 100755 index ece9113..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/acme.go +++ /dev/null @@ -1,921 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package acme provides an implementation of the -// Automatic Certificate Management Environment (ACME) spec. -// See https://tools.ietf.org/html/draft-ietf-acme-acme-02 for details. -// -// Most common scenarios will want to use autocert subdirectory instead, -// which provides automatic access to certificates from Let's Encrypt -// and any other ACME-based CA. -// -// This package is a work in progress and makes no API stability promises. -package acme - -import ( - "context" - "crypto" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/sha256" - "crypto/tls" - "crypto/x509" - "crypto/x509/pkix" - "encoding/asn1" - "encoding/base64" - "encoding/hex" - "encoding/json" - "encoding/pem" - "errors" - "fmt" - "io" - "io/ioutil" - "math/big" - "net/http" - "strings" - "sync" - "time" -) - -const ( - // LetsEncryptURL is the Directory endpoint of Let's Encrypt CA. - LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory" - - // ALPNProto is the ALPN protocol name used by a CA server when validating - // tls-alpn-01 challenges. - // - // Package users must ensure their servers can negotiate the ACME ALPN - // in order for tls-alpn-01 challenge verifications to succeed. - ALPNProto = "acme-tls/1" -) - -// idPeACMEIdentifierV1 is the OID for the ACME extension for the TLS-ALPN challenge. -var idPeACMEIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 30, 1} - -const ( - maxChainLen = 5 // max depth and breadth of a certificate chain - maxCertSize = 1 << 20 // max size of a certificate, in bytes - - // Max number of collected nonces kept in memory. - // Expect usual peak of 1 or 2. - maxNonces = 100 -) - -// Client is an ACME client. -// The only required field is Key. An example of creating a client with a new key -// is as follows: -// -// key, err := rsa.GenerateKey(rand.Reader, 2048) -// if err != nil { -// log.Fatal(err) -// } -// client := &Client{Key: key} -// -type Client struct { - // Key is the account key used to register with a CA and sign requests. - // Key.Public() must return a *rsa.PublicKey or *ecdsa.PublicKey. - Key crypto.Signer - - // HTTPClient optionally specifies an HTTP client to use - // instead of http.DefaultClient. - HTTPClient *http.Client - - // DirectoryURL points to the CA directory endpoint. - // If empty, LetsEncryptURL is used. - // Mutating this value after a successful call of Client's Discover method - // will have no effect. - DirectoryURL string - - // RetryBackoff computes the duration after which the nth retry of a failed request - // should occur. The value of n for the first call on failure is 1. - // The values of r and resp are the request and response of the last failed attempt. - // If the returned value is negative or zero, no more retries are done and an error - // is returned to the caller of the original method. - // - // Requests which result in a 4xx client error are not retried, - // except for 400 Bad Request due to "bad nonce" errors and 429 Too Many Requests. - // - // If RetryBackoff is nil, a truncated exponential backoff algorithm - // with the ceiling of 10 seconds is used, where each subsequent retry n - // is done after either ("Retry-After" + jitter) or (2^n seconds + jitter), - // preferring the former if "Retry-After" header is found in the resp. - // The jitter is a random value up to 1 second. - RetryBackoff func(n int, r *http.Request, resp *http.Response) time.Duration - - dirMu sync.Mutex // guards writes to dir - dir *Directory // cached result of Client's Discover method - - noncesMu sync.Mutex - nonces map[string]struct{} // nonces collected from previous responses -} - -// Discover performs ACME server discovery using c.DirectoryURL. -// -// It caches successful result. So, subsequent calls will not result in -// a network round-trip. This also means mutating c.DirectoryURL after successful call -// of this method will have no effect. -func (c *Client) Discover(ctx context.Context) (Directory, error) { - c.dirMu.Lock() - defer c.dirMu.Unlock() - if c.dir != nil { - return *c.dir, nil - } - - dirURL := c.DirectoryURL - if dirURL == "" { - dirURL = LetsEncryptURL - } - res, err := c.get(ctx, dirURL, wantStatus(http.StatusOK)) - if err != nil { - return Directory{}, err - } - defer res.Body.Close() - c.addNonce(res.Header) - - var v struct { - Reg string `json:"new-reg"` - Authz string `json:"new-authz"` - Cert string `json:"new-cert"` - Revoke string `json:"revoke-cert"` - Meta struct { - Terms string `json:"terms-of-service"` - Website string `json:"website"` - CAA []string `json:"caa-identities"` - } - } - if err := json.NewDecoder(res.Body).Decode(&v); err != nil { - return Directory{}, err - } - c.dir = &Directory{ - RegURL: v.Reg, - AuthzURL: v.Authz, - CertURL: v.Cert, - RevokeURL: v.Revoke, - Terms: v.Meta.Terms, - Website: v.Meta.Website, - CAA: v.Meta.CAA, - } - return *c.dir, nil -} - -// CreateCert requests a new certificate using the Certificate Signing Request csr encoded in DER format. -// The exp argument indicates the desired certificate validity duration. CA may issue a certificate -// with a different duration. -// If the bundle argument is true, the returned value will also contain the CA (issuer) certificate chain. -// -// In the case where CA server does not provide the issued certificate in the response, -// CreateCert will poll certURL using c.FetchCert, which will result in additional round-trips. -// In such a scenario, the caller can cancel the polling with ctx. -// -// CreateCert returns an error if the CA's response or chain was unreasonably large. -// Callers are encouraged to parse the returned value to ensure the certificate is valid and has the expected features. -func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, bundle bool) (der [][]byte, certURL string, err error) { - if _, err := c.Discover(ctx); err != nil { - return nil, "", err - } - - req := struct { - Resource string `json:"resource"` - CSR string `json:"csr"` - NotBefore string `json:"notBefore,omitempty"` - NotAfter string `json:"notAfter,omitempty"` - }{ - Resource: "new-cert", - CSR: base64.RawURLEncoding.EncodeToString(csr), - } - now := timeNow() - req.NotBefore = now.Format(time.RFC3339) - if exp > 0 { - req.NotAfter = now.Add(exp).Format(time.RFC3339) - } - - res, err := c.post(ctx, c.Key, c.dir.CertURL, req, wantStatus(http.StatusCreated)) - if err != nil { - return nil, "", err - } - defer res.Body.Close() - - curl := res.Header.Get("Location") // cert permanent URL - if res.ContentLength == 0 { - // no cert in the body; poll until we get it - cert, err := c.FetchCert(ctx, curl, bundle) - return cert, curl, err - } - // slurp issued cert and CA chain, if requested - cert, err := c.responseCert(ctx, res, bundle) - return cert, curl, err -} - -// FetchCert retrieves already issued certificate from the given url, in DER format. -// It retries the request until the certificate is successfully retrieved, -// context is cancelled by the caller or an error response is received. -// -// The returned value will also contain the CA (issuer) certificate if the bundle argument is true. -// -// FetchCert returns an error if the CA's response or chain was unreasonably large. -// Callers are encouraged to parse the returned value to ensure the certificate is valid -// and has expected features. -func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) { - res, err := c.get(ctx, url, wantStatus(http.StatusOK)) - if err != nil { - return nil, err - } - return c.responseCert(ctx, res, bundle) -} - -// RevokeCert revokes a previously issued certificate cert, provided in DER format. -// -// The key argument, used to sign the request, must be authorized -// to revoke the certificate. It's up to the CA to decide which keys are authorized. -// For instance, the key pair of the certificate may be authorized. -// If the key is nil, c.Key is used instead. -func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error { - if _, err := c.Discover(ctx); err != nil { - return err - } - - body := &struct { - Resource string `json:"resource"` - Cert string `json:"certificate"` - Reason int `json:"reason"` - }{ - Resource: "revoke-cert", - Cert: base64.RawURLEncoding.EncodeToString(cert), - Reason: int(reason), - } - if key == nil { - key = c.Key - } - res, err := c.post(ctx, key, c.dir.RevokeURL, body, wantStatus(http.StatusOK)) - if err != nil { - return err - } - defer res.Body.Close() - return nil -} - -// AcceptTOS always returns true to indicate the acceptance of a CA's Terms of Service -// during account registration. See Register method of Client for more details. -func AcceptTOS(tosURL string) bool { return true } - -// Register creates a new account registration by following the "new-reg" flow. -// It returns the registered account. The account is not modified. -// -// The registration may require the caller to agree to the CA's Terms of Service (TOS). -// If so, and the account has not indicated the acceptance of the terms (see Account for details), -// Register calls prompt with a TOS URL provided by the CA. Prompt should report -// whether the caller agrees to the terms. To always accept the terms, the caller can use AcceptTOS. -func (c *Client) Register(ctx context.Context, a *Account, prompt func(tosURL string) bool) (*Account, error) { - if _, err := c.Discover(ctx); err != nil { - return nil, err - } - - var err error - if a, err = c.doReg(ctx, c.dir.RegURL, "new-reg", a); err != nil { - return nil, err - } - var accept bool - if a.CurrentTerms != "" && a.CurrentTerms != a.AgreedTerms { - accept = prompt(a.CurrentTerms) - } - if accept { - a.AgreedTerms = a.CurrentTerms - a, err = c.UpdateReg(ctx, a) - } - return a, err -} - -// GetReg retrieves an existing registration. -// The url argument is an Account URI. -func (c *Client) GetReg(ctx context.Context, url string) (*Account, error) { - a, err := c.doReg(ctx, url, "reg", nil) - if err != nil { - return nil, err - } - a.URI = url - return a, nil -} - -// UpdateReg updates an existing registration. -// It returns an updated account copy. The provided account is not modified. -func (c *Client) UpdateReg(ctx context.Context, a *Account) (*Account, error) { - uri := a.URI - a, err := c.doReg(ctx, uri, "reg", a) - if err != nil { - return nil, err - } - a.URI = uri - return a, nil -} - -// Authorize performs the initial step in an authorization flow. -// The caller will then need to choose from and perform a set of returned -// challenges using c.Accept in order to successfully complete authorization. -// -// If an authorization has been previously granted, the CA may return -// a valid authorization (Authorization.Status is StatusValid). If so, the caller -// need not fulfill any challenge and can proceed to requesting a certificate. -func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, error) { - if _, err := c.Discover(ctx); err != nil { - return nil, err - } - - type authzID struct { - Type string `json:"type"` - Value string `json:"value"` - } - req := struct { - Resource string `json:"resource"` - Identifier authzID `json:"identifier"` - }{ - Resource: "new-authz", - Identifier: authzID{Type: "dns", Value: domain}, - } - res, err := c.post(ctx, c.Key, c.dir.AuthzURL, req, wantStatus(http.StatusCreated)) - if err != nil { - return nil, err - } - defer res.Body.Close() - - var v wireAuthz - if err := json.NewDecoder(res.Body).Decode(&v); err != nil { - return nil, fmt.Errorf("acme: invalid response: %v", err) - } - if v.Status != StatusPending && v.Status != StatusValid { - return nil, fmt.Errorf("acme: unexpected status: %s", v.Status) - } - return v.authorization(res.Header.Get("Location")), nil -} - -// GetAuthorization retrieves an authorization identified by the given URL. -// -// If a caller needs to poll an authorization until its status is final, -// see the WaitAuthorization method. -func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) { - res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) - if err != nil { - return nil, err - } - defer res.Body.Close() - var v wireAuthz - if err := json.NewDecoder(res.Body).Decode(&v); err != nil { - return nil, fmt.Errorf("acme: invalid response: %v", err) - } - return v.authorization(url), nil -} - -// RevokeAuthorization relinquishes an existing authorization identified -// by the given URL. -// The url argument is an Authorization.URI value. -// -// If successful, the caller will be required to obtain a new authorization -// using the Authorize method before being able to request a new certificate -// for the domain associated with the authorization. -// -// It does not revoke existing certificates. -func (c *Client) RevokeAuthorization(ctx context.Context, url string) error { - req := struct { - Resource string `json:"resource"` - Status string `json:"status"` - Delete bool `json:"delete"` - }{ - Resource: "authz", - Status: "deactivated", - Delete: true, - } - res, err := c.post(ctx, c.Key, url, req, wantStatus(http.StatusOK)) - if err != nil { - return err - } - defer res.Body.Close() - return nil -} - -// WaitAuthorization polls an authorization at the given URL -// until it is in one of the final states, StatusValid or StatusInvalid, -// the ACME CA responded with a 4xx error code, or the context is done. -// -// It returns a non-nil Authorization only if its Status is StatusValid. -// In all other cases WaitAuthorization returns an error. -// If the Status is StatusInvalid, the returned error is of type *AuthorizationError. -func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) { - for { - res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) - if err != nil { - return nil, err - } - - var raw wireAuthz - err = json.NewDecoder(res.Body).Decode(&raw) - res.Body.Close() - switch { - case err != nil: - // Skip and retry. - case raw.Status == StatusValid: - return raw.authorization(url), nil - case raw.Status == StatusInvalid: - return nil, raw.error(url) - } - - // Exponential backoff is implemented in c.get above. - // This is just to prevent continuously hitting the CA - // while waiting for a final authorization status. - d := retryAfter(res.Header.Get("Retry-After")) - if d == 0 { - // Given that the fastest challenges TLS-SNI and HTTP-01 - // require a CA to make at least 1 network round trip - // and most likely persist a challenge state, - // this default delay seems reasonable. - d = time.Second - } - t := time.NewTimer(d) - select { - case <-ctx.Done(): - t.Stop() - return nil, ctx.Err() - case <-t.C: - // Retry. - } - } -} - -// GetChallenge retrieves the current status of an challenge. -// -// A client typically polls a challenge status using this method. -func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) { - res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) - if err != nil { - return nil, err - } - defer res.Body.Close() - v := wireChallenge{URI: url} - if err := json.NewDecoder(res.Body).Decode(&v); err != nil { - return nil, fmt.Errorf("acme: invalid response: %v", err) - } - return v.challenge(), nil -} - -// Accept informs the server that the client accepts one of its challenges -// previously obtained with c.Authorize. -// -// The server will then perform the validation asynchronously. -func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error) { - auth, err := keyAuth(c.Key.Public(), chal.Token) - if err != nil { - return nil, err - } - - req := struct { - Resource string `json:"resource"` - Type string `json:"type"` - Auth string `json:"keyAuthorization"` - }{ - Resource: "challenge", - Type: chal.Type, - Auth: auth, - } - res, err := c.post(ctx, c.Key, chal.URI, req, wantStatus( - http.StatusOK, // according to the spec - http.StatusAccepted, // Let's Encrypt: see https://goo.gl/WsJ7VT (acme-divergences.md) - )) - if err != nil { - return nil, err - } - defer res.Body.Close() - - var v wireChallenge - if err := json.NewDecoder(res.Body).Decode(&v); err != nil { - return nil, fmt.Errorf("acme: invalid response: %v", err) - } - return v.challenge(), nil -} - -// DNS01ChallengeRecord returns a DNS record value for a dns-01 challenge response. -// A TXT record containing the returned value must be provisioned under -// "_acme-challenge" name of the domain being validated. -// -// The token argument is a Challenge.Token value. -func (c *Client) DNS01ChallengeRecord(token string) (string, error) { - ka, err := keyAuth(c.Key.Public(), token) - if err != nil { - return "", err - } - b := sha256.Sum256([]byte(ka)) - return base64.RawURLEncoding.EncodeToString(b[:]), nil -} - -// HTTP01ChallengeResponse returns the response for an http-01 challenge. -// Servers should respond with the value to HTTP requests at the URL path -// provided by HTTP01ChallengePath to validate the challenge and prove control -// over a domain name. -// -// The token argument is a Challenge.Token value. -func (c *Client) HTTP01ChallengeResponse(token string) (string, error) { - return keyAuth(c.Key.Public(), token) -} - -// HTTP01ChallengePath returns the URL path at which the response for an http-01 challenge -// should be provided by the servers. -// The response value can be obtained with HTTP01ChallengeResponse. -// -// The token argument is a Challenge.Token value. -func (c *Client) HTTP01ChallengePath(token string) string { - return "/.well-known/acme-challenge/" + token -} - -// TLSSNI01ChallengeCert creates a certificate for TLS-SNI-01 challenge response. -// Servers can present the certificate to validate the challenge and prove control -// over a domain name. -// -// The implementation is incomplete in that the returned value is a single certificate, -// computed only for Z0 of the key authorization. ACME CAs are expected to update -// their implementations to use the newer version, TLS-SNI-02. -// For more details on TLS-SNI-01 see https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-7.3. -// -// The token argument is a Challenge.Token value. -// If a WithKey option is provided, its private part signs the returned cert, -// and the public part is used to specify the signee. -// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve. -// -// The returned certificate is valid for the next 24 hours and must be presented only when -// the server name of the TLS ClientHello matches exactly the returned name value. -func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) { - ka, err := keyAuth(c.Key.Public(), token) - if err != nil { - return tls.Certificate{}, "", err - } - b := sha256.Sum256([]byte(ka)) - h := hex.EncodeToString(b[:]) - name = fmt.Sprintf("%s.%s.acme.invalid", h[:32], h[32:]) - cert, err = tlsChallengeCert([]string{name}, opt) - if err != nil { - return tls.Certificate{}, "", err - } - return cert, name, nil -} - -// TLSSNI02ChallengeCert creates a certificate for TLS-SNI-02 challenge response. -// Servers can present the certificate to validate the challenge and prove control -// over a domain name. For more details on TLS-SNI-02 see -// https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-7.3. -// -// The token argument is a Challenge.Token value. -// If a WithKey option is provided, its private part signs the returned cert, -// and the public part is used to specify the signee. -// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve. -// -// The returned certificate is valid for the next 24 hours and must be presented only when -// the server name in the TLS ClientHello matches exactly the returned name value. -func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) { - b := sha256.Sum256([]byte(token)) - h := hex.EncodeToString(b[:]) - sanA := fmt.Sprintf("%s.%s.token.acme.invalid", h[:32], h[32:]) - - ka, err := keyAuth(c.Key.Public(), token) - if err != nil { - return tls.Certificate{}, "", err - } - b = sha256.Sum256([]byte(ka)) - h = hex.EncodeToString(b[:]) - sanB := fmt.Sprintf("%s.%s.ka.acme.invalid", h[:32], h[32:]) - - cert, err = tlsChallengeCert([]string{sanA, sanB}, opt) - if err != nil { - return tls.Certificate{}, "", err - } - return cert, sanA, nil -} - -// TLSALPN01ChallengeCert creates a certificate for TLS-ALPN-01 challenge response. -// Servers can present the certificate to validate the challenge and prove control -// over a domain name. For more details on TLS-ALPN-01 see -// https://tools.ietf.org/html/draft-shoemaker-acme-tls-alpn-00#section-3 -// -// The token argument is a Challenge.Token value. -// If a WithKey option is provided, its private part signs the returned cert, -// and the public part is used to specify the signee. -// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve. -// -// The returned certificate is valid for the next 24 hours and must be presented only when -// the server name in the TLS ClientHello matches the domain, and the special acme-tls/1 ALPN protocol -// has been specified. -func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption) (cert tls.Certificate, err error) { - ka, err := keyAuth(c.Key.Public(), token) - if err != nil { - return tls.Certificate{}, err - } - shasum := sha256.Sum256([]byte(ka)) - extValue, err := asn1.Marshal(shasum[:]) - if err != nil { - return tls.Certificate{}, err - } - acmeExtension := pkix.Extension{ - Id: idPeACMEIdentifierV1, - Critical: true, - Value: extValue, - } - - tmpl := defaultTLSChallengeCertTemplate() - - var newOpt []CertOption - for _, o := range opt { - switch o := o.(type) { - case *certOptTemplate: - t := *(*x509.Certificate)(o) // shallow copy is ok - tmpl = &t - default: - newOpt = append(newOpt, o) - } - } - tmpl.ExtraExtensions = append(tmpl.ExtraExtensions, acmeExtension) - newOpt = append(newOpt, WithTemplate(tmpl)) - return tlsChallengeCert([]string{domain}, newOpt) -} - -// doReg sends all types of registration requests. -// The type of request is identified by typ argument, which is a "resource" -// in the ACME spec terms. -// -// A non-nil acct argument indicates whether the intention is to mutate data -// of the Account. Only Contact and Agreement of its fields are used -// in such cases. -func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Account) (*Account, error) { - req := struct { - Resource string `json:"resource"` - Contact []string `json:"contact,omitempty"` - Agreement string `json:"agreement,omitempty"` - }{ - Resource: typ, - } - if acct != nil { - req.Contact = acct.Contact - req.Agreement = acct.AgreedTerms - } - res, err := c.post(ctx, c.Key, url, req, wantStatus( - http.StatusOK, // updates and deletes - http.StatusCreated, // new account creation - http.StatusAccepted, // Let's Encrypt divergent implementation - )) - if err != nil { - return nil, err - } - defer res.Body.Close() - - var v struct { - Contact []string - Agreement string - Authorizations string - Certificates string - } - if err := json.NewDecoder(res.Body).Decode(&v); err != nil { - return nil, fmt.Errorf("acme: invalid response: %v", err) - } - var tos string - if v := linkHeader(res.Header, "terms-of-service"); len(v) > 0 { - tos = v[0] - } - var authz string - if v := linkHeader(res.Header, "next"); len(v) > 0 { - authz = v[0] - } - return &Account{ - URI: res.Header.Get("Location"), - Contact: v.Contact, - AgreedTerms: v.Agreement, - CurrentTerms: tos, - Authz: authz, - Authorizations: v.Authorizations, - Certificates: v.Certificates, - }, nil -} - -// popNonce returns a nonce value previously stored with c.addNonce -// or fetches a fresh one from the given URL. -func (c *Client) popNonce(ctx context.Context, url string) (string, error) { - c.noncesMu.Lock() - defer c.noncesMu.Unlock() - if len(c.nonces) == 0 { - return c.fetchNonce(ctx, url) - } - var nonce string - for nonce = range c.nonces { - delete(c.nonces, nonce) - break - } - return nonce, nil -} - -// clearNonces clears any stored nonces -func (c *Client) clearNonces() { - c.noncesMu.Lock() - defer c.noncesMu.Unlock() - c.nonces = make(map[string]struct{}) -} - -// addNonce stores a nonce value found in h (if any) for future use. -func (c *Client) addNonce(h http.Header) { - v := nonceFromHeader(h) - if v == "" { - return - } - c.noncesMu.Lock() - defer c.noncesMu.Unlock() - if len(c.nonces) >= maxNonces { - return - } - if c.nonces == nil { - c.nonces = make(map[string]struct{}) - } - c.nonces[v] = struct{}{} -} - -func (c *Client) fetchNonce(ctx context.Context, url string) (string, error) { - r, err := http.NewRequest("HEAD", url, nil) - if err != nil { - return "", err - } - resp, err := c.doNoRetry(ctx, r) - if err != nil { - return "", err - } - defer resp.Body.Close() - nonce := nonceFromHeader(resp.Header) - if nonce == "" { - if resp.StatusCode > 299 { - return "", responseError(resp) - } - return "", errors.New("acme: nonce not found") - } - return nonce, nil -} - -func nonceFromHeader(h http.Header) string { - return h.Get("Replay-Nonce") -} - -func (c *Client) responseCert(ctx context.Context, res *http.Response, bundle bool) ([][]byte, error) { - b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1)) - if err != nil { - return nil, fmt.Errorf("acme: response stream: %v", err) - } - if len(b) > maxCertSize { - return nil, errors.New("acme: certificate is too big") - } - cert := [][]byte{b} - if !bundle { - return cert, nil - } - - // Append CA chain cert(s). - // At least one is required according to the spec: - // https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.3.1 - up := linkHeader(res.Header, "up") - if len(up) == 0 { - return nil, errors.New("acme: rel=up link not found") - } - if len(up) > maxChainLen { - return nil, errors.New("acme: rel=up link is too large") - } - for _, url := range up { - cc, err := c.chainCert(ctx, url, 0) - if err != nil { - return nil, err - } - cert = append(cert, cc...) - } - return cert, nil -} - -// chainCert fetches CA certificate chain recursively by following "up" links. -// Each recursive call increments the depth by 1, resulting in an error -// if the recursion level reaches maxChainLen. -// -// First chainCert call starts with depth of 0. -func (c *Client) chainCert(ctx context.Context, url string, depth int) ([][]byte, error) { - if depth >= maxChainLen { - return nil, errors.New("acme: certificate chain is too deep") - } - - res, err := c.get(ctx, url, wantStatus(http.StatusOK)) - if err != nil { - return nil, err - } - defer res.Body.Close() - b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1)) - if err != nil { - return nil, err - } - if len(b) > maxCertSize { - return nil, errors.New("acme: certificate is too big") - } - chain := [][]byte{b} - - uplink := linkHeader(res.Header, "up") - if len(uplink) > maxChainLen { - return nil, errors.New("acme: certificate chain is too large") - } - for _, up := range uplink { - cc, err := c.chainCert(ctx, up, depth+1) - if err != nil { - return nil, err - } - chain = append(chain, cc...) - } - - return chain, nil -} - -// linkHeader returns URI-Reference values of all Link headers -// with relation-type rel. -// See https://tools.ietf.org/html/rfc5988#section-5 for details. -func linkHeader(h http.Header, rel string) []string { - var links []string - for _, v := range h["Link"] { - parts := strings.Split(v, ";") - for _, p := range parts { - p = strings.TrimSpace(p) - if !strings.HasPrefix(p, "rel=") { - continue - } - if v := strings.Trim(p[4:], `"`); v == rel { - links = append(links, strings.Trim(parts[0], "<>")) - } - } - } - return links -} - -// keyAuth generates a key authorization string for a given token. -func keyAuth(pub crypto.PublicKey, token string) (string, error) { - th, err := JWKThumbprint(pub) - if err != nil { - return "", err - } - return fmt.Sprintf("%s.%s", token, th), nil -} - -// defaultTLSChallengeCertTemplate is a template used to create challenge certs for TLS challenges. -func defaultTLSChallengeCertTemplate() *x509.Certificate { - return &x509.Certificate{ - SerialNumber: big.NewInt(1), - NotBefore: time.Now(), - NotAfter: time.Now().Add(24 * time.Hour), - BasicConstraintsValid: true, - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - } -} - -// tlsChallengeCert creates a temporary certificate for TLS-SNI challenges -// with the given SANs and auto-generated public/private key pair. -// The Subject Common Name is set to the first SAN to aid debugging. -// To create a cert with a custom key pair, specify WithKey option. -func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) { - var key crypto.Signer - tmpl := defaultTLSChallengeCertTemplate() - for _, o := range opt { - switch o := o.(type) { - case *certOptKey: - if key != nil { - return tls.Certificate{}, errors.New("acme: duplicate key option") - } - key = o.key - case *certOptTemplate: - t := *(*x509.Certificate)(o) // shallow copy is ok - tmpl = &t - default: - // package's fault, if we let this happen: - panic(fmt.Sprintf("unsupported option type %T", o)) - } - } - if key == nil { - var err error - if key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader); err != nil { - return tls.Certificate{}, err - } - } - tmpl.DNSNames = san - if len(san) > 0 { - tmpl.Subject.CommonName = san[0] - } - - der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, key.Public(), key) - if err != nil { - return tls.Certificate{}, err - } - return tls.Certificate{ - Certificate: [][]byte{der}, - PrivateKey: key, - }, nil -} - -// encodePEM returns b encoded as PEM with block of type typ. -func encodePEM(typ string, b []byte) []byte { - pb := &pem.Block{Type: typ, Bytes: b} - return pem.EncodeToMemory(pb) -} - -// timeNow is useful for testing for fixed current time. -var timeNow = time.Now diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/autocert/autocert.go b/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/autocert/autocert.go deleted file mode 100755 index 1a9d972..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/autocert/autocert.go +++ /dev/null @@ -1,1127 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package autocert provides automatic access to certificates from Let's Encrypt -// and any other ACME-based CA. -// -// This package is a work in progress and makes no API stability promises. -package autocert - -import ( - "bytes" - "context" - "crypto" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/rsa" - "crypto/tls" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "errors" - "fmt" - "io" - mathrand "math/rand" - "net" - "net/http" - "path" - "strings" - "sync" - "time" - - "golang.org/x/crypto/acme" -) - -// createCertRetryAfter is how much time to wait before removing a failed state -// entry due to an unsuccessful createCert call. -// This is a variable instead of a const for testing. -// TODO: Consider making it configurable or an exp backoff? -var createCertRetryAfter = time.Minute - -// pseudoRand is safe for concurrent use. -var pseudoRand *lockedMathRand - -func init() { - src := mathrand.NewSource(timeNow().UnixNano()) - pseudoRand = &lockedMathRand{rnd: mathrand.New(src)} -} - -// AcceptTOS is a Manager.Prompt function that always returns true to -// indicate acceptance of the CA's Terms of Service during account -// registration. -func AcceptTOS(tosURL string) bool { return true } - -// HostPolicy specifies which host names the Manager is allowed to respond to. -// It returns a non-nil error if the host should be rejected. -// The returned error is accessible via tls.Conn.Handshake and its callers. -// See Manager's HostPolicy field and GetCertificate method docs for more details. -type HostPolicy func(ctx context.Context, host string) error - -// HostWhitelist returns a policy where only the specified host names are allowed. -// Only exact matches are currently supported. Subdomains, regexp or wildcard -// will not match. -func HostWhitelist(hosts ...string) HostPolicy { - whitelist := make(map[string]bool, len(hosts)) - for _, h := range hosts { - whitelist[h] = true - } - return func(_ context.Context, host string) error { - if !whitelist[host] { - return errors.New("acme/autocert: host not configured") - } - return nil - } -} - -// defaultHostPolicy is used when Manager.HostPolicy is not set. -func defaultHostPolicy(context.Context, string) error { - return nil -} - -// Manager is a stateful certificate manager built on top of acme.Client. -// It obtains and refreshes certificates automatically using "tls-alpn-01", -// "tls-sni-01", "tls-sni-02" and "http-01" challenge types, -// as well as providing them to a TLS server via tls.Config. -// -// You must specify a cache implementation, such as DirCache, -// to reuse obtained certificates across program restarts. -// Otherwise your server is very likely to exceed the certificate -// issuer's request rate limits. -type Manager struct { - // Prompt specifies a callback function to conditionally accept a CA's Terms of Service (TOS). - // The registration may require the caller to agree to the CA's TOS. - // If so, Manager calls Prompt with a TOS URL provided by the CA. Prompt should report - // whether the caller agrees to the terms. - // - // To always accept the terms, the callers can use AcceptTOS. - Prompt func(tosURL string) bool - - // Cache optionally stores and retrieves previously-obtained certificates - // and other state. If nil, certs will only be cached for the lifetime of - // the Manager. Multiple Managers can share the same Cache. - // - // Using a persistent Cache, such as DirCache, is strongly recommended. - Cache Cache - - // HostPolicy controls which domains the Manager will attempt - // to retrieve new certificates for. It does not affect cached certs. - // - // If non-nil, HostPolicy is called before requesting a new cert. - // If nil, all hosts are currently allowed. This is not recommended, - // as it opens a potential attack where clients connect to a server - // by IP address and pretend to be asking for an incorrect host name. - // Manager will attempt to obtain a certificate for that host, incorrectly, - // eventually reaching the CA's rate limit for certificate requests - // and making it impossible to obtain actual certificates. - // - // See GetCertificate for more details. - HostPolicy HostPolicy - - // RenewBefore optionally specifies how early certificates should - // be renewed before they expire. - // - // If zero, they're renewed 30 days before expiration. - RenewBefore time.Duration - - // Client is used to perform low-level operations, such as account registration - // and requesting new certificates. - // - // If Client is nil, a zero-value acme.Client is used with acme.LetsEncryptURL - // as directory endpoint. If the Client.Key is nil, a new ECDSA P-256 key is - // generated and, if Cache is not nil, stored in cache. - // - // Mutating the field after the first call of GetCertificate method will have no effect. - Client *acme.Client - - // Email optionally specifies a contact email address. - // This is used by CAs, such as Let's Encrypt, to notify about problems - // with issued certificates. - // - // If the Client's account key is already registered, Email is not used. - Email string - - // ForceRSA used to make the Manager generate RSA certificates. It is now ignored. - // - // Deprecated: the Manager will request the correct type of certificate based - // on what each client supports. - ForceRSA bool - - // ExtraExtensions are used when generating a new CSR (Certificate Request), - // thus allowing customization of the resulting certificate. - // For instance, TLS Feature Extension (RFC 7633) can be used - // to prevent an OCSP downgrade attack. - // - // The field value is passed to crypto/x509.CreateCertificateRequest - // in the template's ExtraExtensions field as is. - ExtraExtensions []pkix.Extension - - clientMu sync.Mutex - client *acme.Client // initialized by acmeClient method - - stateMu sync.Mutex - state map[certKey]*certState - - // renewal tracks the set of domains currently running renewal timers. - renewalMu sync.Mutex - renewal map[certKey]*domainRenewal - - // tokensMu guards the rest of the fields: tryHTTP01, certTokens and httpTokens. - tokensMu sync.RWMutex - // tryHTTP01 indicates whether the Manager should try "http-01" challenge type - // during the authorization flow. - tryHTTP01 bool - // httpTokens contains response body values for http-01 challenges - // and is keyed by the URL path at which a challenge response is expected - // to be provisioned. - // The entries are stored for the duration of the authorization flow. - httpTokens map[string][]byte - // certTokens contains temporary certificates for tls-sni and tls-alpn challenges - // and is keyed by token domain name, which matches server name of ClientHello. - // Keys always have ".acme.invalid" suffix for tls-sni. Otherwise, they are domain names - // for tls-alpn. - // The entries are stored for the duration of the authorization flow. - certTokens map[string]*tls.Certificate -} - -// certKey is the key by which certificates are tracked in state, renewal and cache. -type certKey struct { - domain string // without trailing dot - isRSA bool // RSA cert for legacy clients (as opposed to default ECDSA) - isToken bool // tls-based challenge token cert; key type is undefined regardless of isRSA -} - -func (c certKey) String() string { - if c.isToken { - return c.domain + "+token" - } - if c.isRSA { - return c.domain + "+rsa" - } - return c.domain -} - -// TLSConfig creates a new TLS config suitable for net/http.Server servers, -// supporting HTTP/2 and the tls-alpn-01 ACME challenge type. -func (m *Manager) TLSConfig() *tls.Config { - return &tls.Config{ - GetCertificate: m.GetCertificate, - NextProtos: []string{ - "h2", "http/1.1", // enable HTTP/2 - acme.ALPNProto, // enable tls-alpn ACME challenges - }, - } -} - -// GetCertificate implements the tls.Config.GetCertificate hook. -// It provides a TLS certificate for hello.ServerName host, including answering -// tls-alpn-01 and *.acme.invalid (tls-sni-01 and tls-sni-02) challenges. -// All other fields of hello are ignored. -// -// If m.HostPolicy is non-nil, GetCertificate calls the policy before requesting -// a new cert. A non-nil error returned from m.HostPolicy halts TLS negotiation. -// The error is propagated back to the caller of GetCertificate and is user-visible. -// This does not affect cached certs. See HostPolicy field description for more details. -func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { - if m.Prompt == nil { - return nil, errors.New("acme/autocert: Manager.Prompt not set") - } - - name := hello.ServerName - if name == "" { - return nil, errors.New("acme/autocert: missing server name") - } - if !strings.Contains(strings.Trim(name, "."), ".") { - return nil, errors.New("acme/autocert: server name component count invalid") - } - if strings.ContainsAny(name, `+/\`) { - return nil, errors.New("acme/autocert: server name contains invalid character") - } - - // In the worst-case scenario, the timeout needs to account for caching, host policy, - // domain ownership verification and certificate issuance. - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) - defer cancel() - - // Check whether this is a token cert requested for TLS-SNI or TLS-ALPN challenge. - if wantsTokenCert(hello) { - m.tokensMu.RLock() - defer m.tokensMu.RUnlock() - // It's ok to use the same token cert key for both tls-sni and tls-alpn - // because there's always at most 1 token cert per on-going domain authorization. - // See m.verify for details. - if cert := m.certTokens[name]; cert != nil { - return cert, nil - } - if cert, err := m.cacheGet(ctx, certKey{domain: name, isToken: true}); err == nil { - return cert, nil - } - // TODO: cache error results? - return nil, fmt.Errorf("acme/autocert: no token cert for %q", name) - } - - // regular domain - ck := certKey{ - domain: strings.TrimSuffix(name, "."), // golang.org/issue/18114 - isRSA: !supportsECDSA(hello), - } - cert, err := m.cert(ctx, ck) - if err == nil { - return cert, nil - } - if err != ErrCacheMiss { - return nil, err - } - - // first-time - if err := m.hostPolicy()(ctx, name); err != nil { - return nil, err - } - cert, err = m.createCert(ctx, ck) - if err != nil { - return nil, err - } - m.cachePut(ctx, ck, cert) - return cert, nil -} - -// wantsTokenCert reports whether a TLS request with SNI is made by a CA server -// for a challenge verification. -func wantsTokenCert(hello *tls.ClientHelloInfo) bool { - // tls-alpn-01 - if len(hello.SupportedProtos) == 1 && hello.SupportedProtos[0] == acme.ALPNProto { - return true - } - // tls-sni-xx - return strings.HasSuffix(hello.ServerName, ".acme.invalid") -} - -func supportsECDSA(hello *tls.ClientHelloInfo) bool { - // The "signature_algorithms" extension, if present, limits the key exchange - // algorithms allowed by the cipher suites. See RFC 5246, section 7.4.1.4.1. - if hello.SignatureSchemes != nil { - ecdsaOK := false - schemeLoop: - for _, scheme := range hello.SignatureSchemes { - const tlsECDSAWithSHA1 tls.SignatureScheme = 0x0203 // constant added in Go 1.10 - switch scheme { - case tlsECDSAWithSHA1, tls.ECDSAWithP256AndSHA256, - tls.ECDSAWithP384AndSHA384, tls.ECDSAWithP521AndSHA512: - ecdsaOK = true - break schemeLoop - } - } - if !ecdsaOK { - return false - } - } - if hello.SupportedCurves != nil { - ecdsaOK := false - for _, curve := range hello.SupportedCurves { - if curve == tls.CurveP256 { - ecdsaOK = true - break - } - } - if !ecdsaOK { - return false - } - } - for _, suite := range hello.CipherSuites { - switch suite { - case tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: - return true - } - } - return false -} - -// HTTPHandler configures the Manager to provision ACME "http-01" challenge responses. -// It returns an http.Handler that responds to the challenges and must be -// running on port 80. If it receives a request that is not an ACME challenge, -// it delegates the request to the optional fallback handler. -// -// If fallback is nil, the returned handler redirects all GET and HEAD requests -// to the default TLS port 443 with 302 Found status code, preserving the original -// request path and query. It responds with 400 Bad Request to all other HTTP methods. -// The fallback is not protected by the optional HostPolicy. -// -// Because the fallback handler is run with unencrypted port 80 requests, -// the fallback should not serve TLS-only requests. -// -// If HTTPHandler is never called, the Manager will only use TLS SNI -// challenges for domain verification. -func (m *Manager) HTTPHandler(fallback http.Handler) http.Handler { - m.tokensMu.Lock() - defer m.tokensMu.Unlock() - m.tryHTTP01 = true - - if fallback == nil { - fallback = http.HandlerFunc(handleHTTPRedirect) - } - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !strings.HasPrefix(r.URL.Path, "/.well-known/acme-challenge/") { - fallback.ServeHTTP(w, r) - return - } - // A reasonable context timeout for cache and host policy only, - // because we don't wait for a new certificate issuance here. - ctx, cancel := context.WithTimeout(r.Context(), time.Minute) - defer cancel() - if err := m.hostPolicy()(ctx, r.Host); err != nil { - http.Error(w, err.Error(), http.StatusForbidden) - return - } - data, err := m.httpToken(ctx, r.URL.Path) - if err != nil { - http.Error(w, err.Error(), http.StatusNotFound) - return - } - w.Write(data) - }) -} - -func handleHTTPRedirect(w http.ResponseWriter, r *http.Request) { - if r.Method != "GET" && r.Method != "HEAD" { - http.Error(w, "Use HTTPS", http.StatusBadRequest) - return - } - target := "https://" + stripPort(r.Host) + r.URL.RequestURI() - http.Redirect(w, r, target, http.StatusFound) -} - -func stripPort(hostport string) string { - host, _, err := net.SplitHostPort(hostport) - if err != nil { - return hostport - } - return net.JoinHostPort(host, "443") -} - -// cert returns an existing certificate either from m.state or cache. -// If a certificate is found in cache but not in m.state, the latter will be filled -// with the cached value. -func (m *Manager) cert(ctx context.Context, ck certKey) (*tls.Certificate, error) { - m.stateMu.Lock() - if s, ok := m.state[ck]; ok { - m.stateMu.Unlock() - s.RLock() - defer s.RUnlock() - return s.tlscert() - } - defer m.stateMu.Unlock() - cert, err := m.cacheGet(ctx, ck) - if err != nil { - return nil, err - } - signer, ok := cert.PrivateKey.(crypto.Signer) - if !ok { - return nil, errors.New("acme/autocert: private key cannot sign") - } - if m.state == nil { - m.state = make(map[certKey]*certState) - } - s := &certState{ - key: signer, - cert: cert.Certificate, - leaf: cert.Leaf, - } - m.state[ck] = s - go m.renew(ck, s.key, s.leaf.NotAfter) - return cert, nil -} - -// cacheGet always returns a valid certificate, or an error otherwise. -// If a cached certificate exists but is not valid, ErrCacheMiss is returned. -func (m *Manager) cacheGet(ctx context.Context, ck certKey) (*tls.Certificate, error) { - if m.Cache == nil { - return nil, ErrCacheMiss - } - data, err := m.Cache.Get(ctx, ck.String()) - if err != nil { - return nil, err - } - - // private - priv, pub := pem.Decode(data) - if priv == nil || !strings.Contains(priv.Type, "PRIVATE") { - return nil, ErrCacheMiss - } - privKey, err := parsePrivateKey(priv.Bytes) - if err != nil { - return nil, err - } - - // public - var pubDER [][]byte - for len(pub) > 0 { - var b *pem.Block - b, pub = pem.Decode(pub) - if b == nil { - break - } - pubDER = append(pubDER, b.Bytes) - } - if len(pub) > 0 { - // Leftover content not consumed by pem.Decode. Corrupt. Ignore. - return nil, ErrCacheMiss - } - - // verify and create TLS cert - leaf, err := validCert(ck, pubDER, privKey) - if err != nil { - return nil, ErrCacheMiss - } - tlscert := &tls.Certificate{ - Certificate: pubDER, - PrivateKey: privKey, - Leaf: leaf, - } - return tlscert, nil -} - -func (m *Manager) cachePut(ctx context.Context, ck certKey, tlscert *tls.Certificate) error { - if m.Cache == nil { - return nil - } - - // contains PEM-encoded data - var buf bytes.Buffer - - // private - switch key := tlscert.PrivateKey.(type) { - case *ecdsa.PrivateKey: - if err := encodeECDSAKey(&buf, key); err != nil { - return err - } - case *rsa.PrivateKey: - b := x509.MarshalPKCS1PrivateKey(key) - pb := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: b} - if err := pem.Encode(&buf, pb); err != nil { - return err - } - default: - return errors.New("acme/autocert: unknown private key type") - } - - // public - for _, b := range tlscert.Certificate { - pb := &pem.Block{Type: "CERTIFICATE", Bytes: b} - if err := pem.Encode(&buf, pb); err != nil { - return err - } - } - - return m.Cache.Put(ctx, ck.String(), buf.Bytes()) -} - -func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error { - b, err := x509.MarshalECPrivateKey(key) - if err != nil { - return err - } - pb := &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} - return pem.Encode(w, pb) -} - -// createCert starts the domain ownership verification and returns a certificate -// for that domain upon success. -// -// If the domain is already being verified, it waits for the existing verification to complete. -// Either way, createCert blocks for the duration of the whole process. -func (m *Manager) createCert(ctx context.Context, ck certKey) (*tls.Certificate, error) { - // TODO: maybe rewrite this whole piece using sync.Once - state, err := m.certState(ck) - if err != nil { - return nil, err - } - // state may exist if another goroutine is already working on it - // in which case just wait for it to finish - if !state.locked { - state.RLock() - defer state.RUnlock() - return state.tlscert() - } - - // We are the first; state is locked. - // Unblock the readers when domain ownership is verified - // and we got the cert or the process failed. - defer state.Unlock() - state.locked = false - - der, leaf, err := m.authorizedCert(ctx, state.key, ck) - if err != nil { - // Remove the failed state after some time, - // making the manager call createCert again on the following TLS hello. - time.AfterFunc(createCertRetryAfter, func() { - defer testDidRemoveState(ck) - m.stateMu.Lock() - defer m.stateMu.Unlock() - // Verify the state hasn't changed and it's still invalid - // before deleting. - s, ok := m.state[ck] - if !ok { - return - } - if _, err := validCert(ck, s.cert, s.key); err == nil { - return - } - delete(m.state, ck) - }) - return nil, err - } - state.cert = der - state.leaf = leaf - go m.renew(ck, state.key, state.leaf.NotAfter) - return state.tlscert() -} - -// certState returns a new or existing certState. -// If a new certState is returned, state.exist is false and the state is locked. -// The returned error is non-nil only in the case where a new state could not be created. -func (m *Manager) certState(ck certKey) (*certState, error) { - m.stateMu.Lock() - defer m.stateMu.Unlock() - if m.state == nil { - m.state = make(map[certKey]*certState) - } - // existing state - if state, ok := m.state[ck]; ok { - return state, nil - } - - // new locked state - var ( - err error - key crypto.Signer - ) - if ck.isRSA { - key, err = rsa.GenerateKey(rand.Reader, 2048) - } else { - key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - } - if err != nil { - return nil, err - } - - state := &certState{ - key: key, - locked: true, - } - state.Lock() // will be unlocked by m.certState caller - m.state[ck] = state - return state, nil -} - -// authorizedCert starts the domain ownership verification process and requests a new cert upon success. -// The key argument is the certificate private key. -func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, ck certKey) (der [][]byte, leaf *x509.Certificate, err error) { - client, err := m.acmeClient(ctx) - if err != nil { - return nil, nil, err - } - - if err := m.verify(ctx, client, ck.domain); err != nil { - return nil, nil, err - } - csr, err := certRequest(key, ck.domain, m.ExtraExtensions) - if err != nil { - return nil, nil, err - } - der, _, err = client.CreateCert(ctx, csr, 0, true) - if err != nil { - return nil, nil, err - } - leaf, err = validCert(ck, der, key) - if err != nil { - return nil, nil, err - } - return der, leaf, nil -} - -// revokePendingAuthz revokes all authorizations idenfied by the elements of uri slice. -// It ignores revocation errors. -func (m *Manager) revokePendingAuthz(ctx context.Context, uri []string) { - client, err := m.acmeClient(ctx) - if err != nil { - return - } - for _, u := range uri { - client.RevokeAuthorization(ctx, u) - } -} - -// verify runs the identifier (domain) authorization flow -// using each applicable ACME challenge type. -func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string) error { - // The list of challenge types we'll try to fulfill - // in this specific order. - challengeTypes := []string{"tls-alpn-01", "tls-sni-02", "tls-sni-01"} - m.tokensMu.RLock() - if m.tryHTTP01 { - challengeTypes = append(challengeTypes, "http-01") - } - m.tokensMu.RUnlock() - - // Keep track of pending authzs and revoke the ones that did not validate. - pendingAuthzs := make(map[string]bool) - defer func() { - var uri []string - for k, pending := range pendingAuthzs { - if pending { - uri = append(uri, k) - } - } - if len(uri) > 0 { - // Use "detached" background context. - // The revocations need not happen in the current verification flow. - go m.revokePendingAuthz(context.Background(), uri) - } - }() - - // errs accumulates challenge failure errors, printed if all fail - errs := make(map[*acme.Challenge]error) - var nextTyp int // challengeType index of the next challenge type to try - for { - // Start domain authorization and get the challenge. - authz, err := client.Authorize(ctx, domain) - if err != nil { - return err - } - // No point in accepting challenges if the authorization status - // is in a final state. - switch authz.Status { - case acme.StatusValid: - return nil // already authorized - case acme.StatusInvalid: - return fmt.Errorf("acme/autocert: invalid authorization %q", authz.URI) - } - - pendingAuthzs[authz.URI] = true - - // Pick the next preferred challenge. - var chal *acme.Challenge - for chal == nil && nextTyp < len(challengeTypes) { - chal = pickChallenge(challengeTypes[nextTyp], authz.Challenges) - nextTyp++ - } - if chal == nil { - errorMsg := fmt.Sprintf("acme/autocert: unable to authorize %q", domain) - for chal, err := range errs { - errorMsg += fmt.Sprintf("; challenge %q failed with error: %v", chal.Type, err) - } - return errors.New(errorMsg) - } - cleanup, err := m.fulfill(ctx, client, chal, domain) - if err != nil { - errs[chal] = err - continue - } - defer cleanup() - if _, err := client.Accept(ctx, chal); err != nil { - errs[chal] = err - continue - } - - // A challenge is fulfilled and accepted: wait for the CA to validate. - if _, err := client.WaitAuthorization(ctx, authz.URI); err != nil { - errs[chal] = err - continue - } - delete(pendingAuthzs, authz.URI) - return nil - } -} - -// fulfill provisions a response to the challenge chal. -// The cleanup is non-nil only if provisioning succeeded. -func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.Challenge, domain string) (cleanup func(), err error) { - switch chal.Type { - case "tls-alpn-01": - cert, err := client.TLSALPN01ChallengeCert(chal.Token, domain) - if err != nil { - return nil, err - } - m.putCertToken(ctx, domain, &cert) - return func() { go m.deleteCertToken(domain) }, nil - case "tls-sni-01": - cert, name, err := client.TLSSNI01ChallengeCert(chal.Token) - if err != nil { - return nil, err - } - m.putCertToken(ctx, name, &cert) - return func() { go m.deleteCertToken(name) }, nil - case "tls-sni-02": - cert, name, err := client.TLSSNI02ChallengeCert(chal.Token) - if err != nil { - return nil, err - } - m.putCertToken(ctx, name, &cert) - return func() { go m.deleteCertToken(name) }, nil - case "http-01": - resp, err := client.HTTP01ChallengeResponse(chal.Token) - if err != nil { - return nil, err - } - p := client.HTTP01ChallengePath(chal.Token) - m.putHTTPToken(ctx, p, resp) - return func() { go m.deleteHTTPToken(p) }, nil - } - return nil, fmt.Errorf("acme/autocert: unknown challenge type %q", chal.Type) -} - -func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge { - for _, c := range chal { - if c.Type == typ { - return c - } - } - return nil -} - -// putCertToken stores the token certificate with the specified name -// in both m.certTokens map and m.Cache. -func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certificate) { - m.tokensMu.Lock() - defer m.tokensMu.Unlock() - if m.certTokens == nil { - m.certTokens = make(map[string]*tls.Certificate) - } - m.certTokens[name] = cert - m.cachePut(ctx, certKey{domain: name, isToken: true}, cert) -} - -// deleteCertToken removes the token certificate with the specified name -// from both m.certTokens map and m.Cache. -func (m *Manager) deleteCertToken(name string) { - m.tokensMu.Lock() - defer m.tokensMu.Unlock() - delete(m.certTokens, name) - if m.Cache != nil { - ck := certKey{domain: name, isToken: true} - m.Cache.Delete(context.Background(), ck.String()) - } -} - -// httpToken retrieves an existing http-01 token value from an in-memory map -// or the optional cache. -func (m *Manager) httpToken(ctx context.Context, tokenPath string) ([]byte, error) { - m.tokensMu.RLock() - defer m.tokensMu.RUnlock() - if v, ok := m.httpTokens[tokenPath]; ok { - return v, nil - } - if m.Cache == nil { - return nil, fmt.Errorf("acme/autocert: no token at %q", tokenPath) - } - return m.Cache.Get(ctx, httpTokenCacheKey(tokenPath)) -} - -// putHTTPToken stores an http-01 token value using tokenPath as key -// in both in-memory map and the optional Cache. -// -// It ignores any error returned from Cache.Put. -func (m *Manager) putHTTPToken(ctx context.Context, tokenPath, val string) { - m.tokensMu.Lock() - defer m.tokensMu.Unlock() - if m.httpTokens == nil { - m.httpTokens = make(map[string][]byte) - } - b := []byte(val) - m.httpTokens[tokenPath] = b - if m.Cache != nil { - m.Cache.Put(ctx, httpTokenCacheKey(tokenPath), b) - } -} - -// deleteHTTPToken removes an http-01 token value from both in-memory map -// and the optional Cache, ignoring any error returned from the latter. -// -// If m.Cache is non-nil, it blocks until Cache.Delete returns without a timeout. -func (m *Manager) deleteHTTPToken(tokenPath string) { - m.tokensMu.Lock() - defer m.tokensMu.Unlock() - delete(m.httpTokens, tokenPath) - if m.Cache != nil { - m.Cache.Delete(context.Background(), httpTokenCacheKey(tokenPath)) - } -} - -// httpTokenCacheKey returns a key at which an http-01 token value may be stored -// in the Manager's optional Cache. -func httpTokenCacheKey(tokenPath string) string { - return path.Base(tokenPath) + "+http-01" -} - -// renew starts a cert renewal timer loop, one per domain. -// -// The loop is scheduled in two cases: -// - a cert was fetched from cache for the first time (wasn't in m.state) -// - a new cert was created by m.createCert -// -// The key argument is a certificate private key. -// The exp argument is the cert expiration time (NotAfter). -func (m *Manager) renew(ck certKey, key crypto.Signer, exp time.Time) { - m.renewalMu.Lock() - defer m.renewalMu.Unlock() - if m.renewal[ck] != nil { - // another goroutine is already on it - return - } - if m.renewal == nil { - m.renewal = make(map[certKey]*domainRenewal) - } - dr := &domainRenewal{m: m, ck: ck, key: key} - m.renewal[ck] = dr - dr.start(exp) -} - -// stopRenew stops all currently running cert renewal timers. -// The timers are not restarted during the lifetime of the Manager. -func (m *Manager) stopRenew() { - m.renewalMu.Lock() - defer m.renewalMu.Unlock() - for name, dr := range m.renewal { - delete(m.renewal, name) - dr.stop() - } -} - -func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) { - const keyName = "acme_account+key" - - // Previous versions of autocert stored the value under a different key. - const legacyKeyName = "acme_account.key" - - genKey := func() (*ecdsa.PrivateKey, error) { - return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - } - - if m.Cache == nil { - return genKey() - } - - data, err := m.Cache.Get(ctx, keyName) - if err == ErrCacheMiss { - data, err = m.Cache.Get(ctx, legacyKeyName) - } - if err == ErrCacheMiss { - key, err := genKey() - if err != nil { - return nil, err - } - var buf bytes.Buffer - if err := encodeECDSAKey(&buf, key); err != nil { - return nil, err - } - if err := m.Cache.Put(ctx, keyName, buf.Bytes()); err != nil { - return nil, err - } - return key, nil - } - if err != nil { - return nil, err - } - - priv, _ := pem.Decode(data) - if priv == nil || !strings.Contains(priv.Type, "PRIVATE") { - return nil, errors.New("acme/autocert: invalid account key found in cache") - } - return parsePrivateKey(priv.Bytes) -} - -func (m *Manager) acmeClient(ctx context.Context) (*acme.Client, error) { - m.clientMu.Lock() - defer m.clientMu.Unlock() - if m.client != nil { - return m.client, nil - } - - client := m.Client - if client == nil { - client = &acme.Client{DirectoryURL: acme.LetsEncryptURL} - } - if client.Key == nil { - var err error - client.Key, err = m.accountKey(ctx) - if err != nil { - return nil, err - } - } - var contact []string - if m.Email != "" { - contact = []string{"mailto:" + m.Email} - } - a := &acme.Account{Contact: contact} - _, err := client.Register(ctx, a, m.Prompt) - if ae, ok := err.(*acme.Error); err == nil || ok && ae.StatusCode == http.StatusConflict { - // conflict indicates the key is already registered - m.client = client - err = nil - } - return m.client, err -} - -func (m *Manager) hostPolicy() HostPolicy { - if m.HostPolicy != nil { - return m.HostPolicy - } - return defaultHostPolicy -} - -func (m *Manager) renewBefore() time.Duration { - if m.RenewBefore > renewJitter { - return m.RenewBefore - } - return 720 * time.Hour // 30 days -} - -// certState is ready when its mutex is unlocked for reading. -type certState struct { - sync.RWMutex - locked bool // locked for read/write - key crypto.Signer // private key for cert - cert [][]byte // DER encoding - leaf *x509.Certificate // parsed cert[0]; always non-nil if cert != nil -} - -// tlscert creates a tls.Certificate from s.key and s.cert. -// Callers should wrap it in s.RLock() and s.RUnlock(). -func (s *certState) tlscert() (*tls.Certificate, error) { - if s.key == nil { - return nil, errors.New("acme/autocert: missing signer") - } - if len(s.cert) == 0 { - return nil, errors.New("acme/autocert: missing certificate") - } - return &tls.Certificate{ - PrivateKey: s.key, - Certificate: s.cert, - Leaf: s.leaf, - }, nil -} - -// certRequest generates a CSR for the given common name cn and optional SANs. -func certRequest(key crypto.Signer, cn string, ext []pkix.Extension, san ...string) ([]byte, error) { - req := &x509.CertificateRequest{ - Subject: pkix.Name{CommonName: cn}, - DNSNames: san, - ExtraExtensions: ext, - } - return x509.CreateCertificateRequest(rand.Reader, req, key) -} - -// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates -// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys. -// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three. -// -// Inspired by parsePrivateKey in crypto/tls/tls.go. -func parsePrivateKey(der []byte) (crypto.Signer, error) { - if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { - return key, nil - } - if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { - switch key := key.(type) { - case *rsa.PrivateKey: - return key, nil - case *ecdsa.PrivateKey: - return key, nil - default: - return nil, errors.New("acme/autocert: unknown private key type in PKCS#8 wrapping") - } - } - if key, err := x509.ParseECPrivateKey(der); err == nil { - return key, nil - } - - return nil, errors.New("acme/autocert: failed to parse private key") -} - -// validCert parses a cert chain provided as der argument and verifies the leaf and der[0] -// correspond to the private key, the domain and key type match, and expiration dates -// are valid. It doesn't do any revocation checking. -// -// The returned value is the verified leaf cert. -func validCert(ck certKey, der [][]byte, key crypto.Signer) (leaf *x509.Certificate, err error) { - // parse public part(s) - var n int - for _, b := range der { - n += len(b) - } - pub := make([]byte, n) - n = 0 - for _, b := range der { - n += copy(pub[n:], b) - } - x509Cert, err := x509.ParseCertificates(pub) - if err != nil || len(x509Cert) == 0 { - return nil, errors.New("acme/autocert: no public key found") - } - // verify the leaf is not expired and matches the domain name - leaf = x509Cert[0] - now := timeNow() - if now.Before(leaf.NotBefore) { - return nil, errors.New("acme/autocert: certificate is not valid yet") - } - if now.After(leaf.NotAfter) { - return nil, errors.New("acme/autocert: expired certificate") - } - if err := leaf.VerifyHostname(ck.domain); err != nil { - return nil, err - } - // ensure the leaf corresponds to the private key and matches the certKey type - switch pub := leaf.PublicKey.(type) { - case *rsa.PublicKey: - prv, ok := key.(*rsa.PrivateKey) - if !ok { - return nil, errors.New("acme/autocert: private key type does not match public key type") - } - if pub.N.Cmp(prv.N) != 0 { - return nil, errors.New("acme/autocert: private key does not match public key") - } - if !ck.isRSA && !ck.isToken { - return nil, errors.New("acme/autocert: key type does not match expected value") - } - case *ecdsa.PublicKey: - prv, ok := key.(*ecdsa.PrivateKey) - if !ok { - return nil, errors.New("acme/autocert: private key type does not match public key type") - } - if pub.X.Cmp(prv.X) != 0 || pub.Y.Cmp(prv.Y) != 0 { - return nil, errors.New("acme/autocert: private key does not match public key") - } - if ck.isRSA && !ck.isToken { - return nil, errors.New("acme/autocert: key type does not match expected value") - } - default: - return nil, errors.New("acme/autocert: unknown public key algorithm") - } - return leaf, nil -} - -type lockedMathRand struct { - sync.Mutex - rnd *mathrand.Rand -} - -func (r *lockedMathRand) int63n(max int64) int64 { - r.Lock() - n := r.rnd.Int63n(max) - r.Unlock() - return n -} - -// For easier testing. -var ( - timeNow = time.Now - - // Called when a state is removed. - testDidRemoveState = func(certKey) {} -) diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/autocert/cache.go b/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/autocert/cache.go deleted file mode 100755 index aa9aa84..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/autocert/cache.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package autocert - -import ( - "context" - "errors" - "io/ioutil" - "os" - "path/filepath" -) - -// ErrCacheMiss is returned when a certificate is not found in cache. -var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss") - -// Cache is used by Manager to store and retrieve previously obtained certificates -// and other account data as opaque blobs. -// -// Cache implementations should not rely on the key naming pattern. Keys can -// include any printable ASCII characters, except the following: \/:*?"<>| -type Cache interface { - // Get returns a certificate data for the specified key. - // If there's no such key, Get returns ErrCacheMiss. - Get(ctx context.Context, key string) ([]byte, error) - - // Put stores the data in the cache under the specified key. - // Underlying implementations may use any data storage format, - // as long as the reverse operation, Get, results in the original data. - Put(ctx context.Context, key string, data []byte) error - - // Delete removes a certificate data from the cache under the specified key. - // If there's no such key in the cache, Delete returns nil. - Delete(ctx context.Context, key string) error -} - -// DirCache implements Cache using a directory on the local filesystem. -// If the directory does not exist, it will be created with 0700 permissions. -type DirCache string - -// Get reads a certificate data from the specified file name. -func (d DirCache) Get(ctx context.Context, name string) ([]byte, error) { - name = filepath.Join(string(d), name) - var ( - data []byte - err error - done = make(chan struct{}) - ) - go func() { - data, err = ioutil.ReadFile(name) - close(done) - }() - select { - case <-ctx.Done(): - return nil, ctx.Err() - case <-done: - } - if os.IsNotExist(err) { - return nil, ErrCacheMiss - } - return data, err -} - -// Put writes the certificate data to the specified file name. -// The file will be created with 0600 permissions. -func (d DirCache) Put(ctx context.Context, name string, data []byte) error { - if err := os.MkdirAll(string(d), 0700); err != nil { - return err - } - - done := make(chan struct{}) - var err error - go func() { - defer close(done) - var tmp string - if tmp, err = d.writeTempFile(name, data); err != nil { - return - } - select { - case <-ctx.Done(): - // Don't overwrite the file if the context was canceled. - default: - newName := filepath.Join(string(d), name) - err = os.Rename(tmp, newName) - } - }() - select { - case <-ctx.Done(): - return ctx.Err() - case <-done: - } - return err -} - -// Delete removes the specified file name. -func (d DirCache) Delete(ctx context.Context, name string) error { - name = filepath.Join(string(d), name) - var ( - err error - done = make(chan struct{}) - ) - go func() { - err = os.Remove(name) - close(done) - }() - select { - case <-ctx.Done(): - return ctx.Err() - case <-done: - } - if err != nil && !os.IsNotExist(err) { - return err - } - return nil -} - -// writeTempFile writes b to a temporary file, closes the file and returns its path. -func (d DirCache) writeTempFile(prefix string, b []byte) (string, error) { - // TempFile uses 0600 permissions - f, err := ioutil.TempFile(string(d), prefix) - if err != nil { - return "", err - } - if _, err := f.Write(b); err != nil { - f.Close() - return "", err - } - return f.Name(), f.Close() -} diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/autocert/listener.go b/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/autocert/listener.go deleted file mode 100755 index 1e06981..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/autocert/listener.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package autocert - -import ( - "crypto/tls" - "log" - "net" - "os" - "path/filepath" - "runtime" - "time" -) - -// NewListener returns a net.Listener that listens on the standard TLS -// port (443) on all interfaces and returns *tls.Conn connections with -// LetsEncrypt certificates for the provided domain or domains. -// -// It enables one-line HTTPS servers: -// -// log.Fatal(http.Serve(autocert.NewListener("example.com"), handler)) -// -// NewListener is a convenience function for a common configuration. -// More complex or custom configurations can use the autocert.Manager -// type instead. -// -// Use of this function implies acceptance of the LetsEncrypt Terms of -// Service. If domains is not empty, the provided domains are passed -// to HostWhitelist. If domains is empty, the listener will do -// LetsEncrypt challenges for any requested domain, which is not -// recommended. -// -// Certificates are cached in a "golang-autocert" directory under an -// operating system-specific cache or temp directory. This may not -// be suitable for servers spanning multiple machines. -// -// The returned listener uses a *tls.Config that enables HTTP/2, and -// should only be used with servers that support HTTP/2. -// -// The returned Listener also enables TCP keep-alives on the accepted -// connections. The returned *tls.Conn are returned before their TLS -// handshake has completed. -func NewListener(domains ...string) net.Listener { - m := &Manager{ - Prompt: AcceptTOS, - } - if len(domains) > 0 { - m.HostPolicy = HostWhitelist(domains...) - } - dir := cacheDir() - if err := os.MkdirAll(dir, 0700); err != nil { - log.Printf("warning: autocert.NewListener not using a cache: %v", err) - } else { - m.Cache = DirCache(dir) - } - return m.Listener() -} - -// Listener listens on the standard TLS port (443) on all interfaces -// and returns a net.Listener returning *tls.Conn connections. -// -// The returned listener uses a *tls.Config that enables HTTP/2, and -// should only be used with servers that support HTTP/2. -// -// The returned Listener also enables TCP keep-alives on the accepted -// connections. The returned *tls.Conn are returned before their TLS -// handshake has completed. -// -// Unlike NewListener, it is the caller's responsibility to initialize -// the Manager m's Prompt, Cache, HostPolicy, and other desired options. -func (m *Manager) Listener() net.Listener { - ln := &listener{ - m: m, - conf: m.TLSConfig(), - } - ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443") - return ln -} - -type listener struct { - m *Manager - conf *tls.Config - - tcpListener net.Listener - tcpListenErr error -} - -func (ln *listener) Accept() (net.Conn, error) { - if ln.tcpListenErr != nil { - return nil, ln.tcpListenErr - } - conn, err := ln.tcpListener.Accept() - if err != nil { - return nil, err - } - tcpConn := conn.(*net.TCPConn) - - // Because Listener is a convenience function, help out with - // this too. This is not possible for the caller to set once - // we return a *tcp.Conn wrapping an inaccessible net.Conn. - // If callers don't want this, they can do things the manual - // way and tweak as needed. But this is what net/http does - // itself, so copy that. If net/http changes, we can change - // here too. - tcpConn.SetKeepAlive(true) - tcpConn.SetKeepAlivePeriod(3 * time.Minute) - - return tls.Server(tcpConn, ln.conf), nil -} - -func (ln *listener) Addr() net.Addr { - if ln.tcpListener != nil { - return ln.tcpListener.Addr() - } - // net.Listen failed. Return something non-nil in case callers - // call Addr before Accept: - return &net.TCPAddr{IP: net.IP{0, 0, 0, 0}, Port: 443} -} - -func (ln *listener) Close() error { - if ln.tcpListenErr != nil { - return ln.tcpListenErr - } - return ln.tcpListener.Close() -} - -func homeDir() string { - if runtime.GOOS == "windows" { - return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") - } - if h := os.Getenv("HOME"); h != "" { - return h - } - return "/" -} - -func cacheDir() string { - const base = "golang-autocert" - switch runtime.GOOS { - case "darwin": - return filepath.Join(homeDir(), "Library", "Caches", base) - case "windows": - for _, ev := range []string{"APPDATA", "CSIDL_APPDATA", "TEMP", "TMP"} { - if v := os.Getenv(ev); v != "" { - return filepath.Join(v, base) - } - } - // Worst case: - return filepath.Join(homeDir(), base) - } - if xdg := os.Getenv("XDG_CACHE_HOME"); xdg != "" { - return filepath.Join(xdg, base) - } - return filepath.Join(homeDir(), ".cache", base) -} diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/autocert/renewal.go b/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/autocert/renewal.go deleted file mode 100755 index ef3e44e..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/autocert/renewal.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package autocert - -import ( - "context" - "crypto" - "sync" - "time" -) - -// renewJitter is the maximum deviation from Manager.RenewBefore. -const renewJitter = time.Hour - -// domainRenewal tracks the state used by the periodic timers -// renewing a single domain's cert. -type domainRenewal struct { - m *Manager - ck certKey - key crypto.Signer - - timerMu sync.Mutex - timer *time.Timer -} - -// start starts a cert renewal timer at the time -// defined by the certificate expiration time exp. -// -// If the timer is already started, calling start is a noop. -func (dr *domainRenewal) start(exp time.Time) { - dr.timerMu.Lock() - defer dr.timerMu.Unlock() - if dr.timer != nil { - return - } - dr.timer = time.AfterFunc(dr.next(exp), dr.renew) -} - -// stop stops the cert renewal timer. -// If the timer is already stopped, calling stop is a noop. -func (dr *domainRenewal) stop() { - dr.timerMu.Lock() - defer dr.timerMu.Unlock() - if dr.timer == nil { - return - } - dr.timer.Stop() - dr.timer = nil -} - -// renew is called periodically by a timer. -// The first renew call is kicked off by dr.start. -func (dr *domainRenewal) renew() { - dr.timerMu.Lock() - defer dr.timerMu.Unlock() - if dr.timer == nil { - return - } - - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) - defer cancel() - // TODO: rotate dr.key at some point? - next, err := dr.do(ctx) - if err != nil { - next = renewJitter / 2 - next += time.Duration(pseudoRand.int63n(int64(next))) - } - dr.timer = time.AfterFunc(next, dr.renew) - testDidRenewLoop(next, err) -} - -// updateState locks and replaces the relevant Manager.state item with the given -// state. It additionally updates dr.key with the given state's key. -func (dr *domainRenewal) updateState(state *certState) { - dr.m.stateMu.Lock() - defer dr.m.stateMu.Unlock() - dr.key = state.key - dr.m.state[dr.ck] = state -} - -// do is similar to Manager.createCert but it doesn't lock a Manager.state item. -// Instead, it requests a new certificate independently and, upon success, -// replaces dr.m.state item with a new one and updates cache for the given domain. -// -// It may lock and update the Manager.state if the expiration date of the currently -// cached cert is far enough in the future. -// -// The returned value is a time interval after which the renewal should occur again. -func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) { - // a race is likely unavoidable in a distributed environment - // but we try nonetheless - if tlscert, err := dr.m.cacheGet(ctx, dr.ck); err == nil { - next := dr.next(tlscert.Leaf.NotAfter) - if next > dr.m.renewBefore()+renewJitter { - signer, ok := tlscert.PrivateKey.(crypto.Signer) - if ok { - state := &certState{ - key: signer, - cert: tlscert.Certificate, - leaf: tlscert.Leaf, - } - dr.updateState(state) - return next, nil - } - } - } - - der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.ck) - if err != nil { - return 0, err - } - state := &certState{ - key: dr.key, - cert: der, - leaf: leaf, - } - tlscert, err := state.tlscert() - if err != nil { - return 0, err - } - if err := dr.m.cachePut(ctx, dr.ck, tlscert); err != nil { - return 0, err - } - dr.updateState(state) - return dr.next(leaf.NotAfter), nil -} - -func (dr *domainRenewal) next(expiry time.Time) time.Duration { - d := expiry.Sub(timeNow()) - dr.m.renewBefore() - // add a bit of randomness to renew deadline - n := pseudoRand.int63n(int64(renewJitter)) - d -= time.Duration(n) - if d < 0 { - return 0 - } - return d -} - -var testDidRenewLoop = func(next time.Duration, err error) {} diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/http.go b/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/http.go deleted file mode 100755 index a43ce6a..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/http.go +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package acme - -import ( - "bytes" - "context" - "crypto" - "crypto/rand" - "encoding/json" - "fmt" - "io/ioutil" - "math/big" - "net/http" - "strconv" - "strings" - "time" -) - -// retryTimer encapsulates common logic for retrying unsuccessful requests. -// It is not safe for concurrent use. -type retryTimer struct { - // backoffFn provides backoff delay sequence for retries. - // See Client.RetryBackoff doc comment. - backoffFn func(n int, r *http.Request, res *http.Response) time.Duration - // n is the current retry attempt. - n int -} - -func (t *retryTimer) inc() { - t.n++ -} - -// backoff pauses the current goroutine as described in Client.RetryBackoff. -func (t *retryTimer) backoff(ctx context.Context, r *http.Request, res *http.Response) error { - d := t.backoffFn(t.n, r, res) - if d <= 0 { - return fmt.Errorf("acme: no more retries for %s; tried %d time(s)", r.URL, t.n) - } - wakeup := time.NewTimer(d) - defer wakeup.Stop() - select { - case <-ctx.Done(): - return ctx.Err() - case <-wakeup.C: - return nil - } -} - -func (c *Client) retryTimer() *retryTimer { - f := c.RetryBackoff - if f == nil { - f = defaultBackoff - } - return &retryTimer{backoffFn: f} -} - -// defaultBackoff provides default Client.RetryBackoff implementation -// using a truncated exponential backoff algorithm, -// as described in Client.RetryBackoff. -// -// The n argument is always bounded between 1 and 30. -// The returned value is always greater than 0. -func defaultBackoff(n int, r *http.Request, res *http.Response) time.Duration { - const max = 10 * time.Second - var jitter time.Duration - if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil { - // Set the minimum to 1ms to avoid a case where - // an invalid Retry-After value is parsed into 0 below, - // resulting in the 0 returned value which would unintentionally - // stop the retries. - jitter = (1 + time.Duration(x.Int64())) * time.Millisecond - } - if v, ok := res.Header["Retry-After"]; ok { - return retryAfter(v[0]) + jitter - } - - if n < 1 { - n = 1 - } - if n > 30 { - n = 30 - } - d := time.Duration(1< max { - return max - } - return d -} - -// retryAfter parses a Retry-After HTTP header value, -// trying to convert v into an int (seconds) or use http.ParseTime otherwise. -// It returns zero value if v cannot be parsed. -func retryAfter(v string) time.Duration { - if i, err := strconv.Atoi(v); err == nil { - return time.Duration(i) * time.Second - } - t, err := http.ParseTime(v) - if err != nil { - return 0 - } - return t.Sub(timeNow()) -} - -// resOkay is a function that reports whether the provided response is okay. -// It is expected to keep the response body unread. -type resOkay func(*http.Response) bool - -// wantStatus returns a function which reports whether the code -// matches the status code of a response. -func wantStatus(codes ...int) resOkay { - return func(res *http.Response) bool { - for _, code := range codes { - if code == res.StatusCode { - return true - } - } - return false - } -} - -// get issues an unsigned GET request to the specified URL. -// It returns a non-error value only when ok reports true. -// -// get retries unsuccessful attempts according to c.RetryBackoff -// until the context is done or a non-retriable error is received. -func (c *Client) get(ctx context.Context, url string, ok resOkay) (*http.Response, error) { - retry := c.retryTimer() - for { - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return nil, err - } - res, err := c.doNoRetry(ctx, req) - switch { - case err != nil: - return nil, err - case ok(res): - return res, nil - case isRetriable(res.StatusCode): - retry.inc() - resErr := responseError(res) - res.Body.Close() - // Ignore the error value from retry.backoff - // and return the one from last retry, as received from the CA. - if retry.backoff(ctx, req, res) != nil { - return nil, resErr - } - default: - defer res.Body.Close() - return nil, responseError(res) - } - } -} - -// post issues a signed POST request in JWS format using the provided key -// to the specified URL. -// It returns a non-error value only when ok reports true. -// -// post retries unsuccessful attempts according to c.RetryBackoff -// until the context is done or a non-retriable error is received. -// It uses postNoRetry to make individual requests. -func (c *Client) post(ctx context.Context, key crypto.Signer, url string, body interface{}, ok resOkay) (*http.Response, error) { - retry := c.retryTimer() - for { - res, req, err := c.postNoRetry(ctx, key, url, body) - if err != nil { - return nil, err - } - if ok(res) { - return res, nil - } - resErr := responseError(res) - res.Body.Close() - switch { - // Check for bad nonce before isRetriable because it may have been returned - // with an unretriable response code such as 400 Bad Request. - case isBadNonce(resErr): - // Consider any previously stored nonce values to be invalid. - c.clearNonces() - case !isRetriable(res.StatusCode): - return nil, resErr - } - retry.inc() - // Ignore the error value from retry.backoff - // and return the one from last retry, as received from the CA. - if err := retry.backoff(ctx, req, res); err != nil { - return nil, resErr - } - } -} - -// postNoRetry signs the body with the given key and POSTs it to the provided url. -// The body argument must be JSON-serializable. -// It is used by c.post to retry unsuccessful attempts. -func (c *Client) postNoRetry(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, *http.Request, error) { - nonce, err := c.popNonce(ctx, url) - if err != nil { - return nil, nil, err - } - b, err := jwsEncodeJSON(body, key, nonce) - if err != nil { - return nil, nil, err - } - req, err := http.NewRequest("POST", url, bytes.NewReader(b)) - if err != nil { - return nil, nil, err - } - req.Header.Set("Content-Type", "application/jose+json") - res, err := c.doNoRetry(ctx, req) - if err != nil { - return nil, nil, err - } - c.addNonce(res.Header) - return res, req, nil -} - -// doNoRetry issues a request req, replacing its context (if any) with ctx. -func (c *Client) doNoRetry(ctx context.Context, req *http.Request) (*http.Response, error) { - res, err := c.httpClient().Do(req.WithContext(ctx)) - if err != nil { - select { - case <-ctx.Done(): - // Prefer the unadorned context error. - // (The acme package had tests assuming this, previously from ctxhttp's - // behavior, predating net/http supporting contexts natively) - // TODO(bradfitz): reconsider this in the future. But for now this - // requires no test updates. - return nil, ctx.Err() - default: - return nil, err - } - } - return res, nil -} - -func (c *Client) httpClient() *http.Client { - if c.HTTPClient != nil { - return c.HTTPClient - } - return http.DefaultClient -} - -// isBadNonce reports whether err is an ACME "badnonce" error. -func isBadNonce(err error) bool { - // According to the spec badNonce is urn:ietf:params:acme:error:badNonce. - // However, ACME servers in the wild return their versions of the error. - // See https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-5.4 - // and https://github.com/letsencrypt/boulder/blob/0e07eacb/docs/acme-divergences.md#section-66. - ae, ok := err.(*Error) - return ok && strings.HasSuffix(strings.ToLower(ae.ProblemType), ":badnonce") -} - -// isRetriable reports whether a request can be retried -// based on the response status code. -// -// Note that a "bad nonce" error is returned with a non-retriable 400 Bad Request code. -// Callers should parse the response and check with isBadNonce. -func isRetriable(code int) bool { - return code <= 399 || code >= 500 || code == http.StatusTooManyRequests -} - -// responseError creates an error of Error type from resp. -func responseError(resp *http.Response) error { - // don't care if ReadAll returns an error: - // json.Unmarshal will fail in that case anyway - b, _ := ioutil.ReadAll(resp.Body) - e := &wireError{Status: resp.StatusCode} - if err := json.Unmarshal(b, e); err != nil { - // this is not a regular error response: - // populate detail with anything we received, - // e.Status will already contain HTTP response code value - e.Detail = string(b) - if e.Detail == "" { - e.Detail = resp.Status - } - } - return e.error(resp.Header) -} diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/jws.go b/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/jws.go deleted file mode 100755 index 6cbca25..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/jws.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package acme - -import ( - "crypto" - "crypto/ecdsa" - "crypto/rand" - "crypto/rsa" - "crypto/sha256" - _ "crypto/sha512" // need for EC keys - "encoding/base64" - "encoding/json" - "fmt" - "math/big" -) - -// jwsEncodeJSON signs claimset using provided key and a nonce. -// The result is serialized in JSON format. -// See https://tools.ietf.org/html/rfc7515#section-7. -func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byte, error) { - jwk, err := jwkEncode(key.Public()) - if err != nil { - return nil, err - } - alg, sha := jwsHasher(key) - if alg == "" || !sha.Available() { - return nil, ErrUnsupportedKey - } - phead := fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q}`, alg, jwk, nonce) - phead = base64.RawURLEncoding.EncodeToString([]byte(phead)) - cs, err := json.Marshal(claimset) - if err != nil { - return nil, err - } - payload := base64.RawURLEncoding.EncodeToString(cs) - hash := sha.New() - hash.Write([]byte(phead + "." + payload)) - sig, err := jwsSign(key, sha, hash.Sum(nil)) - if err != nil { - return nil, err - } - - enc := struct { - Protected string `json:"protected"` - Payload string `json:"payload"` - Sig string `json:"signature"` - }{ - Protected: phead, - Payload: payload, - Sig: base64.RawURLEncoding.EncodeToString(sig), - } - return json.Marshal(&enc) -} - -// jwkEncode encodes public part of an RSA or ECDSA key into a JWK. -// The result is also suitable for creating a JWK thumbprint. -// https://tools.ietf.org/html/rfc7517 -func jwkEncode(pub crypto.PublicKey) (string, error) { - switch pub := pub.(type) { - case *rsa.PublicKey: - // https://tools.ietf.org/html/rfc7518#section-6.3.1 - n := pub.N - e := big.NewInt(int64(pub.E)) - // Field order is important. - // See https://tools.ietf.org/html/rfc7638#section-3.3 for details. - return fmt.Sprintf(`{"e":"%s","kty":"RSA","n":"%s"}`, - base64.RawURLEncoding.EncodeToString(e.Bytes()), - base64.RawURLEncoding.EncodeToString(n.Bytes()), - ), nil - case *ecdsa.PublicKey: - // https://tools.ietf.org/html/rfc7518#section-6.2.1 - p := pub.Curve.Params() - n := p.BitSize / 8 - if p.BitSize%8 != 0 { - n++ - } - x := pub.X.Bytes() - if n > len(x) { - x = append(make([]byte, n-len(x)), x...) - } - y := pub.Y.Bytes() - if n > len(y) { - y = append(make([]byte, n-len(y)), y...) - } - // Field order is important. - // See https://tools.ietf.org/html/rfc7638#section-3.3 for details. - return fmt.Sprintf(`{"crv":"%s","kty":"EC","x":"%s","y":"%s"}`, - p.Name, - base64.RawURLEncoding.EncodeToString(x), - base64.RawURLEncoding.EncodeToString(y), - ), nil - } - return "", ErrUnsupportedKey -} - -// jwsSign signs the digest using the given key. -// It returns ErrUnsupportedKey if the key type is unknown. -// The hash is used only for RSA keys. -func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) { - switch key := key.(type) { - case *rsa.PrivateKey: - return key.Sign(rand.Reader, digest, hash) - case *ecdsa.PrivateKey: - r, s, err := ecdsa.Sign(rand.Reader, key, digest) - if err != nil { - return nil, err - } - rb, sb := r.Bytes(), s.Bytes() - size := key.Params().BitSize / 8 - if size%8 > 0 { - size++ - } - sig := make([]byte, size*2) - copy(sig[size-len(rb):], rb) - copy(sig[size*2-len(sb):], sb) - return sig, nil - } - return nil, ErrUnsupportedKey -} - -// jwsHasher indicates suitable JWS algorithm name and a hash function -// to use for signing a digest with the provided key. -// It returns ("", 0) if the key is not supported. -func jwsHasher(key crypto.Signer) (string, crypto.Hash) { - switch key := key.(type) { - case *rsa.PrivateKey: - return "RS256", crypto.SHA256 - case *ecdsa.PrivateKey: - switch key.Params().Name { - case "P-256": - return "ES256", crypto.SHA256 - case "P-384": - return "ES384", crypto.SHA384 - case "P-521": - return "ES512", crypto.SHA512 - } - } - return "", 0 -} - -// JWKThumbprint creates a JWK thumbprint out of pub -// as specified in https://tools.ietf.org/html/rfc7638. -func JWKThumbprint(pub crypto.PublicKey) (string, error) { - jwk, err := jwkEncode(pub) - if err != nil { - return "", err - } - b := sha256.Sum256([]byte(jwk)) - return base64.RawURLEncoding.EncodeToString(b[:]), nil -} diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/types.go b/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/types.go deleted file mode 100755 index 54792c0..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/acme/types.go +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package acme - -import ( - "crypto" - "crypto/x509" - "errors" - "fmt" - "net/http" - "strings" - "time" -) - -// ACME server response statuses used to describe Authorization and Challenge states. -const ( - StatusUnknown = "unknown" - StatusPending = "pending" - StatusProcessing = "processing" - StatusValid = "valid" - StatusInvalid = "invalid" - StatusRevoked = "revoked" -) - -// CRLReasonCode identifies the reason for a certificate revocation. -type CRLReasonCode int - -// CRL reason codes as defined in RFC 5280. -const ( - CRLReasonUnspecified CRLReasonCode = 0 - CRLReasonKeyCompromise CRLReasonCode = 1 - CRLReasonCACompromise CRLReasonCode = 2 - CRLReasonAffiliationChanged CRLReasonCode = 3 - CRLReasonSuperseded CRLReasonCode = 4 - CRLReasonCessationOfOperation CRLReasonCode = 5 - CRLReasonCertificateHold CRLReasonCode = 6 - CRLReasonRemoveFromCRL CRLReasonCode = 8 - CRLReasonPrivilegeWithdrawn CRLReasonCode = 9 - CRLReasonAACompromise CRLReasonCode = 10 -) - -// ErrUnsupportedKey is returned when an unsupported key type is encountered. -var ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported") - -// Error is an ACME error, defined in Problem Details for HTTP APIs doc -// http://tools.ietf.org/html/draft-ietf-appsawg-http-problem. -type Error struct { - // StatusCode is The HTTP status code generated by the origin server. - StatusCode int - // ProblemType is a URI reference that identifies the problem type, - // typically in a "urn:acme:error:xxx" form. - ProblemType string - // Detail is a human-readable explanation specific to this occurrence of the problem. - Detail string - // Header is the original server error response headers. - // It may be nil. - Header http.Header -} - -func (e *Error) Error() string { - return fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail) -} - -// AuthorizationError indicates that an authorization for an identifier -// did not succeed. -// It contains all errors from Challenge items of the failed Authorization. -type AuthorizationError struct { - // URI uniquely identifies the failed Authorization. - URI string - - // Identifier is an AuthzID.Value of the failed Authorization. - Identifier string - - // Errors is a collection of non-nil error values of Challenge items - // of the failed Authorization. - Errors []error -} - -func (a *AuthorizationError) Error() string { - e := make([]string, len(a.Errors)) - for i, err := range a.Errors { - e[i] = err.Error() - } - return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; ")) -} - -// RateLimit reports whether err represents a rate limit error and -// any Retry-After duration returned by the server. -// -// See the following for more details on rate limiting: -// https://tools.ietf.org/html/draft-ietf-acme-acme-05#section-5.6 -func RateLimit(err error) (time.Duration, bool) { - e, ok := err.(*Error) - if !ok { - return 0, false - } - // Some CA implementations may return incorrect values. - // Use case-insensitive comparison. - if !strings.HasSuffix(strings.ToLower(e.ProblemType), ":ratelimited") { - return 0, false - } - if e.Header == nil { - return 0, true - } - return retryAfter(e.Header.Get("Retry-After")), true -} - -// Account is a user account. It is associated with a private key. -type Account struct { - // URI is the account unique ID, which is also a URL used to retrieve - // account data from the CA. - URI string - - // Contact is a slice of contact info used during registration. - Contact []string - - // The terms user has agreed to. - // A value not matching CurrentTerms indicates that the user hasn't agreed - // to the actual Terms of Service of the CA. - AgreedTerms string - - // Actual terms of a CA. - CurrentTerms string - - // Authz is the authorization URL used to initiate a new authz flow. - Authz string - - // Authorizations is a URI from which a list of authorizations - // granted to this account can be fetched via a GET request. - Authorizations string - - // Certificates is a URI from which a list of certificates - // issued for this account can be fetched via a GET request. - Certificates string -} - -// Directory is ACME server discovery data. -type Directory struct { - // RegURL is an account endpoint URL, allowing for creating new - // and modifying existing accounts. - RegURL string - - // AuthzURL is used to initiate Identifier Authorization flow. - AuthzURL string - - // CertURL is a new certificate issuance endpoint URL. - CertURL string - - // RevokeURL is used to initiate a certificate revocation flow. - RevokeURL string - - // Term is a URI identifying the current terms of service. - Terms string - - // Website is an HTTP or HTTPS URL locating a website - // providing more information about the ACME server. - Website string - - // CAA consists of lowercase hostname elements, which the ACME server - // recognises as referring to itself for the purposes of CAA record validation - // as defined in RFC6844. - CAA []string -} - -// Challenge encodes a returned CA challenge. -// Its Error field may be non-nil if the challenge is part of an Authorization -// with StatusInvalid. -type Challenge struct { - // Type is the challenge type, e.g. "http-01", "tls-sni-02", "dns-01". - Type string - - // URI is where a challenge response can be posted to. - URI string - - // Token is a random value that uniquely identifies the challenge. - Token string - - // Status identifies the status of this challenge. - Status string - - // Error indicates the reason for an authorization failure - // when this challenge was used. - // The type of a non-nil value is *Error. - Error error -} - -// Authorization encodes an authorization response. -type Authorization struct { - // URI uniquely identifies a authorization. - URI string - - // Status identifies the status of an authorization. - Status string - - // Identifier is what the account is authorized to represent. - Identifier AuthzID - - // Challenges that the client needs to fulfill in order to prove possession - // of the identifier (for pending authorizations). - // For final authorizations, the challenges that were used. - Challenges []*Challenge - - // A collection of sets of challenges, each of which would be sufficient - // to prove possession of the identifier. - // Clients must complete a set of challenges that covers at least one set. - // Challenges are identified by their indices in the challenges array. - // If this field is empty, the client needs to complete all challenges. - Combinations [][]int -} - -// AuthzID is an identifier that an account is authorized to represent. -type AuthzID struct { - Type string // The type of identifier, e.g. "dns". - Value string // The identifier itself, e.g. "example.org". -} - -// wireAuthz is ACME JSON representation of Authorization objects. -type wireAuthz struct { - Status string - Challenges []wireChallenge - Combinations [][]int - Identifier struct { - Type string - Value string - } -} - -func (z *wireAuthz) authorization(uri string) *Authorization { - a := &Authorization{ - URI: uri, - Status: z.Status, - Identifier: AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value}, - Combinations: z.Combinations, // shallow copy - Challenges: make([]*Challenge, len(z.Challenges)), - } - for i, v := range z.Challenges { - a.Challenges[i] = v.challenge() - } - return a -} - -func (z *wireAuthz) error(uri string) *AuthorizationError { - err := &AuthorizationError{ - URI: uri, - Identifier: z.Identifier.Value, - } - for _, raw := range z.Challenges { - if raw.Error != nil { - err.Errors = append(err.Errors, raw.Error.error(nil)) - } - } - return err -} - -// wireChallenge is ACME JSON challenge representation. -type wireChallenge struct { - URI string `json:"uri"` - Type string - Token string - Status string - Error *wireError -} - -func (c *wireChallenge) challenge() *Challenge { - v := &Challenge{ - URI: c.URI, - Type: c.Type, - Token: c.Token, - Status: c.Status, - } - if v.Status == "" { - v.Status = StatusPending - } - if c.Error != nil { - v.Error = c.Error.error(nil) - } - return v -} - -// wireError is a subset of fields of the Problem Details object -// as described in https://tools.ietf.org/html/rfc7807#section-3.1. -type wireError struct { - Status int - Type string - Detail string -} - -func (e *wireError) error(h http.Header) *Error { - return &Error{ - StatusCode: e.Status, - ProblemType: e.Type, - Detail: e.Detail, - Header: h, - } -} - -// CertOption is an optional argument type for the TLS ChallengeCert methods for -// customizing a temporary certificate for TLS-based challenges. -type CertOption interface { - privateCertOpt() -} - -// WithKey creates an option holding a private/public key pair. -// The private part signs a certificate, and the public part represents the signee. -func WithKey(key crypto.Signer) CertOption { - return &certOptKey{key} -} - -type certOptKey struct { - key crypto.Signer -} - -func (*certOptKey) privateCertOpt() {} - -// WithTemplate creates an option for specifying a certificate template. -// See x509.CreateCertificate for template usage details. -// -// In TLS ChallengeCert methods, the template is also used as parent, -// resulting in a self-signed certificate. -// The DNSNames field of t is always overwritten for tls-sni challenge certs. -func WithTemplate(t *x509.Certificate) CertOption { - return (*certOptTemplate)(t) -} - -type certOptTemplate x509.Certificate - -func (*certOptTemplate) privateCertOpt() {} diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go b/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go deleted file mode 100755 index 593f653..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC -2898 / PKCS #5 v2.0. - -A key derivation function is useful when encrypting data based on a password -or any other not-fully-random data. It uses a pseudorandom function to derive -a secure encryption key based on the password. - -While v2.0 of the standard defines only one pseudorandom function to use, -HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved -Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To -choose, you can pass the `New` functions from the different SHA packages to -pbkdf2.Key. -*/ -package pbkdf2 // import "golang.org/x/crypto/pbkdf2" - -import ( - "crypto/hmac" - "hash" -) - -// Key derives a key from the password, salt and iteration count, returning a -// []byte of length keylen that can be used as cryptographic key. The key is -// derived based on the method described as PBKDF2 with the HMAC variant using -// the supplied hash function. -// -// For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you -// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by -// doing: -// -// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New) -// -// Remember to get a good random salt. At least 8 bytes is recommended by the -// RFC. -// -// Using a higher iteration count will increase the cost of an exhaustive -// search but will also make derivation proportionally slower. -func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte { - prf := hmac.New(h, password) - hashLen := prf.Size() - numBlocks := (keyLen + hashLen - 1) / hashLen - - var buf [4]byte - dk := make([]byte, 0, numBlocks*hashLen) - U := make([]byte, hashLen) - for block := 1; block <= numBlocks; block++ { - // N.B.: || means concatenation, ^ means XOR - // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter - // U_1 = PRF(password, salt || uint(i)) - prf.Reset() - prf.Write(salt) - buf[0] = byte(block >> 24) - buf[1] = byte(block >> 16) - buf[2] = byte(block >> 8) - buf[3] = byte(block) - prf.Write(buf[:4]) - dk = prf.Sum(dk) - T := dk[len(dk)-hashLen:] - copy(U, T) - - // U_n = PRF(password, U_(n-1)) - for n := 2; n <= iter; n++ { - prf.Reset() - prf.Write(U) - U = U[:0] - U = prf.Sum(U) - for x := range U { - T[x] ^= U[x] - } - } - } - return dk[:keyLen] -} diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/net/LICENSE b/vender/github.com/astaxie/beego/vendor/golang.org/x/net/LICENSE deleted file mode 100755 index 6a66aea..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/net/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/net/PATENTS b/vender/github.com/astaxie/beego/vendor/golang.org/x/net/PATENTS deleted file mode 100755 index 7330990..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/net/PATENTS +++ /dev/null @@ -1,22 +0,0 @@ -Additional IP Rights Grant (Patents) - -"This implementation" means the copyrightable works distributed by -Google as part of the Go project. - -Google hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) -patent license to make, have made, use, offer to sell, sell, import, -transfer and otherwise run, modify and propagate the contents of this -implementation of Go, where such license applies only to those patent -claims, both currently owned or controlled by Google and acquired in -the future, licensable by Google that are necessarily infringed by this -implementation of Go. This grant does not include claims that would be -infringed only as a consequence of further modification of this -implementation. If you or your agent or exclusive licensee institute or -order or agree to the institution of patent litigation against any -entity (including a cross-claim or counterclaim in a lawsuit) alleging -that this implementation of Go or any code incorporated within this -implementation of Go constitutes direct or contributory patent -infringement, or inducement of patent infringement, then any patent -rights granted to you under this License for this implementation of Go -shall terminate as of the date such litigation is filed. diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/context.go b/vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/context.go deleted file mode 100755 index d3681ab..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/context.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package context defines the Context type, which carries deadlines, -// cancelation signals, and other request-scoped values across API boundaries -// and between processes. -// -// Incoming requests to a server should create a Context, and outgoing calls to -// servers should accept a Context. The chain of function calls between must -// propagate the Context, optionally replacing it with a modified copy created -// using WithDeadline, WithTimeout, WithCancel, or WithValue. -// -// Programs that use Contexts should follow these rules to keep interfaces -// consistent across packages and enable static analysis tools to check context -// propagation: -// -// Do not store Contexts inside a struct type; instead, pass a Context -// explicitly to each function that needs it. The Context should be the first -// parameter, typically named ctx: -// -// func DoSomething(ctx context.Context, arg Arg) error { -// // ... use ctx ... -// } -// -// Do not pass a nil Context, even if a function permits it. Pass context.TODO -// if you are unsure about which Context to use. -// -// Use context Values only for request-scoped data that transits processes and -// APIs, not for passing optional parameters to functions. -// -// The same Context may be passed to functions running in different goroutines; -// Contexts are safe for simultaneous use by multiple goroutines. -// -// See http://blog.golang.org/context for example code for a server that uses -// Contexts. -package context // import "golang.org/x/net/context" - -// Background returns a non-nil, empty Context. It is never canceled, has no -// values, and has no deadline. It is typically used by the main function, -// initialization, and tests, and as the top-level Context for incoming -// requests. -func Background() Context { - return background -} - -// TODO returns a non-nil, empty Context. Code should use context.TODO when -// it's unclear which Context to use or it is not yet available (because the -// surrounding function has not yet been extended to accept a Context -// parameter). TODO is recognized by static analysis tools that determine -// whether Contexts are propagated correctly in a program. -func TODO() Context { - return todo -} diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/go17.go b/vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/go17.go deleted file mode 100755 index d20f52b..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/go17.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.7 - -package context - -import ( - "context" // standard library's context, as of Go 1.7 - "time" -) - -var ( - todo = context.TODO() - background = context.Background() -) - -// Canceled is the error returned by Context.Err when the context is canceled. -var Canceled = context.Canceled - -// DeadlineExceeded is the error returned by Context.Err when the context's -// deadline passes. -var DeadlineExceeded = context.DeadlineExceeded - -// WithCancel returns a copy of parent with a new Done channel. The returned -// context's Done channel is closed when the returned cancel function is called -// or when the parent context's Done channel is closed, whichever happens first. -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete. -func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { - ctx, f := context.WithCancel(parent) - return ctx, CancelFunc(f) -} - -// WithDeadline returns a copy of the parent context with the deadline adjusted -// to be no later than d. If the parent's deadline is already earlier than d, -// WithDeadline(parent, d) is semantically equivalent to parent. The returned -// context's Done channel is closed when the deadline expires, when the returned -// cancel function is called, or when the parent context's Done channel is -// closed, whichever happens first. -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete. -func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { - ctx, f := context.WithDeadline(parent, deadline) - return ctx, CancelFunc(f) -} - -// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete: -// -// func slowOperationWithTimeout(ctx context.Context) (Result, error) { -// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) -// defer cancel() // releases resources if slowOperation completes before timeout elapses -// return slowOperation(ctx) -// } -func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { - return WithDeadline(parent, time.Now().Add(timeout)) -} - -// WithValue returns a copy of parent in which the value associated with key is -// val. -// -// Use context Values only for request-scoped data that transits processes and -// APIs, not for passing optional parameters to functions. -func WithValue(parent Context, key interface{}, val interface{}) Context { - return context.WithValue(parent, key, val) -} diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/go19.go b/vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/go19.go deleted file mode 100755 index d88bd1d..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/go19.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.9 - -package context - -import "context" // standard library's context, as of Go 1.7 - -// A Context carries a deadline, a cancelation signal, and other values across -// API boundaries. -// -// Context's methods may be called by multiple goroutines simultaneously. -type Context = context.Context - -// A CancelFunc tells an operation to abandon its work. -// A CancelFunc does not wait for the work to stop. -// After the first call, subsequent calls to a CancelFunc do nothing. -type CancelFunc = context.CancelFunc diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/pre_go17.go b/vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/pre_go17.go deleted file mode 100755 index 0f35592..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/pre_go17.go +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.7 - -package context - -import ( - "errors" - "fmt" - "sync" - "time" -) - -// An emptyCtx is never canceled, has no values, and has no deadline. It is not -// struct{}, since vars of this type must have distinct addresses. -type emptyCtx int - -func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { - return -} - -func (*emptyCtx) Done() <-chan struct{} { - return nil -} - -func (*emptyCtx) Err() error { - return nil -} - -func (*emptyCtx) Value(key interface{}) interface{} { - return nil -} - -func (e *emptyCtx) String() string { - switch e { - case background: - return "context.Background" - case todo: - return "context.TODO" - } - return "unknown empty Context" -} - -var ( - background = new(emptyCtx) - todo = new(emptyCtx) -) - -// Canceled is the error returned by Context.Err when the context is canceled. -var Canceled = errors.New("context canceled") - -// DeadlineExceeded is the error returned by Context.Err when the context's -// deadline passes. -var DeadlineExceeded = errors.New("context deadline exceeded") - -// WithCancel returns a copy of parent with a new Done channel. The returned -// context's Done channel is closed when the returned cancel function is called -// or when the parent context's Done channel is closed, whichever happens first. -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete. -func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { - c := newCancelCtx(parent) - propagateCancel(parent, c) - return c, func() { c.cancel(true, Canceled) } -} - -// newCancelCtx returns an initialized cancelCtx. -func newCancelCtx(parent Context) *cancelCtx { - return &cancelCtx{ - Context: parent, - done: make(chan struct{}), - } -} - -// propagateCancel arranges for child to be canceled when parent is. -func propagateCancel(parent Context, child canceler) { - if parent.Done() == nil { - return // parent is never canceled - } - if p, ok := parentCancelCtx(parent); ok { - p.mu.Lock() - if p.err != nil { - // parent has already been canceled - child.cancel(false, p.err) - } else { - if p.children == nil { - p.children = make(map[canceler]bool) - } - p.children[child] = true - } - p.mu.Unlock() - } else { - go func() { - select { - case <-parent.Done(): - child.cancel(false, parent.Err()) - case <-child.Done(): - } - }() - } -} - -// parentCancelCtx follows a chain of parent references until it finds a -// *cancelCtx. This function understands how each of the concrete types in this -// package represents its parent. -func parentCancelCtx(parent Context) (*cancelCtx, bool) { - for { - switch c := parent.(type) { - case *cancelCtx: - return c, true - case *timerCtx: - return c.cancelCtx, true - case *valueCtx: - parent = c.Context - default: - return nil, false - } - } -} - -// removeChild removes a context from its parent. -func removeChild(parent Context, child canceler) { - p, ok := parentCancelCtx(parent) - if !ok { - return - } - p.mu.Lock() - if p.children != nil { - delete(p.children, child) - } - p.mu.Unlock() -} - -// A canceler is a context type that can be canceled directly. The -// implementations are *cancelCtx and *timerCtx. -type canceler interface { - cancel(removeFromParent bool, err error) - Done() <-chan struct{} -} - -// A cancelCtx can be canceled. When canceled, it also cancels any children -// that implement canceler. -type cancelCtx struct { - Context - - done chan struct{} // closed by the first cancel call. - - mu sync.Mutex - children map[canceler]bool // set to nil by the first cancel call - err error // set to non-nil by the first cancel call -} - -func (c *cancelCtx) Done() <-chan struct{} { - return c.done -} - -func (c *cancelCtx) Err() error { - c.mu.Lock() - defer c.mu.Unlock() - return c.err -} - -func (c *cancelCtx) String() string { - return fmt.Sprintf("%v.WithCancel", c.Context) -} - -// cancel closes c.done, cancels each of c's children, and, if -// removeFromParent is true, removes c from its parent's children. -func (c *cancelCtx) cancel(removeFromParent bool, err error) { - if err == nil { - panic("context: internal error: missing cancel error") - } - c.mu.Lock() - if c.err != nil { - c.mu.Unlock() - return // already canceled - } - c.err = err - close(c.done) - for child := range c.children { - // NOTE: acquiring the child's lock while holding parent's lock. - child.cancel(false, err) - } - c.children = nil - c.mu.Unlock() - - if removeFromParent { - removeChild(c.Context, c) - } -} - -// WithDeadline returns a copy of the parent context with the deadline adjusted -// to be no later than d. If the parent's deadline is already earlier than d, -// WithDeadline(parent, d) is semantically equivalent to parent. The returned -// context's Done channel is closed when the deadline expires, when the returned -// cancel function is called, or when the parent context's Done channel is -// closed, whichever happens first. -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete. -func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { - if cur, ok := parent.Deadline(); ok && cur.Before(deadline) { - // The current deadline is already sooner than the new one. - return WithCancel(parent) - } - c := &timerCtx{ - cancelCtx: newCancelCtx(parent), - deadline: deadline, - } - propagateCancel(parent, c) - d := deadline.Sub(time.Now()) - if d <= 0 { - c.cancel(true, DeadlineExceeded) // deadline has already passed - return c, func() { c.cancel(true, Canceled) } - } - c.mu.Lock() - defer c.mu.Unlock() - if c.err == nil { - c.timer = time.AfterFunc(d, func() { - c.cancel(true, DeadlineExceeded) - }) - } - return c, func() { c.cancel(true, Canceled) } -} - -// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to -// implement Done and Err. It implements cancel by stopping its timer then -// delegating to cancelCtx.cancel. -type timerCtx struct { - *cancelCtx - timer *time.Timer // Under cancelCtx.mu. - - deadline time.Time -} - -func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { - return c.deadline, true -} - -func (c *timerCtx) String() string { - return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now())) -} - -func (c *timerCtx) cancel(removeFromParent bool, err error) { - c.cancelCtx.cancel(false, err) - if removeFromParent { - // Remove this timerCtx from its parent cancelCtx's children. - removeChild(c.cancelCtx.Context, c) - } - c.mu.Lock() - if c.timer != nil { - c.timer.Stop() - c.timer = nil - } - c.mu.Unlock() -} - -// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete: -// -// func slowOperationWithTimeout(ctx context.Context) (Result, error) { -// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) -// defer cancel() // releases resources if slowOperation completes before timeout elapses -// return slowOperation(ctx) -// } -func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { - return WithDeadline(parent, time.Now().Add(timeout)) -} - -// WithValue returns a copy of parent in which the value associated with key is -// val. -// -// Use context Values only for request-scoped data that transits processes and -// APIs, not for passing optional parameters to functions. -func WithValue(parent Context, key interface{}, val interface{}) Context { - return &valueCtx{parent, key, val} -} - -// A valueCtx carries a key-value pair. It implements Value for that key and -// delegates all other calls to the embedded Context. -type valueCtx struct { - Context - key, val interface{} -} - -func (c *valueCtx) String() string { - return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val) -} - -func (c *valueCtx) Value(key interface{}) interface{} { - if c.key == key { - return c.val - } - return c.Context.Value(key) -} diff --git a/vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/pre_go19.go b/vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/pre_go19.go deleted file mode 100755 index b105f80..0000000 --- a/vender/github.com/astaxie/beego/vendor/golang.org/x/net/context/pre_go19.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.9 - -package context - -import "time" - -// A Context carries a deadline, a cancelation signal, and other values across -// API boundaries. -// -// Context's methods may be called by multiple goroutines simultaneously. -type Context interface { - // Deadline returns the time when work done on behalf of this context - // should be canceled. Deadline returns ok==false when no deadline is - // set. Successive calls to Deadline return the same results. - Deadline() (deadline time.Time, ok bool) - - // Done returns a channel that's closed when work done on behalf of this - // context should be canceled. Done may return nil if this context can - // never be canceled. Successive calls to Done return the same value. - // - // WithCancel arranges for Done to be closed when cancel is called; - // WithDeadline arranges for Done to be closed when the deadline - // expires; WithTimeout arranges for Done to be closed when the timeout - // elapses. - // - // Done is provided for use in select statements: - // - // // Stream generates values with DoSomething and sends them to out - // // until DoSomething returns an error or ctx.Done is closed. - // func Stream(ctx context.Context, out chan<- Value) error { - // for { - // v, err := DoSomething(ctx) - // if err != nil { - // return err - // } - // select { - // case <-ctx.Done(): - // return ctx.Err() - // case out <- v: - // } - // } - // } - // - // See http://blog.golang.org/pipelines for more examples of how to use - // a Done channel for cancelation. - Done() <-chan struct{} - - // Err returns a non-nil error value after Done is closed. Err returns - // Canceled if the context was canceled or DeadlineExceeded if the - // context's deadline passed. No other values for Err are defined. - // After Done is closed, successive calls to Err return the same value. - Err() error - - // Value returns the value associated with this context for key, or nil - // if no value is associated with key. Successive calls to Value with - // the same key returns the same result. - // - // Use context values only for request-scoped data that transits - // processes and API boundaries, not for passing optional parameters to - // functions. - // - // A key identifies a specific value in a Context. Functions that wish - // to store values in Context typically allocate a key in a global - // variable then use that key as the argument to context.WithValue and - // Context.Value. A key can be any type that supports equality; - // packages should define keys as an unexported type to avoid - // collisions. - // - // Packages that define a Context key should provide type-safe accessors - // for the values stores using that key: - // - // // Package user defines a User type that's stored in Contexts. - // package user - // - // import "golang.org/x/net/context" - // - // // User is the type of value stored in the Contexts. - // type User struct {...} - // - // // key is an unexported type for keys defined in this package. - // // This prevents collisions with keys defined in other packages. - // type key int - // - // // userKey is the key for user.User values in Contexts. It is - // // unexported; clients use user.NewContext and user.FromContext - // // instead of using this key directly. - // var userKey key = 0 - // - // // NewContext returns a new Context that carries value u. - // func NewContext(ctx context.Context, u *User) context.Context { - // return context.WithValue(ctx, userKey, u) - // } - // - // // FromContext returns the User value stored in ctx, if any. - // func FromContext(ctx context.Context) (*User, bool) { - // u, ok := ctx.Value(userKey).(*User) - // return u, ok - // } - Value(key interface{}) interface{} -} - -// A CancelFunc tells an operation to abandon its work. -// A CancelFunc does not wait for the work to stop. -// After the first call, subsequent calls to a CancelFunc do nothing. -type CancelFunc func() diff --git a/vender/github.com/astaxie/beego/vendor/google.golang.org/appengine/LICENSE b/vender/github.com/astaxie/beego/vendor/google.golang.org/appengine/LICENSE deleted file mode 100755 index d645695..0000000 --- a/vender/github.com/astaxie/beego/vendor/google.golang.org/appengine/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/vender/github.com/astaxie/beego/vendor/google.golang.org/appengine/cloudsql/cloudsql.go b/vender/github.com/astaxie/beego/vendor/google.golang.org/appengine/cloudsql/cloudsql.go deleted file mode 100755 index 7b27e6b..0000000 --- a/vender/github.com/astaxie/beego/vendor/google.golang.org/appengine/cloudsql/cloudsql.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2013 Google Inc. All rights reserved. -// Use of this source code is governed by the Apache 2.0 -// license that can be found in the LICENSE file. - -/* -Package cloudsql exposes access to Google Cloud SQL databases. - -This package does not work in App Engine "flexible environment". - -This package is intended for MySQL drivers to make App Engine-specific -connections. Applications should use this package through database/sql: -Select a pure Go MySQL driver that supports this package, and use sql.Open -with protocol "cloudsql" and an address of the Cloud SQL instance. - -A Go MySQL driver that has been tested to work well with Cloud SQL -is the go-sql-driver: - import "database/sql" - import _ "github.com/go-sql-driver/mysql" - - db, err := sql.Open("mysql", "user@cloudsql(project-id:instance-name)/dbname") - - -Another driver that works well with Cloud SQL is the mymysql driver: - import "database/sql" - import _ "github.com/ziutek/mymysql/godrv" - - db, err := sql.Open("mymysql", "cloudsql:instance-name*dbname/user/password") - - -Using either of these drivers, you can perform a standard SQL query. -This example assumes there is a table named 'users' with -columns 'first_name' and 'last_name': - - rows, err := db.Query("SELECT first_name, last_name FROM users") - if err != nil { - log.Errorf(ctx, "db.Query: %v", err) - } - defer rows.Close() - - for rows.Next() { - var firstName string - var lastName string - if err := rows.Scan(&firstName, &lastName); err != nil { - log.Errorf(ctx, "rows.Scan: %v", err) - continue - } - log.Infof(ctx, "First: %v - Last: %v", firstName, lastName) - } - if err := rows.Err(); err != nil { - log.Errorf(ctx, "Row error: %v", err) - } -*/ -package cloudsql - -import ( - "net" -) - -// Dial connects to the named Cloud SQL instance. -func Dial(instance string) (net.Conn, error) { - return connect(instance) -} diff --git a/vender/github.com/astaxie/beego/vendor/google.golang.org/appengine/cloudsql/cloudsql_classic.go b/vender/github.com/astaxie/beego/vendor/google.golang.org/appengine/cloudsql/cloudsql_classic.go deleted file mode 100755 index af62dba..0000000 --- a/vender/github.com/astaxie/beego/vendor/google.golang.org/appengine/cloudsql/cloudsql_classic.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2013 Google Inc. All rights reserved. -// Use of this source code is governed by the Apache 2.0 -// license that can be found in the LICENSE file. - -// +build appengine - -package cloudsql - -import ( - "net" - - "appengine/cloudsql" -) - -func connect(instance string) (net.Conn, error) { - return cloudsql.Dial(instance) -} diff --git a/vender/github.com/astaxie/beego/vendor/google.golang.org/appengine/cloudsql/cloudsql_vm.go b/vender/github.com/astaxie/beego/vendor/google.golang.org/appengine/cloudsql/cloudsql_vm.go deleted file mode 100755 index 90fa7b3..0000000 --- a/vender/github.com/astaxie/beego/vendor/google.golang.org/appengine/cloudsql/cloudsql_vm.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2013 Google Inc. All rights reserved. -// Use of this source code is governed by the Apache 2.0 -// license that can be found in the LICENSE file. - -// +build !appengine - -package cloudsql - -import ( - "errors" - "net" -) - -func connect(instance string) (net.Conn, error) { - return nil, errors.New(`cloudsql: not supported in App Engine "flexible environment"`) -} diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/LICENSE b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/LICENSE deleted file mode 100755 index 8dada3e..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - 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. diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/LICENSE.libyaml b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/LICENSE.libyaml deleted file mode 100755 index 8da58fb..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/LICENSE.libyaml +++ /dev/null @@ -1,31 +0,0 @@ -The following files were ported to Go from C files of libyaml, and thus -are still covered by their original copyright and license: - - apic.go - emitterc.go - parserc.go - readerc.go - scannerc.go - writerc.go - yamlh.go - yamlprivateh.go - -Copyright (c) 2006 Kirill Simonov - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/NOTICE b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/NOTICE deleted file mode 100755 index 866d74a..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/NOTICE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2011-2016 Canonical Ltd. - -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. diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/README.md b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/README.md deleted file mode 100755 index b50c6e8..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/README.md +++ /dev/null @@ -1,133 +0,0 @@ -# YAML support for the Go language - -Introduction ------------- - -The yaml package enables Go programs to comfortably encode and decode YAML -values. It was developed within [Canonical](https://www.canonical.com) as -part of the [juju](https://juju.ubuntu.com) project, and is based on a -pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) -C library to parse and generate YAML data quickly and reliably. - -Compatibility -------------- - -The yaml package supports most of YAML 1.1 and 1.2, including support for -anchors, tags, map merging, etc. Multi-document unmarshalling is not yet -implemented, and base-60 floats from YAML 1.1 are purposefully not -supported since they're a poor design and are gone in YAML 1.2. - -Installation and usage ----------------------- - -The import path for the package is *gopkg.in/yaml.v2*. - -To install it, run: - - go get gopkg.in/yaml.v2 - -API documentation ------------------ - -If opened in a browser, the import path itself leads to the API documentation: - - * [https://gopkg.in/yaml.v2](https://gopkg.in/yaml.v2) - -API stability -------------- - -The package API for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in). - - -License -------- - -The yaml package is licensed under the Apache License 2.0. Please see the LICENSE file for details. - - -Example -------- - -```Go -package main - -import ( - "fmt" - "log" - - "gopkg.in/yaml.v2" -) - -var data = ` -a: Easy! -b: - c: 2 - d: [3, 4] -` - -// Note: struct fields must be public in order for unmarshal to -// correctly populate the data. -type T struct { - A string - B struct { - RenamedC int `yaml:"c"` - D []int `yaml:",flow"` - } -} - -func main() { - t := T{} - - err := yaml.Unmarshal([]byte(data), &t) - if err != nil { - log.Fatalf("error: %v", err) - } - fmt.Printf("--- t:\n%v\n\n", t) - - d, err := yaml.Marshal(&t) - if err != nil { - log.Fatalf("error: %v", err) - } - fmt.Printf("--- t dump:\n%s\n\n", string(d)) - - m := make(map[interface{}]interface{}) - - err = yaml.Unmarshal([]byte(data), &m) - if err != nil { - log.Fatalf("error: %v", err) - } - fmt.Printf("--- m:\n%v\n\n", m) - - d, err = yaml.Marshal(&m) - if err != nil { - log.Fatalf("error: %v", err) - } - fmt.Printf("--- m dump:\n%s\n\n", string(d)) -} -``` - -This example will generate the following output: - -``` ---- t: -{Easy! {2 [3 4]}} - ---- t dump: -a: Easy! -b: - c: 2 - d: [3, 4] - - ---- m: -map[a:Easy! b:map[c:2 d:[3 4]]] - ---- m dump: -a: Easy! -b: - c: 2 - d: - - 3 - - 4 -``` - diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/apic.go b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/apic.go deleted file mode 100755 index 1f7e87e..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/apic.go +++ /dev/null @@ -1,739 +0,0 @@ -package yaml - -import ( - "io" -) - -func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) { - //fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens)) - - // Check if we can move the queue at the beginning of the buffer. - if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) { - if parser.tokens_head != len(parser.tokens) { - copy(parser.tokens, parser.tokens[parser.tokens_head:]) - } - parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head] - parser.tokens_head = 0 - } - parser.tokens = append(parser.tokens, *token) - if pos < 0 { - return - } - copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:]) - parser.tokens[parser.tokens_head+pos] = *token -} - -// Create a new parser object. -func yaml_parser_initialize(parser *yaml_parser_t) bool { - *parser = yaml_parser_t{ - raw_buffer: make([]byte, 0, input_raw_buffer_size), - buffer: make([]byte, 0, input_buffer_size), - } - return true -} - -// Destroy a parser object. -func yaml_parser_delete(parser *yaml_parser_t) { - *parser = yaml_parser_t{} -} - -// String read handler. -func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { - if parser.input_pos == len(parser.input) { - return 0, io.EOF - } - n = copy(buffer, parser.input[parser.input_pos:]) - parser.input_pos += n - return n, nil -} - -// Reader read handler. -func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { - return parser.input_reader.Read(buffer) -} - -// Set a string input. -func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) { - if parser.read_handler != nil { - panic("must set the input source only once") - } - parser.read_handler = yaml_string_read_handler - parser.input = input - parser.input_pos = 0 -} - -// Set a file input. -func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) { - if parser.read_handler != nil { - panic("must set the input source only once") - } - parser.read_handler = yaml_reader_read_handler - parser.input_reader = r -} - -// Set the source encoding. -func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) { - if parser.encoding != yaml_ANY_ENCODING { - panic("must set the encoding only once") - } - parser.encoding = encoding -} - -// Create a new emitter object. -func yaml_emitter_initialize(emitter *yaml_emitter_t) { - *emitter = yaml_emitter_t{ - buffer: make([]byte, output_buffer_size), - raw_buffer: make([]byte, 0, output_raw_buffer_size), - states: make([]yaml_emitter_state_t, 0, initial_stack_size), - events: make([]yaml_event_t, 0, initial_queue_size), - } -} - -// Destroy an emitter object. -func yaml_emitter_delete(emitter *yaml_emitter_t) { - *emitter = yaml_emitter_t{} -} - -// String write handler. -func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error { - *emitter.output_buffer = append(*emitter.output_buffer, buffer...) - return nil -} - -// yaml_writer_write_handler uses emitter.output_writer to write the -// emitted text. -func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error { - _, err := emitter.output_writer.Write(buffer) - return err -} - -// Set a string output. -func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) { - if emitter.write_handler != nil { - panic("must set the output target only once") - } - emitter.write_handler = yaml_string_write_handler - emitter.output_buffer = output_buffer -} - -// Set a file output. -func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) { - if emitter.write_handler != nil { - panic("must set the output target only once") - } - emitter.write_handler = yaml_writer_write_handler - emitter.output_writer = w -} - -// Set the output encoding. -func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) { - if emitter.encoding != yaml_ANY_ENCODING { - panic("must set the output encoding only once") - } - emitter.encoding = encoding -} - -// Set the canonical output style. -func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) { - emitter.canonical = canonical -} - -//// Set the indentation increment. -func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) { - if indent < 2 || indent > 9 { - indent = 2 - } - emitter.best_indent = indent -} - -// Set the preferred line width. -func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) { - if width < 0 { - width = -1 - } - emitter.best_width = width -} - -// Set if unescaped non-ASCII characters are allowed. -func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) { - emitter.unicode = unicode -} - -// Set the preferred line break character. -func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) { - emitter.line_break = line_break -} - -///* -// * Destroy a token object. -// */ -// -//YAML_DECLARE(void) -//yaml_token_delete(yaml_token_t *token) -//{ -// assert(token); // Non-NULL token object expected. -// -// switch (token.type) -// { -// case YAML_TAG_DIRECTIVE_TOKEN: -// yaml_free(token.data.tag_directive.handle); -// yaml_free(token.data.tag_directive.prefix); -// break; -// -// case YAML_ALIAS_TOKEN: -// yaml_free(token.data.alias.value); -// break; -// -// case YAML_ANCHOR_TOKEN: -// yaml_free(token.data.anchor.value); -// break; -// -// case YAML_TAG_TOKEN: -// yaml_free(token.data.tag.handle); -// yaml_free(token.data.tag.suffix); -// break; -// -// case YAML_SCALAR_TOKEN: -// yaml_free(token.data.scalar.value); -// break; -// -// default: -// break; -// } -// -// memset(token, 0, sizeof(yaml_token_t)); -//} -// -///* -// * Check if a string is a valid UTF-8 sequence. -// * -// * Check 'reader.c' for more details on UTF-8 encoding. -// */ -// -//static int -//yaml_check_utf8(yaml_char_t *start, size_t length) -//{ -// yaml_char_t *end = start+length; -// yaml_char_t *pointer = start; -// -// while (pointer < end) { -// unsigned char octet; -// unsigned int width; -// unsigned int value; -// size_t k; -// -// octet = pointer[0]; -// width = (octet & 0x80) == 0x00 ? 1 : -// (octet & 0xE0) == 0xC0 ? 2 : -// (octet & 0xF0) == 0xE0 ? 3 : -// (octet & 0xF8) == 0xF0 ? 4 : 0; -// value = (octet & 0x80) == 0x00 ? octet & 0x7F : -// (octet & 0xE0) == 0xC0 ? octet & 0x1F : -// (octet & 0xF0) == 0xE0 ? octet & 0x0F : -// (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; -// if (!width) return 0; -// if (pointer+width > end) return 0; -// for (k = 1; k < width; k ++) { -// octet = pointer[k]; -// if ((octet & 0xC0) != 0x80) return 0; -// value = (value << 6) + (octet & 0x3F); -// } -// if (!((width == 1) || -// (width == 2 && value >= 0x80) || -// (width == 3 && value >= 0x800) || -// (width == 4 && value >= 0x10000))) return 0; -// -// pointer += width; -// } -// -// return 1; -//} -// - -// Create STREAM-START. -func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) { - *event = yaml_event_t{ - typ: yaml_STREAM_START_EVENT, - encoding: encoding, - } -} - -// Create STREAM-END. -func yaml_stream_end_event_initialize(event *yaml_event_t) { - *event = yaml_event_t{ - typ: yaml_STREAM_END_EVENT, - } -} - -// Create DOCUMENT-START. -func yaml_document_start_event_initialize( - event *yaml_event_t, - version_directive *yaml_version_directive_t, - tag_directives []yaml_tag_directive_t, - implicit bool, -) { - *event = yaml_event_t{ - typ: yaml_DOCUMENT_START_EVENT, - version_directive: version_directive, - tag_directives: tag_directives, - implicit: implicit, - } -} - -// Create DOCUMENT-END. -func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) { - *event = yaml_event_t{ - typ: yaml_DOCUMENT_END_EVENT, - implicit: implicit, - } -} - -///* -// * Create ALIAS. -// */ -// -//YAML_DECLARE(int) -//yaml_alias_event_initialize(event *yaml_event_t, anchor *yaml_char_t) -//{ -// mark yaml_mark_t = { 0, 0, 0 } -// anchor_copy *yaml_char_t = NULL -// -// assert(event) // Non-NULL event object is expected. -// assert(anchor) // Non-NULL anchor is expected. -// -// if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0 -// -// anchor_copy = yaml_strdup(anchor) -// if (!anchor_copy) -// return 0 -// -// ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark) -// -// return 1 -//} - -// Create SCALAR. -func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool { - *event = yaml_event_t{ - typ: yaml_SCALAR_EVENT, - anchor: anchor, - tag: tag, - value: value, - implicit: plain_implicit, - quoted_implicit: quoted_implicit, - style: yaml_style_t(style), - } - return true -} - -// Create SEQUENCE-START. -func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool { - *event = yaml_event_t{ - typ: yaml_SEQUENCE_START_EVENT, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(style), - } - return true -} - -// Create SEQUENCE-END. -func yaml_sequence_end_event_initialize(event *yaml_event_t) bool { - *event = yaml_event_t{ - typ: yaml_SEQUENCE_END_EVENT, - } - return true -} - -// Create MAPPING-START. -func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) { - *event = yaml_event_t{ - typ: yaml_MAPPING_START_EVENT, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(style), - } -} - -// Create MAPPING-END. -func yaml_mapping_end_event_initialize(event *yaml_event_t) { - *event = yaml_event_t{ - typ: yaml_MAPPING_END_EVENT, - } -} - -// Destroy an event object. -func yaml_event_delete(event *yaml_event_t) { - *event = yaml_event_t{} -} - -///* -// * Create a document object. -// */ -// -//YAML_DECLARE(int) -//yaml_document_initialize(document *yaml_document_t, -// version_directive *yaml_version_directive_t, -// tag_directives_start *yaml_tag_directive_t, -// tag_directives_end *yaml_tag_directive_t, -// start_implicit int, end_implicit int) -//{ -// struct { -// error yaml_error_type_t -// } context -// struct { -// start *yaml_node_t -// end *yaml_node_t -// top *yaml_node_t -// } nodes = { NULL, NULL, NULL } -// version_directive_copy *yaml_version_directive_t = NULL -// struct { -// start *yaml_tag_directive_t -// end *yaml_tag_directive_t -// top *yaml_tag_directive_t -// } tag_directives_copy = { NULL, NULL, NULL } -// value yaml_tag_directive_t = { NULL, NULL } -// mark yaml_mark_t = { 0, 0, 0 } -// -// assert(document) // Non-NULL document object is expected. -// assert((tag_directives_start && tag_directives_end) || -// (tag_directives_start == tag_directives_end)) -// // Valid tag directives are expected. -// -// if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error -// -// if (version_directive) { -// version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)) -// if (!version_directive_copy) goto error -// version_directive_copy.major = version_directive.major -// version_directive_copy.minor = version_directive.minor -// } -// -// if (tag_directives_start != tag_directives_end) { -// tag_directive *yaml_tag_directive_t -// if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE)) -// goto error -// for (tag_directive = tag_directives_start -// tag_directive != tag_directives_end; tag_directive ++) { -// assert(tag_directive.handle) -// assert(tag_directive.prefix) -// if (!yaml_check_utf8(tag_directive.handle, -// strlen((char *)tag_directive.handle))) -// goto error -// if (!yaml_check_utf8(tag_directive.prefix, -// strlen((char *)tag_directive.prefix))) -// goto error -// value.handle = yaml_strdup(tag_directive.handle) -// value.prefix = yaml_strdup(tag_directive.prefix) -// if (!value.handle || !value.prefix) goto error -// if (!PUSH(&context, tag_directives_copy, value)) -// goto error -// value.handle = NULL -// value.prefix = NULL -// } -// } -// -// DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy, -// tag_directives_copy.start, tag_directives_copy.top, -// start_implicit, end_implicit, mark, mark) -// -// return 1 -// -//error: -// STACK_DEL(&context, nodes) -// yaml_free(version_directive_copy) -// while (!STACK_EMPTY(&context, tag_directives_copy)) { -// value yaml_tag_directive_t = POP(&context, tag_directives_copy) -// yaml_free(value.handle) -// yaml_free(value.prefix) -// } -// STACK_DEL(&context, tag_directives_copy) -// yaml_free(value.handle) -// yaml_free(value.prefix) -// -// return 0 -//} -// -///* -// * Destroy a document object. -// */ -// -//YAML_DECLARE(void) -//yaml_document_delete(document *yaml_document_t) -//{ -// struct { -// error yaml_error_type_t -// } context -// tag_directive *yaml_tag_directive_t -// -// context.error = YAML_NO_ERROR // Eliminate a compiler warning. -// -// assert(document) // Non-NULL document object is expected. -// -// while (!STACK_EMPTY(&context, document.nodes)) { -// node yaml_node_t = POP(&context, document.nodes) -// yaml_free(node.tag) -// switch (node.type) { -// case YAML_SCALAR_NODE: -// yaml_free(node.data.scalar.value) -// break -// case YAML_SEQUENCE_NODE: -// STACK_DEL(&context, node.data.sequence.items) -// break -// case YAML_MAPPING_NODE: -// STACK_DEL(&context, node.data.mapping.pairs) -// break -// default: -// assert(0) // Should not happen. -// } -// } -// STACK_DEL(&context, document.nodes) -// -// yaml_free(document.version_directive) -// for (tag_directive = document.tag_directives.start -// tag_directive != document.tag_directives.end -// tag_directive++) { -// yaml_free(tag_directive.handle) -// yaml_free(tag_directive.prefix) -// } -// yaml_free(document.tag_directives.start) -// -// memset(document, 0, sizeof(yaml_document_t)) -//} -// -///** -// * Get a document node. -// */ -// -//YAML_DECLARE(yaml_node_t *) -//yaml_document_get_node(document *yaml_document_t, index int) -//{ -// assert(document) // Non-NULL document object is expected. -// -// if (index > 0 && document.nodes.start + index <= document.nodes.top) { -// return document.nodes.start + index - 1 -// } -// return NULL -//} -// -///** -// * Get the root object. -// */ -// -//YAML_DECLARE(yaml_node_t *) -//yaml_document_get_root_node(document *yaml_document_t) -//{ -// assert(document) // Non-NULL document object is expected. -// -// if (document.nodes.top != document.nodes.start) { -// return document.nodes.start -// } -// return NULL -//} -// -///* -// * Add a scalar node to a document. -// */ -// -//YAML_DECLARE(int) -//yaml_document_add_scalar(document *yaml_document_t, -// tag *yaml_char_t, value *yaml_char_t, length int, -// style yaml_scalar_style_t) -//{ -// struct { -// error yaml_error_type_t -// } context -// mark yaml_mark_t = { 0, 0, 0 } -// tag_copy *yaml_char_t = NULL -// value_copy *yaml_char_t = NULL -// node yaml_node_t -// -// assert(document) // Non-NULL document object is expected. -// assert(value) // Non-NULL value is expected. -// -// if (!tag) { -// tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG -// } -// -// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error -// tag_copy = yaml_strdup(tag) -// if (!tag_copy) goto error -// -// if (length < 0) { -// length = strlen((char *)value) -// } -// -// if (!yaml_check_utf8(value, length)) goto error -// value_copy = yaml_malloc(length+1) -// if (!value_copy) goto error -// memcpy(value_copy, value, length) -// value_copy[length] = '\0' -// -// SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark) -// if (!PUSH(&context, document.nodes, node)) goto error -// -// return document.nodes.top - document.nodes.start -// -//error: -// yaml_free(tag_copy) -// yaml_free(value_copy) -// -// return 0 -//} -// -///* -// * Add a sequence node to a document. -// */ -// -//YAML_DECLARE(int) -//yaml_document_add_sequence(document *yaml_document_t, -// tag *yaml_char_t, style yaml_sequence_style_t) -//{ -// struct { -// error yaml_error_type_t -// } context -// mark yaml_mark_t = { 0, 0, 0 } -// tag_copy *yaml_char_t = NULL -// struct { -// start *yaml_node_item_t -// end *yaml_node_item_t -// top *yaml_node_item_t -// } items = { NULL, NULL, NULL } -// node yaml_node_t -// -// assert(document) // Non-NULL document object is expected. -// -// if (!tag) { -// tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG -// } -// -// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error -// tag_copy = yaml_strdup(tag) -// if (!tag_copy) goto error -// -// if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error -// -// SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end, -// style, mark, mark) -// if (!PUSH(&context, document.nodes, node)) goto error -// -// return document.nodes.top - document.nodes.start -// -//error: -// STACK_DEL(&context, items) -// yaml_free(tag_copy) -// -// return 0 -//} -// -///* -// * Add a mapping node to a document. -// */ -// -//YAML_DECLARE(int) -//yaml_document_add_mapping(document *yaml_document_t, -// tag *yaml_char_t, style yaml_mapping_style_t) -//{ -// struct { -// error yaml_error_type_t -// } context -// mark yaml_mark_t = { 0, 0, 0 } -// tag_copy *yaml_char_t = NULL -// struct { -// start *yaml_node_pair_t -// end *yaml_node_pair_t -// top *yaml_node_pair_t -// } pairs = { NULL, NULL, NULL } -// node yaml_node_t -// -// assert(document) // Non-NULL document object is expected. -// -// if (!tag) { -// tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG -// } -// -// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error -// tag_copy = yaml_strdup(tag) -// if (!tag_copy) goto error -// -// if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error -// -// MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end, -// style, mark, mark) -// if (!PUSH(&context, document.nodes, node)) goto error -// -// return document.nodes.top - document.nodes.start -// -//error: -// STACK_DEL(&context, pairs) -// yaml_free(tag_copy) -// -// return 0 -//} -// -///* -// * Append an item to a sequence node. -// */ -// -//YAML_DECLARE(int) -//yaml_document_append_sequence_item(document *yaml_document_t, -// sequence int, item int) -//{ -// struct { -// error yaml_error_type_t -// } context -// -// assert(document) // Non-NULL document is required. -// assert(sequence > 0 -// && document.nodes.start + sequence <= document.nodes.top) -// // Valid sequence id is required. -// assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE) -// // A sequence node is required. -// assert(item > 0 && document.nodes.start + item <= document.nodes.top) -// // Valid item id is required. -// -// if (!PUSH(&context, -// document.nodes.start[sequence-1].data.sequence.items, item)) -// return 0 -// -// return 1 -//} -// -///* -// * Append a pair of a key and a value to a mapping node. -// */ -// -//YAML_DECLARE(int) -//yaml_document_append_mapping_pair(document *yaml_document_t, -// mapping int, key int, value int) -//{ -// struct { -// error yaml_error_type_t -// } context -// -// pair yaml_node_pair_t -// -// assert(document) // Non-NULL document is required. -// assert(mapping > 0 -// && document.nodes.start + mapping <= document.nodes.top) -// // Valid mapping id is required. -// assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE) -// // A mapping node is required. -// assert(key > 0 && document.nodes.start + key <= document.nodes.top) -// // Valid key id is required. -// assert(value > 0 && document.nodes.start + value <= document.nodes.top) -// // Valid value id is required. -// -// pair.key = key -// pair.value = value -// -// if (!PUSH(&context, -// document.nodes.start[mapping-1].data.mapping.pairs, pair)) -// return 0 -// -// return 1 -//} -// -// diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/decode.go b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/decode.go deleted file mode 100755 index e4e56e2..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/decode.go +++ /dev/null @@ -1,775 +0,0 @@ -package yaml - -import ( - "encoding" - "encoding/base64" - "fmt" - "io" - "math" - "reflect" - "strconv" - "time" -) - -const ( - documentNode = 1 << iota - mappingNode - sequenceNode - scalarNode - aliasNode -) - -type node struct { - kind int - line, column int - tag string - // For an alias node, alias holds the resolved alias. - alias *node - value string - implicit bool - children []*node - anchors map[string]*node -} - -// ---------------------------------------------------------------------------- -// Parser, produces a node tree out of a libyaml event stream. - -type parser struct { - parser yaml_parser_t - event yaml_event_t - doc *node - doneInit bool -} - -func newParser(b []byte) *parser { - p := parser{} - if !yaml_parser_initialize(&p.parser) { - panic("failed to initialize YAML emitter") - } - if len(b) == 0 { - b = []byte{'\n'} - } - yaml_parser_set_input_string(&p.parser, b) - return &p -} - -func newParserFromReader(r io.Reader) *parser { - p := parser{} - if !yaml_parser_initialize(&p.parser) { - panic("failed to initialize YAML emitter") - } - yaml_parser_set_input_reader(&p.parser, r) - return &p -} - -func (p *parser) init() { - if p.doneInit { - return - } - p.expect(yaml_STREAM_START_EVENT) - p.doneInit = true -} - -func (p *parser) destroy() { - if p.event.typ != yaml_NO_EVENT { - yaml_event_delete(&p.event) - } - yaml_parser_delete(&p.parser) -} - -// expect consumes an event from the event stream and -// checks that it's of the expected type. -func (p *parser) expect(e yaml_event_type_t) { - if p.event.typ == yaml_NO_EVENT { - if !yaml_parser_parse(&p.parser, &p.event) { - p.fail() - } - } - if p.event.typ == yaml_STREAM_END_EVENT { - failf("attempted to go past the end of stream; corrupted value?") - } - if p.event.typ != e { - p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ) - p.fail() - } - yaml_event_delete(&p.event) - p.event.typ = yaml_NO_EVENT -} - -// peek peeks at the next event in the event stream, -// puts the results into p.event and returns the event type. -func (p *parser) peek() yaml_event_type_t { - if p.event.typ != yaml_NO_EVENT { - return p.event.typ - } - if !yaml_parser_parse(&p.parser, &p.event) { - p.fail() - } - return p.event.typ -} - -func (p *parser) fail() { - var where string - var line int - if p.parser.problem_mark.line != 0 { - line = p.parser.problem_mark.line - // Scanner errors don't iterate line before returning error - if p.parser.error == yaml_SCANNER_ERROR { - line++ - } - } else if p.parser.context_mark.line != 0 { - line = p.parser.context_mark.line - } - if line != 0 { - where = "line " + strconv.Itoa(line) + ": " - } - var msg string - if len(p.parser.problem) > 0 { - msg = p.parser.problem - } else { - msg = "unknown problem parsing YAML content" - } - failf("%s%s", where, msg) -} - -func (p *parser) anchor(n *node, anchor []byte) { - if anchor != nil { - p.doc.anchors[string(anchor)] = n - } -} - -func (p *parser) parse() *node { - p.init() - switch p.peek() { - case yaml_SCALAR_EVENT: - return p.scalar() - case yaml_ALIAS_EVENT: - return p.alias() - case yaml_MAPPING_START_EVENT: - return p.mapping() - case yaml_SEQUENCE_START_EVENT: - return p.sequence() - case yaml_DOCUMENT_START_EVENT: - return p.document() - case yaml_STREAM_END_EVENT: - // Happens when attempting to decode an empty buffer. - return nil - default: - panic("attempted to parse unknown event: " + p.event.typ.String()) - } -} - -func (p *parser) node(kind int) *node { - return &node{ - kind: kind, - line: p.event.start_mark.line, - column: p.event.start_mark.column, - } -} - -func (p *parser) document() *node { - n := p.node(documentNode) - n.anchors = make(map[string]*node) - p.doc = n - p.expect(yaml_DOCUMENT_START_EVENT) - n.children = append(n.children, p.parse()) - p.expect(yaml_DOCUMENT_END_EVENT) - return n -} - -func (p *parser) alias() *node { - n := p.node(aliasNode) - n.value = string(p.event.anchor) - n.alias = p.doc.anchors[n.value] - if n.alias == nil { - failf("unknown anchor '%s' referenced", n.value) - } - p.expect(yaml_ALIAS_EVENT) - return n -} - -func (p *parser) scalar() *node { - n := p.node(scalarNode) - n.value = string(p.event.value) - n.tag = string(p.event.tag) - n.implicit = p.event.implicit - p.anchor(n, p.event.anchor) - p.expect(yaml_SCALAR_EVENT) - return n -} - -func (p *parser) sequence() *node { - n := p.node(sequenceNode) - p.anchor(n, p.event.anchor) - p.expect(yaml_SEQUENCE_START_EVENT) - for p.peek() != yaml_SEQUENCE_END_EVENT { - n.children = append(n.children, p.parse()) - } - p.expect(yaml_SEQUENCE_END_EVENT) - return n -} - -func (p *parser) mapping() *node { - n := p.node(mappingNode) - p.anchor(n, p.event.anchor) - p.expect(yaml_MAPPING_START_EVENT) - for p.peek() != yaml_MAPPING_END_EVENT { - n.children = append(n.children, p.parse(), p.parse()) - } - p.expect(yaml_MAPPING_END_EVENT) - return n -} - -// ---------------------------------------------------------------------------- -// Decoder, unmarshals a node into a provided value. - -type decoder struct { - doc *node - aliases map[*node]bool - mapType reflect.Type - terrors []string - strict bool -} - -var ( - mapItemType = reflect.TypeOf(MapItem{}) - durationType = reflect.TypeOf(time.Duration(0)) - defaultMapType = reflect.TypeOf(map[interface{}]interface{}{}) - ifaceType = defaultMapType.Elem() - timeType = reflect.TypeOf(time.Time{}) - ptrTimeType = reflect.TypeOf(&time.Time{}) -) - -func newDecoder(strict bool) *decoder { - d := &decoder{mapType: defaultMapType, strict: strict} - d.aliases = make(map[*node]bool) - return d -} - -func (d *decoder) terror(n *node, tag string, out reflect.Value) { - if n.tag != "" { - tag = n.tag - } - value := n.value - if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG { - if len(value) > 10 { - value = " `" + value[:7] + "...`" - } else { - value = " `" + value + "`" - } - } - d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type())) -} - -func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) { - terrlen := len(d.terrors) - err := u.UnmarshalYAML(func(v interface{}) (err error) { - defer handleErr(&err) - d.unmarshal(n, reflect.ValueOf(v)) - if len(d.terrors) > terrlen { - issues := d.terrors[terrlen:] - d.terrors = d.terrors[:terrlen] - return &TypeError{issues} - } - return nil - }) - if e, ok := err.(*TypeError); ok { - d.terrors = append(d.terrors, e.Errors...) - return false - } - if err != nil { - fail(err) - } - return true -} - -// d.prepare initializes and dereferences pointers and calls UnmarshalYAML -// if a value is found to implement it. -// It returns the initialized and dereferenced out value, whether -// unmarshalling was already done by UnmarshalYAML, and if so whether -// its types unmarshalled appropriately. -// -// If n holds a null value, prepare returns before doing anything. -func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) { - if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) { - return out, false, false - } - again := true - for again { - again = false - if out.Kind() == reflect.Ptr { - if out.IsNil() { - out.Set(reflect.New(out.Type().Elem())) - } - out = out.Elem() - again = true - } - if out.CanAddr() { - if u, ok := out.Addr().Interface().(Unmarshaler); ok { - good = d.callUnmarshaler(n, u) - return out, true, good - } - } - } - return out, false, false -} - -func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) { - switch n.kind { - case documentNode: - return d.document(n, out) - case aliasNode: - return d.alias(n, out) - } - out, unmarshaled, good := d.prepare(n, out) - if unmarshaled { - return good - } - switch n.kind { - case scalarNode: - good = d.scalar(n, out) - case mappingNode: - good = d.mapping(n, out) - case sequenceNode: - good = d.sequence(n, out) - default: - panic("internal error: unknown node kind: " + strconv.Itoa(n.kind)) - } - return good -} - -func (d *decoder) document(n *node, out reflect.Value) (good bool) { - if len(n.children) == 1 { - d.doc = n - d.unmarshal(n.children[0], out) - return true - } - return false -} - -func (d *decoder) alias(n *node, out reflect.Value) (good bool) { - if d.aliases[n] { - // TODO this could actually be allowed in some circumstances. - failf("anchor '%s' value contains itself", n.value) - } - d.aliases[n] = true - good = d.unmarshal(n.alias, out) - delete(d.aliases, n) - return good -} - -var zeroValue reflect.Value - -func resetMap(out reflect.Value) { - for _, k := range out.MapKeys() { - out.SetMapIndex(k, zeroValue) - } -} - -func (d *decoder) scalar(n *node, out reflect.Value) bool { - var tag string - var resolved interface{} - if n.tag == "" && !n.implicit { - tag = yaml_STR_TAG - resolved = n.value - } else { - tag, resolved = resolve(n.tag, n.value) - if tag == yaml_BINARY_TAG { - data, err := base64.StdEncoding.DecodeString(resolved.(string)) - if err != nil { - failf("!!binary value contains invalid base64 data") - } - resolved = string(data) - } - } - if resolved == nil { - if out.Kind() == reflect.Map && !out.CanAddr() { - resetMap(out) - } else { - out.Set(reflect.Zero(out.Type())) - } - return true - } - if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { - // We've resolved to exactly the type we want, so use that. - out.Set(resolvedv) - return true - } - // Perhaps we can use the value as a TextUnmarshaler to - // set its value. - if out.CanAddr() { - u, ok := out.Addr().Interface().(encoding.TextUnmarshaler) - if ok { - var text []byte - if tag == yaml_BINARY_TAG { - text = []byte(resolved.(string)) - } else { - // We let any value be unmarshaled into TextUnmarshaler. - // That might be more lax than we'd like, but the - // TextUnmarshaler itself should bowl out any dubious values. - text = []byte(n.value) - } - err := u.UnmarshalText(text) - if err != nil { - fail(err) - } - return true - } - } - switch out.Kind() { - case reflect.String: - if tag == yaml_BINARY_TAG { - out.SetString(resolved.(string)) - return true - } - if resolved != nil { - out.SetString(n.value) - return true - } - case reflect.Interface: - if resolved == nil { - out.Set(reflect.Zero(out.Type())) - } else if tag == yaml_TIMESTAMP_TAG { - // It looks like a timestamp but for backward compatibility - // reasons we set it as a string, so that code that unmarshals - // timestamp-like values into interface{} will continue to - // see a string and not a time.Time. - // TODO(v3) Drop this. - out.Set(reflect.ValueOf(n.value)) - } else { - out.Set(reflect.ValueOf(resolved)) - } - return true - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - switch resolved := resolved.(type) { - case int: - if !out.OverflowInt(int64(resolved)) { - out.SetInt(int64(resolved)) - return true - } - case int64: - if !out.OverflowInt(resolved) { - out.SetInt(resolved) - return true - } - case uint64: - if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { - out.SetInt(int64(resolved)) - return true - } - case float64: - if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { - out.SetInt(int64(resolved)) - return true - } - case string: - if out.Type() == durationType { - d, err := time.ParseDuration(resolved) - if err == nil { - out.SetInt(int64(d)) - return true - } - } - } - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - switch resolved := resolved.(type) { - case int: - if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { - out.SetUint(uint64(resolved)) - return true - } - case int64: - if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { - out.SetUint(uint64(resolved)) - return true - } - case uint64: - if !out.OverflowUint(uint64(resolved)) { - out.SetUint(uint64(resolved)) - return true - } - case float64: - if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) { - out.SetUint(uint64(resolved)) - return true - } - } - case reflect.Bool: - switch resolved := resolved.(type) { - case bool: - out.SetBool(resolved) - return true - } - case reflect.Float32, reflect.Float64: - switch resolved := resolved.(type) { - case int: - out.SetFloat(float64(resolved)) - return true - case int64: - out.SetFloat(float64(resolved)) - return true - case uint64: - out.SetFloat(float64(resolved)) - return true - case float64: - out.SetFloat(resolved) - return true - } - case reflect.Struct: - if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { - out.Set(resolvedv) - return true - } - case reflect.Ptr: - if out.Type().Elem() == reflect.TypeOf(resolved) { - // TODO DOes this make sense? When is out a Ptr except when decoding a nil value? - elem := reflect.New(out.Type().Elem()) - elem.Elem().Set(reflect.ValueOf(resolved)) - out.Set(elem) - return true - } - } - d.terror(n, tag, out) - return false -} - -func settableValueOf(i interface{}) reflect.Value { - v := reflect.ValueOf(i) - sv := reflect.New(v.Type()).Elem() - sv.Set(v) - return sv -} - -func (d *decoder) sequence(n *node, out reflect.Value) (good bool) { - l := len(n.children) - - var iface reflect.Value - switch out.Kind() { - case reflect.Slice: - out.Set(reflect.MakeSlice(out.Type(), l, l)) - case reflect.Array: - if l != out.Len() { - failf("invalid array: want %d elements but got %d", out.Len(), l) - } - case reflect.Interface: - // No type hints. Will have to use a generic sequence. - iface = out - out = settableValueOf(make([]interface{}, l)) - default: - d.terror(n, yaml_SEQ_TAG, out) - return false - } - et := out.Type().Elem() - - j := 0 - for i := 0; i < l; i++ { - e := reflect.New(et).Elem() - if ok := d.unmarshal(n.children[i], e); ok { - out.Index(j).Set(e) - j++ - } - } - if out.Kind() != reflect.Array { - out.Set(out.Slice(0, j)) - } - if iface.IsValid() { - iface.Set(out) - } - return true -} - -func (d *decoder) mapping(n *node, out reflect.Value) (good bool) { - switch out.Kind() { - case reflect.Struct: - return d.mappingStruct(n, out) - case reflect.Slice: - return d.mappingSlice(n, out) - case reflect.Map: - // okay - case reflect.Interface: - if d.mapType.Kind() == reflect.Map { - iface := out - out = reflect.MakeMap(d.mapType) - iface.Set(out) - } else { - slicev := reflect.New(d.mapType).Elem() - if !d.mappingSlice(n, slicev) { - return false - } - out.Set(slicev) - return true - } - default: - d.terror(n, yaml_MAP_TAG, out) - return false - } - outt := out.Type() - kt := outt.Key() - et := outt.Elem() - - mapType := d.mapType - if outt.Key() == ifaceType && outt.Elem() == ifaceType { - d.mapType = outt - } - - if out.IsNil() { - out.Set(reflect.MakeMap(outt)) - } - l := len(n.children) - for i := 0; i < l; i += 2 { - if isMerge(n.children[i]) { - d.merge(n.children[i+1], out) - continue - } - k := reflect.New(kt).Elem() - if d.unmarshal(n.children[i], k) { - kkind := k.Kind() - if kkind == reflect.Interface { - kkind = k.Elem().Kind() - } - if kkind == reflect.Map || kkind == reflect.Slice { - failf("invalid map key: %#v", k.Interface()) - } - e := reflect.New(et).Elem() - if d.unmarshal(n.children[i+1], e) { - d.setMapIndex(n.children[i+1], out, k, e) - } - } - } - d.mapType = mapType - return true -} - -func (d *decoder) setMapIndex(n *node, out, k, v reflect.Value) { - if d.strict && out.MapIndex(k) != zeroValue { - d.terrors = append(d.terrors, fmt.Sprintf("line %d: key %#v already set in map", n.line+1, k.Interface())) - return - } - out.SetMapIndex(k, v) -} - -func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) { - outt := out.Type() - if outt.Elem() != mapItemType { - d.terror(n, yaml_MAP_TAG, out) - return false - } - - mapType := d.mapType - d.mapType = outt - - var slice []MapItem - var l = len(n.children) - for i := 0; i < l; i += 2 { - if isMerge(n.children[i]) { - d.merge(n.children[i+1], out) - continue - } - item := MapItem{} - k := reflect.ValueOf(&item.Key).Elem() - if d.unmarshal(n.children[i], k) { - v := reflect.ValueOf(&item.Value).Elem() - if d.unmarshal(n.children[i+1], v) { - slice = append(slice, item) - } - } - } - out.Set(reflect.ValueOf(slice)) - d.mapType = mapType - return true -} - -func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) { - sinfo, err := getStructInfo(out.Type()) - if err != nil { - panic(err) - } - name := settableValueOf("") - l := len(n.children) - - var inlineMap reflect.Value - var elemType reflect.Type - if sinfo.InlineMap != -1 { - inlineMap = out.Field(sinfo.InlineMap) - inlineMap.Set(reflect.New(inlineMap.Type()).Elem()) - elemType = inlineMap.Type().Elem() - } - - var doneFields []bool - if d.strict { - doneFields = make([]bool, len(sinfo.FieldsList)) - } - for i := 0; i < l; i += 2 { - ni := n.children[i] - if isMerge(ni) { - d.merge(n.children[i+1], out) - continue - } - if !d.unmarshal(ni, name) { - continue - } - if info, ok := sinfo.FieldsMap[name.String()]; ok { - if d.strict { - if doneFields[info.Id] { - d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.line+1, name.String(), out.Type())) - continue - } - doneFields[info.Id] = true - } - var field reflect.Value - if info.Inline == nil { - field = out.Field(info.Num) - } else { - field = out.FieldByIndex(info.Inline) - } - d.unmarshal(n.children[i+1], field) - } else if sinfo.InlineMap != -1 { - if inlineMap.IsNil() { - inlineMap.Set(reflect.MakeMap(inlineMap.Type())) - } - value := reflect.New(elemType).Elem() - d.unmarshal(n.children[i+1], value) - d.setMapIndex(n.children[i+1], inlineMap, name, value) - } else if d.strict { - d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.line+1, name.String(), out.Type())) - } - } - return true -} - -func failWantMap() { - failf("map merge requires map or sequence of maps as the value") -} - -func (d *decoder) merge(n *node, out reflect.Value) { - switch n.kind { - case mappingNode: - d.unmarshal(n, out) - case aliasNode: - an, ok := d.doc.anchors[n.value] - if ok && an.kind != mappingNode { - failWantMap() - } - d.unmarshal(n, out) - case sequenceNode: - // Step backwards as earlier nodes take precedence. - for i := len(n.children) - 1; i >= 0; i-- { - ni := n.children[i] - if ni.kind == aliasNode { - an, ok := d.doc.anchors[ni.value] - if ok && an.kind != mappingNode { - failWantMap() - } - } else if ni.kind != mappingNode { - failWantMap() - } - d.unmarshal(ni, out) - } - default: - failWantMap() - } -} - -func isMerge(n *node) bool { - return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG) -} diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/emitterc.go b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/emitterc.go deleted file mode 100755 index a1c2cc5..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/emitterc.go +++ /dev/null @@ -1,1685 +0,0 @@ -package yaml - -import ( - "bytes" - "fmt" -) - -// Flush the buffer if needed. -func flush(emitter *yaml_emitter_t) bool { - if emitter.buffer_pos+5 >= len(emitter.buffer) { - return yaml_emitter_flush(emitter) - } - return true -} - -// Put a character to the output buffer. -func put(emitter *yaml_emitter_t, value byte) bool { - if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { - return false - } - emitter.buffer[emitter.buffer_pos] = value - emitter.buffer_pos++ - emitter.column++ - return true -} - -// Put a line break to the output buffer. -func put_break(emitter *yaml_emitter_t) bool { - if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { - return false - } - switch emitter.line_break { - case yaml_CR_BREAK: - emitter.buffer[emitter.buffer_pos] = '\r' - emitter.buffer_pos += 1 - case yaml_LN_BREAK: - emitter.buffer[emitter.buffer_pos] = '\n' - emitter.buffer_pos += 1 - case yaml_CRLN_BREAK: - emitter.buffer[emitter.buffer_pos+0] = '\r' - emitter.buffer[emitter.buffer_pos+1] = '\n' - emitter.buffer_pos += 2 - default: - panic("unknown line break setting") - } - emitter.column = 0 - emitter.line++ - return true -} - -// Copy a character from a string into buffer. -func write(emitter *yaml_emitter_t, s []byte, i *int) bool { - if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { - return false - } - p := emitter.buffer_pos - w := width(s[*i]) - switch w { - case 4: - emitter.buffer[p+3] = s[*i+3] - fallthrough - case 3: - emitter.buffer[p+2] = s[*i+2] - fallthrough - case 2: - emitter.buffer[p+1] = s[*i+1] - fallthrough - case 1: - emitter.buffer[p+0] = s[*i+0] - default: - panic("unknown character width") - } - emitter.column++ - emitter.buffer_pos += w - *i += w - return true -} - -// Write a whole string into buffer. -func write_all(emitter *yaml_emitter_t, s []byte) bool { - for i := 0; i < len(s); { - if !write(emitter, s, &i) { - return false - } - } - return true -} - -// Copy a line break character from a string into buffer. -func write_break(emitter *yaml_emitter_t, s []byte, i *int) bool { - if s[*i] == '\n' { - if !put_break(emitter) { - return false - } - *i++ - } else { - if !write(emitter, s, i) { - return false - } - emitter.column = 0 - emitter.line++ - } - return true -} - -// Set an emitter error and return false. -func yaml_emitter_set_emitter_error(emitter *yaml_emitter_t, problem string) bool { - emitter.error = yaml_EMITTER_ERROR - emitter.problem = problem - return false -} - -// Emit an event. -func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool { - emitter.events = append(emitter.events, *event) - for !yaml_emitter_need_more_events(emitter) { - event := &emitter.events[emitter.events_head] - if !yaml_emitter_analyze_event(emitter, event) { - return false - } - if !yaml_emitter_state_machine(emitter, event) { - return false - } - yaml_event_delete(event) - emitter.events_head++ - } - return true -} - -// Check if we need to accumulate more events before emitting. -// -// We accumulate extra -// - 1 event for DOCUMENT-START -// - 2 events for SEQUENCE-START -// - 3 events for MAPPING-START -// -func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool { - if emitter.events_head == len(emitter.events) { - return true - } - var accumulate int - switch emitter.events[emitter.events_head].typ { - case yaml_DOCUMENT_START_EVENT: - accumulate = 1 - break - case yaml_SEQUENCE_START_EVENT: - accumulate = 2 - break - case yaml_MAPPING_START_EVENT: - accumulate = 3 - break - default: - return false - } - if len(emitter.events)-emitter.events_head > accumulate { - return false - } - var level int - for i := emitter.events_head; i < len(emitter.events); i++ { - switch emitter.events[i].typ { - case yaml_STREAM_START_EVENT, yaml_DOCUMENT_START_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT: - level++ - case yaml_STREAM_END_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_END_EVENT, yaml_MAPPING_END_EVENT: - level-- - } - if level == 0 { - return false - } - } - return true -} - -// Append a directive to the directives stack. -func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t, value *yaml_tag_directive_t, allow_duplicates bool) bool { - for i := 0; i < len(emitter.tag_directives); i++ { - if bytes.Equal(value.handle, emitter.tag_directives[i].handle) { - if allow_duplicates { - return true - } - return yaml_emitter_set_emitter_error(emitter, "duplicate %TAG directive") - } - } - - // [Go] Do we actually need to copy this given garbage collection - // and the lack of deallocating destructors? - tag_copy := yaml_tag_directive_t{ - handle: make([]byte, len(value.handle)), - prefix: make([]byte, len(value.prefix)), - } - copy(tag_copy.handle, value.handle) - copy(tag_copy.prefix, value.prefix) - emitter.tag_directives = append(emitter.tag_directives, tag_copy) - return true -} - -// Increase the indentation level. -func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool) bool { - emitter.indents = append(emitter.indents, emitter.indent) - if emitter.indent < 0 { - if flow { - emitter.indent = emitter.best_indent - } else { - emitter.indent = 0 - } - } else if !indentless { - emitter.indent += emitter.best_indent - } - return true -} - -// State dispatcher. -func yaml_emitter_state_machine(emitter *yaml_emitter_t, event *yaml_event_t) bool { - switch emitter.state { - default: - case yaml_EMIT_STREAM_START_STATE: - return yaml_emitter_emit_stream_start(emitter, event) - - case yaml_EMIT_FIRST_DOCUMENT_START_STATE: - return yaml_emitter_emit_document_start(emitter, event, true) - - case yaml_EMIT_DOCUMENT_START_STATE: - return yaml_emitter_emit_document_start(emitter, event, false) - - case yaml_EMIT_DOCUMENT_CONTENT_STATE: - return yaml_emitter_emit_document_content(emitter, event) - - case yaml_EMIT_DOCUMENT_END_STATE: - return yaml_emitter_emit_document_end(emitter, event) - - case yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE: - return yaml_emitter_emit_flow_sequence_item(emitter, event, true) - - case yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE: - return yaml_emitter_emit_flow_sequence_item(emitter, event, false) - - case yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE: - return yaml_emitter_emit_flow_mapping_key(emitter, event, true) - - case yaml_EMIT_FLOW_MAPPING_KEY_STATE: - return yaml_emitter_emit_flow_mapping_key(emitter, event, false) - - case yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE: - return yaml_emitter_emit_flow_mapping_value(emitter, event, true) - - case yaml_EMIT_FLOW_MAPPING_VALUE_STATE: - return yaml_emitter_emit_flow_mapping_value(emitter, event, false) - - case yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE: - return yaml_emitter_emit_block_sequence_item(emitter, event, true) - - case yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE: - return yaml_emitter_emit_block_sequence_item(emitter, event, false) - - case yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE: - return yaml_emitter_emit_block_mapping_key(emitter, event, true) - - case yaml_EMIT_BLOCK_MAPPING_KEY_STATE: - return yaml_emitter_emit_block_mapping_key(emitter, event, false) - - case yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE: - return yaml_emitter_emit_block_mapping_value(emitter, event, true) - - case yaml_EMIT_BLOCK_MAPPING_VALUE_STATE: - return yaml_emitter_emit_block_mapping_value(emitter, event, false) - - case yaml_EMIT_END_STATE: - return yaml_emitter_set_emitter_error(emitter, "expected nothing after STREAM-END") - } - panic("invalid emitter state") -} - -// Expect STREAM-START. -func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if event.typ != yaml_STREAM_START_EVENT { - return yaml_emitter_set_emitter_error(emitter, "expected STREAM-START") - } - if emitter.encoding == yaml_ANY_ENCODING { - emitter.encoding = event.encoding - if emitter.encoding == yaml_ANY_ENCODING { - emitter.encoding = yaml_UTF8_ENCODING - } - } - if emitter.best_indent < 2 || emitter.best_indent > 9 { - emitter.best_indent = 2 - } - if emitter.best_width >= 0 && emitter.best_width <= emitter.best_indent*2 { - emitter.best_width = 80 - } - if emitter.best_width < 0 { - emitter.best_width = 1<<31 - 1 - } - if emitter.line_break == yaml_ANY_BREAK { - emitter.line_break = yaml_LN_BREAK - } - - emitter.indent = -1 - emitter.line = 0 - emitter.column = 0 - emitter.whitespace = true - emitter.indention = true - - if emitter.encoding != yaml_UTF8_ENCODING { - if !yaml_emitter_write_bom(emitter) { - return false - } - } - emitter.state = yaml_EMIT_FIRST_DOCUMENT_START_STATE - return true -} - -// Expect DOCUMENT-START or STREAM-END. -func yaml_emitter_emit_document_start(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - - if event.typ == yaml_DOCUMENT_START_EVENT { - - if event.version_directive != nil { - if !yaml_emitter_analyze_version_directive(emitter, event.version_directive) { - return false - } - } - - for i := 0; i < len(event.tag_directives); i++ { - tag_directive := &event.tag_directives[i] - if !yaml_emitter_analyze_tag_directive(emitter, tag_directive) { - return false - } - if !yaml_emitter_append_tag_directive(emitter, tag_directive, false) { - return false - } - } - - for i := 0; i < len(default_tag_directives); i++ { - tag_directive := &default_tag_directives[i] - if !yaml_emitter_append_tag_directive(emitter, tag_directive, true) { - return false - } - } - - implicit := event.implicit - if !first || emitter.canonical { - implicit = false - } - - if emitter.open_ended && (event.version_directive != nil || len(event.tag_directives) > 0) { - if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - - if event.version_directive != nil { - implicit = false - if !yaml_emitter_write_indicator(emitter, []byte("%YAML"), true, false, false) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte("1.1"), true, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - - if len(event.tag_directives) > 0 { - implicit = false - for i := 0; i < len(event.tag_directives); i++ { - tag_directive := &event.tag_directives[i] - if !yaml_emitter_write_indicator(emitter, []byte("%TAG"), true, false, false) { - return false - } - if !yaml_emitter_write_tag_handle(emitter, tag_directive.handle) { - return false - } - if !yaml_emitter_write_tag_content(emitter, tag_directive.prefix, true) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - } - - if yaml_emitter_check_empty_document(emitter) { - implicit = false - } - if !implicit { - if !yaml_emitter_write_indent(emitter) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) { - return false - } - if emitter.canonical { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - } - - emitter.state = yaml_EMIT_DOCUMENT_CONTENT_STATE - return true - } - - if event.typ == yaml_STREAM_END_EVENT { - if emitter.open_ended { - if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_flush(emitter) { - return false - } - emitter.state = yaml_EMIT_END_STATE - return true - } - - return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-START or STREAM-END") -} - -// Expect the root node. -func yaml_emitter_emit_document_content(emitter *yaml_emitter_t, event *yaml_event_t) bool { - emitter.states = append(emitter.states, yaml_EMIT_DOCUMENT_END_STATE) - return yaml_emitter_emit_node(emitter, event, true, false, false, false) -} - -// Expect DOCUMENT-END. -func yaml_emitter_emit_document_end(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if event.typ != yaml_DOCUMENT_END_EVENT { - return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-END") - } - if !yaml_emitter_write_indent(emitter) { - return false - } - if !event.implicit { - // [Go] Allocate the slice elsewhere. - if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_flush(emitter) { - return false - } - emitter.state = yaml_EMIT_DOCUMENT_START_STATE - emitter.tag_directives = emitter.tag_directives[:0] - return true -} - -// Expect a flow item node. -func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - if first { - if !yaml_emitter_write_indicator(emitter, []byte{'['}, true, true, false) { - return false - } - if !yaml_emitter_increase_indent(emitter, true, false) { - return false - } - emitter.flow_level++ - } - - if event.typ == yaml_SEQUENCE_END_EVENT { - emitter.flow_level-- - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - if emitter.canonical && !first { - if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{']'}, false, false, false) { - return false - } - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - - return true - } - - if !first { - if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { - return false - } - } - - if emitter.canonical || emitter.column > emitter.best_width { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE) - return yaml_emitter_emit_node(emitter, event, false, true, false, false) -} - -// Expect a flow key node. -func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - if first { - if !yaml_emitter_write_indicator(emitter, []byte{'{'}, true, true, false) { - return false - } - if !yaml_emitter_increase_indent(emitter, true, false) { - return false - } - emitter.flow_level++ - } - - if event.typ == yaml_MAPPING_END_EVENT { - emitter.flow_level-- - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - if emitter.canonical && !first { - if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{'}'}, false, false, false) { - return false - } - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true - } - - if !first { - if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { - return false - } - } - if emitter.canonical || emitter.column > emitter.best_width { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - - if !emitter.canonical && yaml_emitter_check_simple_key(emitter) { - emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, true) - } - if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, false) { - return false - } - emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_VALUE_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, false) -} - -// Expect a flow value node. -func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool { - if simple { - if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) { - return false - } - } else { - if emitter.canonical || emitter.column > emitter.best_width { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, false) { - return false - } - } - emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, false) -} - -// Expect a block item node. -func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - if first { - if !yaml_emitter_increase_indent(emitter, false, emitter.mapping_context && !emitter.indention) { - return false - } - } - if event.typ == yaml_SEQUENCE_END_EVENT { - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true - } - if !yaml_emitter_write_indent(emitter) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte{'-'}, true, false, true) { - return false - } - emitter.states = append(emitter.states, yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE) - return yaml_emitter_emit_node(emitter, event, false, true, false, false) -} - -// Expect a block key node. -func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - if first { - if !yaml_emitter_increase_indent(emitter, false, false) { - return false - } - } - if event.typ == yaml_MAPPING_END_EVENT { - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true - } - if !yaml_emitter_write_indent(emitter) { - return false - } - if yaml_emitter_check_simple_key(emitter) { - emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, true) - } - if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, true) { - return false - } - emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_VALUE_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, false) -} - -// Expect a block value node. -func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool { - if simple { - if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) { - return false - } - } else { - if !yaml_emitter_write_indent(emitter) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, true) { - return false - } - } - emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, false) -} - -// Expect a node. -func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t, - root bool, sequence bool, mapping bool, simple_key bool) bool { - - emitter.root_context = root - emitter.sequence_context = sequence - emitter.mapping_context = mapping - emitter.simple_key_context = simple_key - - switch event.typ { - case yaml_ALIAS_EVENT: - return yaml_emitter_emit_alias(emitter, event) - case yaml_SCALAR_EVENT: - return yaml_emitter_emit_scalar(emitter, event) - case yaml_SEQUENCE_START_EVENT: - return yaml_emitter_emit_sequence_start(emitter, event) - case yaml_MAPPING_START_EVENT: - return yaml_emitter_emit_mapping_start(emitter, event) - default: - return yaml_emitter_set_emitter_error(emitter, - fmt.Sprintf("expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got %v", event.typ)) - } -} - -// Expect ALIAS. -func yaml_emitter_emit_alias(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if !yaml_emitter_process_anchor(emitter) { - return false - } - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true -} - -// Expect SCALAR. -func yaml_emitter_emit_scalar(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if !yaml_emitter_select_scalar_style(emitter, event) { - return false - } - if !yaml_emitter_process_anchor(emitter) { - return false - } - if !yaml_emitter_process_tag(emitter) { - return false - } - if !yaml_emitter_increase_indent(emitter, true, false) { - return false - } - if !yaml_emitter_process_scalar(emitter) { - return false - } - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true -} - -// Expect SEQUENCE-START. -func yaml_emitter_emit_sequence_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if !yaml_emitter_process_anchor(emitter) { - return false - } - if !yaml_emitter_process_tag(emitter) { - return false - } - if emitter.flow_level > 0 || emitter.canonical || event.sequence_style() == yaml_FLOW_SEQUENCE_STYLE || - yaml_emitter_check_empty_sequence(emitter) { - emitter.state = yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE - } else { - emitter.state = yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE - } - return true -} - -// Expect MAPPING-START. -func yaml_emitter_emit_mapping_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if !yaml_emitter_process_anchor(emitter) { - return false - } - if !yaml_emitter_process_tag(emitter) { - return false - } - if emitter.flow_level > 0 || emitter.canonical || event.mapping_style() == yaml_FLOW_MAPPING_STYLE || - yaml_emitter_check_empty_mapping(emitter) { - emitter.state = yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE - } else { - emitter.state = yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE - } - return true -} - -// Check if the document content is an empty scalar. -func yaml_emitter_check_empty_document(emitter *yaml_emitter_t) bool { - return false // [Go] Huh? -} - -// Check if the next events represent an empty sequence. -func yaml_emitter_check_empty_sequence(emitter *yaml_emitter_t) bool { - if len(emitter.events)-emitter.events_head < 2 { - return false - } - return emitter.events[emitter.events_head].typ == yaml_SEQUENCE_START_EVENT && - emitter.events[emitter.events_head+1].typ == yaml_SEQUENCE_END_EVENT -} - -// Check if the next events represent an empty mapping. -func yaml_emitter_check_empty_mapping(emitter *yaml_emitter_t) bool { - if len(emitter.events)-emitter.events_head < 2 { - return false - } - return emitter.events[emitter.events_head].typ == yaml_MAPPING_START_EVENT && - emitter.events[emitter.events_head+1].typ == yaml_MAPPING_END_EVENT -} - -// Check if the next node can be expressed as a simple key. -func yaml_emitter_check_simple_key(emitter *yaml_emitter_t) bool { - length := 0 - switch emitter.events[emitter.events_head].typ { - case yaml_ALIAS_EVENT: - length += len(emitter.anchor_data.anchor) - case yaml_SCALAR_EVENT: - if emitter.scalar_data.multiline { - return false - } - length += len(emitter.anchor_data.anchor) + - len(emitter.tag_data.handle) + - len(emitter.tag_data.suffix) + - len(emitter.scalar_data.value) - case yaml_SEQUENCE_START_EVENT: - if !yaml_emitter_check_empty_sequence(emitter) { - return false - } - length += len(emitter.anchor_data.anchor) + - len(emitter.tag_data.handle) + - len(emitter.tag_data.suffix) - case yaml_MAPPING_START_EVENT: - if !yaml_emitter_check_empty_mapping(emitter) { - return false - } - length += len(emitter.anchor_data.anchor) + - len(emitter.tag_data.handle) + - len(emitter.tag_data.suffix) - default: - return false - } - return length <= 128 -} - -// Determine an acceptable scalar style. -func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event_t) bool { - - no_tag := len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 - if no_tag && !event.implicit && !event.quoted_implicit { - return yaml_emitter_set_emitter_error(emitter, "neither tag nor implicit flags are specified") - } - - style := event.scalar_style() - if style == yaml_ANY_SCALAR_STYLE { - style = yaml_PLAIN_SCALAR_STYLE - } - if emitter.canonical { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - if emitter.simple_key_context && emitter.scalar_data.multiline { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - - if style == yaml_PLAIN_SCALAR_STYLE { - if emitter.flow_level > 0 && !emitter.scalar_data.flow_plain_allowed || - emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed { - style = yaml_SINGLE_QUOTED_SCALAR_STYLE - } - if len(emitter.scalar_data.value) == 0 && (emitter.flow_level > 0 || emitter.simple_key_context) { - style = yaml_SINGLE_QUOTED_SCALAR_STYLE - } - if no_tag && !event.implicit { - style = yaml_SINGLE_QUOTED_SCALAR_STYLE - } - } - if style == yaml_SINGLE_QUOTED_SCALAR_STYLE { - if !emitter.scalar_data.single_quoted_allowed { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - } - if style == yaml_LITERAL_SCALAR_STYLE || style == yaml_FOLDED_SCALAR_STYLE { - if !emitter.scalar_data.block_allowed || emitter.flow_level > 0 || emitter.simple_key_context { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - } - - if no_tag && !event.quoted_implicit && style != yaml_PLAIN_SCALAR_STYLE { - emitter.tag_data.handle = []byte{'!'} - } - emitter.scalar_data.style = style - return true -} - -// Write an anchor. -func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool { - if emitter.anchor_data.anchor == nil { - return true - } - c := []byte{'&'} - if emitter.anchor_data.alias { - c[0] = '*' - } - if !yaml_emitter_write_indicator(emitter, c, true, false, false) { - return false - } - return yaml_emitter_write_anchor(emitter, emitter.anchor_data.anchor) -} - -// Write a tag. -func yaml_emitter_process_tag(emitter *yaml_emitter_t) bool { - if len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 { - return true - } - if len(emitter.tag_data.handle) > 0 { - if !yaml_emitter_write_tag_handle(emitter, emitter.tag_data.handle) { - return false - } - if len(emitter.tag_data.suffix) > 0 { - if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) { - return false - } - } - } else { - // [Go] Allocate these slices elsewhere. - if !yaml_emitter_write_indicator(emitter, []byte("!<"), true, false, false) { - return false - } - if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte{'>'}, false, false, false) { - return false - } - } - return true -} - -// Write a scalar. -func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool { - switch emitter.scalar_data.style { - case yaml_PLAIN_SCALAR_STYLE: - return yaml_emitter_write_plain_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) - - case yaml_SINGLE_QUOTED_SCALAR_STYLE: - return yaml_emitter_write_single_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) - - case yaml_DOUBLE_QUOTED_SCALAR_STYLE: - return yaml_emitter_write_double_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) - - case yaml_LITERAL_SCALAR_STYLE: - return yaml_emitter_write_literal_scalar(emitter, emitter.scalar_data.value) - - case yaml_FOLDED_SCALAR_STYLE: - return yaml_emitter_write_folded_scalar(emitter, emitter.scalar_data.value) - } - panic("unknown scalar style") -} - -// Check if a %YAML directive is valid. -func yaml_emitter_analyze_version_directive(emitter *yaml_emitter_t, version_directive *yaml_version_directive_t) bool { - if version_directive.major != 1 || version_directive.minor != 1 { - return yaml_emitter_set_emitter_error(emitter, "incompatible %YAML directive") - } - return true -} - -// Check if a %TAG directive is valid. -func yaml_emitter_analyze_tag_directive(emitter *yaml_emitter_t, tag_directive *yaml_tag_directive_t) bool { - handle := tag_directive.handle - prefix := tag_directive.prefix - if len(handle) == 0 { - return yaml_emitter_set_emitter_error(emitter, "tag handle must not be empty") - } - if handle[0] != '!' { - return yaml_emitter_set_emitter_error(emitter, "tag handle must start with '!'") - } - if handle[len(handle)-1] != '!' { - return yaml_emitter_set_emitter_error(emitter, "tag handle must end with '!'") - } - for i := 1; i < len(handle)-1; i += width(handle[i]) { - if !is_alpha(handle, i) { - return yaml_emitter_set_emitter_error(emitter, "tag handle must contain alphanumerical characters only") - } - } - if len(prefix) == 0 { - return yaml_emitter_set_emitter_error(emitter, "tag prefix must not be empty") - } - return true -} - -// Check if an anchor is valid. -func yaml_emitter_analyze_anchor(emitter *yaml_emitter_t, anchor []byte, alias bool) bool { - if len(anchor) == 0 { - problem := "anchor value must not be empty" - if alias { - problem = "alias value must not be empty" - } - return yaml_emitter_set_emitter_error(emitter, problem) - } - for i := 0; i < len(anchor); i += width(anchor[i]) { - if !is_alpha(anchor, i) { - problem := "anchor value must contain alphanumerical characters only" - if alias { - problem = "alias value must contain alphanumerical characters only" - } - return yaml_emitter_set_emitter_error(emitter, problem) - } - } - emitter.anchor_data.anchor = anchor - emitter.anchor_data.alias = alias - return true -} - -// Check if a tag is valid. -func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool { - if len(tag) == 0 { - return yaml_emitter_set_emitter_error(emitter, "tag value must not be empty") - } - for i := 0; i < len(emitter.tag_directives); i++ { - tag_directive := &emitter.tag_directives[i] - if bytes.HasPrefix(tag, tag_directive.prefix) { - emitter.tag_data.handle = tag_directive.handle - emitter.tag_data.suffix = tag[len(tag_directive.prefix):] - return true - } - } - emitter.tag_data.suffix = tag - return true -} - -// Check if a scalar is valid. -func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool { - var ( - block_indicators = false - flow_indicators = false - line_breaks = false - special_characters = false - - leading_space = false - leading_break = false - trailing_space = false - trailing_break = false - break_space = false - space_break = false - - preceded_by_whitespace = false - followed_by_whitespace = false - previous_space = false - previous_break = false - ) - - emitter.scalar_data.value = value - - if len(value) == 0 { - emitter.scalar_data.multiline = false - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = true - emitter.scalar_data.single_quoted_allowed = true - emitter.scalar_data.block_allowed = false - return true - } - - if len(value) >= 3 && ((value[0] == '-' && value[1] == '-' && value[2] == '-') || (value[0] == '.' && value[1] == '.' && value[2] == '.')) { - block_indicators = true - flow_indicators = true - } - - preceded_by_whitespace = true - for i, w := 0, 0; i < len(value); i += w { - w = width(value[i]) - followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w) - - if i == 0 { - switch value[i] { - case '#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`': - flow_indicators = true - block_indicators = true - case '?', ':': - flow_indicators = true - if followed_by_whitespace { - block_indicators = true - } - case '-': - if followed_by_whitespace { - flow_indicators = true - block_indicators = true - } - } - } else { - switch value[i] { - case ',', '?', '[', ']', '{', '}': - flow_indicators = true - case ':': - flow_indicators = true - if followed_by_whitespace { - block_indicators = true - } - case '#': - if preceded_by_whitespace { - flow_indicators = true - block_indicators = true - } - } - } - - if !is_printable(value, i) || !is_ascii(value, i) && !emitter.unicode { - special_characters = true - } - if is_space(value, i) { - if i == 0 { - leading_space = true - } - if i+width(value[i]) == len(value) { - trailing_space = true - } - if previous_break { - break_space = true - } - previous_space = true - previous_break = false - } else if is_break(value, i) { - line_breaks = true - if i == 0 { - leading_break = true - } - if i+width(value[i]) == len(value) { - trailing_break = true - } - if previous_space { - space_break = true - } - previous_space = false - previous_break = true - } else { - previous_space = false - previous_break = false - } - - // [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition. - preceded_by_whitespace = is_blankz(value, i) - } - - emitter.scalar_data.multiline = line_breaks - emitter.scalar_data.flow_plain_allowed = true - emitter.scalar_data.block_plain_allowed = true - emitter.scalar_data.single_quoted_allowed = true - emitter.scalar_data.block_allowed = true - - if leading_space || leading_break || trailing_space || trailing_break { - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = false - } - if trailing_space { - emitter.scalar_data.block_allowed = false - } - if break_space { - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = false - emitter.scalar_data.single_quoted_allowed = false - } - if space_break || special_characters { - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = false - emitter.scalar_data.single_quoted_allowed = false - emitter.scalar_data.block_allowed = false - } - if line_breaks { - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = false - } - if flow_indicators { - emitter.scalar_data.flow_plain_allowed = false - } - if block_indicators { - emitter.scalar_data.block_plain_allowed = false - } - return true -} - -// Check if the event data is valid. -func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bool { - - emitter.anchor_data.anchor = nil - emitter.tag_data.handle = nil - emitter.tag_data.suffix = nil - emitter.scalar_data.value = nil - - switch event.typ { - case yaml_ALIAS_EVENT: - if !yaml_emitter_analyze_anchor(emitter, event.anchor, true) { - return false - } - - case yaml_SCALAR_EVENT: - if len(event.anchor) > 0 { - if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { - return false - } - } - if len(event.tag) > 0 && (emitter.canonical || (!event.implicit && !event.quoted_implicit)) { - if !yaml_emitter_analyze_tag(emitter, event.tag) { - return false - } - } - if !yaml_emitter_analyze_scalar(emitter, event.value) { - return false - } - - case yaml_SEQUENCE_START_EVENT: - if len(event.anchor) > 0 { - if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { - return false - } - } - if len(event.tag) > 0 && (emitter.canonical || !event.implicit) { - if !yaml_emitter_analyze_tag(emitter, event.tag) { - return false - } - } - - case yaml_MAPPING_START_EVENT: - if len(event.anchor) > 0 { - if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { - return false - } - } - if len(event.tag) > 0 && (emitter.canonical || !event.implicit) { - if !yaml_emitter_analyze_tag(emitter, event.tag) { - return false - } - } - } - return true -} - -// Write the BOM character. -func yaml_emitter_write_bom(emitter *yaml_emitter_t) bool { - if !flush(emitter) { - return false - } - pos := emitter.buffer_pos - emitter.buffer[pos+0] = '\xEF' - emitter.buffer[pos+1] = '\xBB' - emitter.buffer[pos+2] = '\xBF' - emitter.buffer_pos += 3 - return true -} - -func yaml_emitter_write_indent(emitter *yaml_emitter_t) bool { - indent := emitter.indent - if indent < 0 { - indent = 0 - } - if !emitter.indention || emitter.column > indent || (emitter.column == indent && !emitter.whitespace) { - if !put_break(emitter) { - return false - } - } - for emitter.column < indent { - if !put(emitter, ' ') { - return false - } - } - emitter.whitespace = true - emitter.indention = true - return true -} - -func yaml_emitter_write_indicator(emitter *yaml_emitter_t, indicator []byte, need_whitespace, is_whitespace, is_indention bool) bool { - if need_whitespace && !emitter.whitespace { - if !put(emitter, ' ') { - return false - } - } - if !write_all(emitter, indicator) { - return false - } - emitter.whitespace = is_whitespace - emitter.indention = (emitter.indention && is_indention) - emitter.open_ended = false - return true -} - -func yaml_emitter_write_anchor(emitter *yaml_emitter_t, value []byte) bool { - if !write_all(emitter, value) { - return false - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_tag_handle(emitter *yaml_emitter_t, value []byte) bool { - if !emitter.whitespace { - if !put(emitter, ' ') { - return false - } - } - if !write_all(emitter, value) { - return false - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte, need_whitespace bool) bool { - if need_whitespace && !emitter.whitespace { - if !put(emitter, ' ') { - return false - } - } - for i := 0; i < len(value); { - var must_write bool - switch value[i] { - case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '~', '*', '\'', '(', ')', '[', ']': - must_write = true - default: - must_write = is_alpha(value, i) - } - if must_write { - if !write(emitter, value, &i) { - return false - } - } else { - w := width(value[i]) - for k := 0; k < w; k++ { - octet := value[i] - i++ - if !put(emitter, '%') { - return false - } - - c := octet >> 4 - if c < 10 { - c += '0' - } else { - c += 'A' - 10 - } - if !put(emitter, c) { - return false - } - - c = octet & 0x0f - if c < 10 { - c += '0' - } else { - c += 'A' - 10 - } - if !put(emitter, c) { - return false - } - } - } - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_plain_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { - if !emitter.whitespace { - if !put(emitter, ' ') { - return false - } - } - - spaces := false - breaks := false - for i := 0; i < len(value); { - if is_space(value, i) { - if allow_breaks && !spaces && emitter.column > emitter.best_width && !is_space(value, i+1) { - if !yaml_emitter_write_indent(emitter) { - return false - } - i += width(value[i]) - } else { - if !write(emitter, value, &i) { - return false - } - } - spaces = true - } else if is_break(value, i) { - if !breaks && value[i] == '\n' { - if !put_break(emitter) { - return false - } - } - if !write_break(emitter, value, &i) { - return false - } - emitter.indention = true - breaks = true - } else { - if breaks { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !write(emitter, value, &i) { - return false - } - emitter.indention = false - spaces = false - breaks = false - } - } - - emitter.whitespace = false - emitter.indention = false - if emitter.root_context { - emitter.open_ended = true - } - - return true -} - -func yaml_emitter_write_single_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { - - if !yaml_emitter_write_indicator(emitter, []byte{'\''}, true, false, false) { - return false - } - - spaces := false - breaks := false - for i := 0; i < len(value); { - if is_space(value, i) { - if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 && !is_space(value, i+1) { - if !yaml_emitter_write_indent(emitter) { - return false - } - i += width(value[i]) - } else { - if !write(emitter, value, &i) { - return false - } - } - spaces = true - } else if is_break(value, i) { - if !breaks && value[i] == '\n' { - if !put_break(emitter) { - return false - } - } - if !write_break(emitter, value, &i) { - return false - } - emitter.indention = true - breaks = true - } else { - if breaks { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if value[i] == '\'' { - if !put(emitter, '\'') { - return false - } - } - if !write(emitter, value, &i) { - return false - } - emitter.indention = false - spaces = false - breaks = false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{'\''}, false, false, false) { - return false - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_double_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { - spaces := false - if !yaml_emitter_write_indicator(emitter, []byte{'"'}, true, false, false) { - return false - } - - for i := 0; i < len(value); { - if !is_printable(value, i) || (!emitter.unicode && !is_ascii(value, i)) || - is_bom(value, i) || is_break(value, i) || - value[i] == '"' || value[i] == '\\' { - - octet := value[i] - - var w int - var v rune - switch { - case octet&0x80 == 0x00: - w, v = 1, rune(octet&0x7F) - case octet&0xE0 == 0xC0: - w, v = 2, rune(octet&0x1F) - case octet&0xF0 == 0xE0: - w, v = 3, rune(octet&0x0F) - case octet&0xF8 == 0xF0: - w, v = 4, rune(octet&0x07) - } - for k := 1; k < w; k++ { - octet = value[i+k] - v = (v << 6) + (rune(octet) & 0x3F) - } - i += w - - if !put(emitter, '\\') { - return false - } - - var ok bool - switch v { - case 0x00: - ok = put(emitter, '0') - case 0x07: - ok = put(emitter, 'a') - case 0x08: - ok = put(emitter, 'b') - case 0x09: - ok = put(emitter, 't') - case 0x0A: - ok = put(emitter, 'n') - case 0x0b: - ok = put(emitter, 'v') - case 0x0c: - ok = put(emitter, 'f') - case 0x0d: - ok = put(emitter, 'r') - case 0x1b: - ok = put(emitter, 'e') - case 0x22: - ok = put(emitter, '"') - case 0x5c: - ok = put(emitter, '\\') - case 0x85: - ok = put(emitter, 'N') - case 0xA0: - ok = put(emitter, '_') - case 0x2028: - ok = put(emitter, 'L') - case 0x2029: - ok = put(emitter, 'P') - default: - if v <= 0xFF { - ok = put(emitter, 'x') - w = 2 - } else if v <= 0xFFFF { - ok = put(emitter, 'u') - w = 4 - } else { - ok = put(emitter, 'U') - w = 8 - } - for k := (w - 1) * 4; ok && k >= 0; k -= 4 { - digit := byte((v >> uint(k)) & 0x0F) - if digit < 10 { - ok = put(emitter, digit+'0') - } else { - ok = put(emitter, digit+'A'-10) - } - } - } - if !ok { - return false - } - spaces = false - } else if is_space(value, i) { - if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 { - if !yaml_emitter_write_indent(emitter) { - return false - } - if is_space(value, i+1) { - if !put(emitter, '\\') { - return false - } - } - i += width(value[i]) - } else if !write(emitter, value, &i) { - return false - } - spaces = true - } else { - if !write(emitter, value, &i) { - return false - } - spaces = false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{'"'}, false, false, false) { - return false - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_block_scalar_hints(emitter *yaml_emitter_t, value []byte) bool { - if is_space(value, 0) || is_break(value, 0) { - indent_hint := []byte{'0' + byte(emitter.best_indent)} - if !yaml_emitter_write_indicator(emitter, indent_hint, false, false, false) { - return false - } - } - - emitter.open_ended = false - - var chomp_hint [1]byte - if len(value) == 0 { - chomp_hint[0] = '-' - } else { - i := len(value) - 1 - for value[i]&0xC0 == 0x80 { - i-- - } - if !is_break(value, i) { - chomp_hint[0] = '-' - } else if i == 0 { - chomp_hint[0] = '+' - emitter.open_ended = true - } else { - i-- - for value[i]&0xC0 == 0x80 { - i-- - } - if is_break(value, i) { - chomp_hint[0] = '+' - emitter.open_ended = true - } - } - } - if chomp_hint[0] != 0 { - if !yaml_emitter_write_indicator(emitter, chomp_hint[:], false, false, false) { - return false - } - } - return true -} - -func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bool { - if !yaml_emitter_write_indicator(emitter, []byte{'|'}, true, false, false) { - return false - } - if !yaml_emitter_write_block_scalar_hints(emitter, value) { - return false - } - if !put_break(emitter) { - return false - } - emitter.indention = true - emitter.whitespace = true - breaks := true - for i := 0; i < len(value); { - if is_break(value, i) { - if !write_break(emitter, value, &i) { - return false - } - emitter.indention = true - breaks = true - } else { - if breaks { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !write(emitter, value, &i) { - return false - } - emitter.indention = false - breaks = false - } - } - - return true -} - -func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) bool { - if !yaml_emitter_write_indicator(emitter, []byte{'>'}, true, false, false) { - return false - } - if !yaml_emitter_write_block_scalar_hints(emitter, value) { - return false - } - - if !put_break(emitter) { - return false - } - emitter.indention = true - emitter.whitespace = true - - breaks := true - leading_spaces := true - for i := 0; i < len(value); { - if is_break(value, i) { - if !breaks && !leading_spaces && value[i] == '\n' { - k := 0 - for is_break(value, k) { - k += width(value[k]) - } - if !is_blankz(value, k) { - if !put_break(emitter) { - return false - } - } - } - if !write_break(emitter, value, &i) { - return false - } - emitter.indention = true - breaks = true - } else { - if breaks { - if !yaml_emitter_write_indent(emitter) { - return false - } - leading_spaces = is_blank(value, i) - } - if !breaks && is_space(value, i) && !is_space(value, i+1) && emitter.column > emitter.best_width { - if !yaml_emitter_write_indent(emitter) { - return false - } - i += width(value[i]) - } else { - if !write(emitter, value, &i) { - return false - } - } - emitter.indention = false - breaks = false - } - } - return true -} diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/encode.go b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/encode.go deleted file mode 100755 index a14435e..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/encode.go +++ /dev/null @@ -1,362 +0,0 @@ -package yaml - -import ( - "encoding" - "fmt" - "io" - "reflect" - "regexp" - "sort" - "strconv" - "strings" - "time" - "unicode/utf8" -) - -type encoder struct { - emitter yaml_emitter_t - event yaml_event_t - out []byte - flow bool - // doneInit holds whether the initial stream_start_event has been - // emitted. - doneInit bool -} - -func newEncoder() *encoder { - e := &encoder{} - yaml_emitter_initialize(&e.emitter) - yaml_emitter_set_output_string(&e.emitter, &e.out) - yaml_emitter_set_unicode(&e.emitter, true) - return e -} - -func newEncoderWithWriter(w io.Writer) *encoder { - e := &encoder{} - yaml_emitter_initialize(&e.emitter) - yaml_emitter_set_output_writer(&e.emitter, w) - yaml_emitter_set_unicode(&e.emitter, true) - return e -} - -func (e *encoder) init() { - if e.doneInit { - return - } - yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING) - e.emit() - e.doneInit = true -} - -func (e *encoder) finish() { - e.emitter.open_ended = false - yaml_stream_end_event_initialize(&e.event) - e.emit() -} - -func (e *encoder) destroy() { - yaml_emitter_delete(&e.emitter) -} - -func (e *encoder) emit() { - // This will internally delete the e.event value. - e.must(yaml_emitter_emit(&e.emitter, &e.event)) -} - -func (e *encoder) must(ok bool) { - if !ok { - msg := e.emitter.problem - if msg == "" { - msg = "unknown problem generating YAML content" - } - failf("%s", msg) - } -} - -func (e *encoder) marshalDoc(tag string, in reflect.Value) { - e.init() - yaml_document_start_event_initialize(&e.event, nil, nil, true) - e.emit() - e.marshal(tag, in) - yaml_document_end_event_initialize(&e.event, true) - e.emit() -} - -func (e *encoder) marshal(tag string, in reflect.Value) { - if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() { - e.nilv() - return - } - iface := in.Interface() - switch m := iface.(type) { - case time.Time, *time.Time: - // Although time.Time implements TextMarshaler, - // we don't want to treat it as a string for YAML - // purposes because YAML has special support for - // timestamps. - case Marshaler: - v, err := m.MarshalYAML() - if err != nil { - fail(err) - } - if v == nil { - e.nilv() - return - } - in = reflect.ValueOf(v) - case encoding.TextMarshaler: - text, err := m.MarshalText() - if err != nil { - fail(err) - } - in = reflect.ValueOf(string(text)) - case nil: - e.nilv() - return - } - switch in.Kind() { - case reflect.Interface: - e.marshal(tag, in.Elem()) - case reflect.Map: - e.mapv(tag, in) - case reflect.Ptr: - if in.Type() == ptrTimeType { - e.timev(tag, in.Elem()) - } else { - e.marshal(tag, in.Elem()) - } - case reflect.Struct: - if in.Type() == timeType { - e.timev(tag, in) - } else { - e.structv(tag, in) - } - case reflect.Slice, reflect.Array: - if in.Type().Elem() == mapItemType { - e.itemsv(tag, in) - } else { - e.slicev(tag, in) - } - case reflect.String: - e.stringv(tag, in) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if in.Type() == durationType { - e.stringv(tag, reflect.ValueOf(iface.(time.Duration).String())) - } else { - e.intv(tag, in) - } - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - e.uintv(tag, in) - case reflect.Float32, reflect.Float64: - e.floatv(tag, in) - case reflect.Bool: - e.boolv(tag, in) - default: - panic("cannot marshal type: " + in.Type().String()) - } -} - -func (e *encoder) mapv(tag string, in reflect.Value) { - e.mappingv(tag, func() { - keys := keyList(in.MapKeys()) - sort.Sort(keys) - for _, k := range keys { - e.marshal("", k) - e.marshal("", in.MapIndex(k)) - } - }) -} - -func (e *encoder) itemsv(tag string, in reflect.Value) { - e.mappingv(tag, func() { - slice := in.Convert(reflect.TypeOf([]MapItem{})).Interface().([]MapItem) - for _, item := range slice { - e.marshal("", reflect.ValueOf(item.Key)) - e.marshal("", reflect.ValueOf(item.Value)) - } - }) -} - -func (e *encoder) structv(tag string, in reflect.Value) { - sinfo, err := getStructInfo(in.Type()) - if err != nil { - panic(err) - } - e.mappingv(tag, func() { - for _, info := range sinfo.FieldsList { - var value reflect.Value - if info.Inline == nil { - value = in.Field(info.Num) - } else { - value = in.FieldByIndex(info.Inline) - } - if info.OmitEmpty && isZero(value) { - continue - } - e.marshal("", reflect.ValueOf(info.Key)) - e.flow = info.Flow - e.marshal("", value) - } - if sinfo.InlineMap >= 0 { - m := in.Field(sinfo.InlineMap) - if m.Len() > 0 { - e.flow = false - keys := keyList(m.MapKeys()) - sort.Sort(keys) - for _, k := range keys { - if _, found := sinfo.FieldsMap[k.String()]; found { - panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", k.String())) - } - e.marshal("", k) - e.flow = false - e.marshal("", m.MapIndex(k)) - } - } - } - }) -} - -func (e *encoder) mappingv(tag string, f func()) { - implicit := tag == "" - style := yaml_BLOCK_MAPPING_STYLE - if e.flow { - e.flow = false - style = yaml_FLOW_MAPPING_STYLE - } - yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style) - e.emit() - f() - yaml_mapping_end_event_initialize(&e.event) - e.emit() -} - -func (e *encoder) slicev(tag string, in reflect.Value) { - implicit := tag == "" - style := yaml_BLOCK_SEQUENCE_STYLE - if e.flow { - e.flow = false - style = yaml_FLOW_SEQUENCE_STYLE - } - e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)) - e.emit() - n := in.Len() - for i := 0; i < n; i++ { - e.marshal("", in.Index(i)) - } - e.must(yaml_sequence_end_event_initialize(&e.event)) - e.emit() -} - -// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1. -// -// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported -// in YAML 1.2 and by this package, but these should be marshalled quoted for -// the time being for compatibility with other parsers. -func isBase60Float(s string) (result bool) { - // Fast path. - if s == "" { - return false - } - c := s[0] - if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 { - return false - } - // Do the full match. - return base60float.MatchString(s) -} - -// From http://yaml.org/type/float.html, except the regular expression there -// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix. -var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`) - -func (e *encoder) stringv(tag string, in reflect.Value) { - var style yaml_scalar_style_t - s := in.String() - canUsePlain := true - switch { - case !utf8.ValidString(s): - if tag == yaml_BINARY_TAG { - failf("explicitly tagged !!binary data must be base64-encoded") - } - if tag != "" { - failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag)) - } - // It can't be encoded directly as YAML so use a binary tag - // and encode it as base64. - tag = yaml_BINARY_TAG - s = encodeBase64(s) - case tag == "": - // Check to see if it would resolve to a specific - // tag when encoded unquoted. If it doesn't, - // there's no need to quote it. - rtag, _ := resolve("", s) - canUsePlain = rtag == yaml_STR_TAG && !isBase60Float(s) - } - // Note: it's possible for user code to emit invalid YAML - // if they explicitly specify a tag and a string containing - // text that's incompatible with that tag. - switch { - case strings.Contains(s, "\n"): - style = yaml_LITERAL_SCALAR_STYLE - case canUsePlain: - style = yaml_PLAIN_SCALAR_STYLE - default: - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - e.emitScalar(s, "", tag, style) -} - -func (e *encoder) boolv(tag string, in reflect.Value) { - var s string - if in.Bool() { - s = "true" - } else { - s = "false" - } - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) intv(tag string, in reflect.Value) { - s := strconv.FormatInt(in.Int(), 10) - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) uintv(tag string, in reflect.Value) { - s := strconv.FormatUint(in.Uint(), 10) - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) timev(tag string, in reflect.Value) { - t := in.Interface().(time.Time) - s := t.Format(time.RFC3339Nano) - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) floatv(tag string, in reflect.Value) { - // Issue #352: When formatting, use the precision of the underlying value - precision := 64 - if in.Kind() == reflect.Float32 { - precision = 32 - } - - s := strconv.FormatFloat(in.Float(), 'g', -1, precision) - switch s { - case "+Inf": - s = ".inf" - case "-Inf": - s = "-.inf" - case "NaN": - s = ".nan" - } - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) nilv() { - e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) { - implicit := tag == "" - e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style)) - e.emit() -} diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/go.mod b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/go.mod deleted file mode 100755 index 1934e87..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module "gopkg.in/yaml.v2" - -require ( - "gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405 -) diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/parserc.go b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/parserc.go deleted file mode 100755 index 81d05df..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/parserc.go +++ /dev/null @@ -1,1095 +0,0 @@ -package yaml - -import ( - "bytes" -) - -// The parser implements the following grammar: -// -// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END -// implicit_document ::= block_node DOCUMENT-END* -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// block_node_or_indentless_sequence ::= -// ALIAS -// | properties (block_content | indentless_block_sequence)? -// | block_content -// | indentless_block_sequence -// block_node ::= ALIAS -// | properties block_content? -// | block_content -// flow_node ::= ALIAS -// | properties flow_content? -// | flow_content -// properties ::= TAG ANCHOR? | ANCHOR TAG? -// block_content ::= block_collection | flow_collection | SCALAR -// flow_content ::= flow_collection | SCALAR -// block_collection ::= block_sequence | block_mapping -// flow_collection ::= flow_sequence | flow_mapping -// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END -// indentless_sequence ::= (BLOCK-ENTRY block_node?)+ -// block_mapping ::= BLOCK-MAPPING_START -// ((KEY block_node_or_indentless_sequence?)? -// (VALUE block_node_or_indentless_sequence?)?)* -// BLOCK-END -// flow_sequence ::= FLOW-SEQUENCE-START -// (flow_sequence_entry FLOW-ENTRY)* -// flow_sequence_entry? -// FLOW-SEQUENCE-END -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// flow_mapping ::= FLOW-MAPPING-START -// (flow_mapping_entry FLOW-ENTRY)* -// flow_mapping_entry? -// FLOW-MAPPING-END -// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? - -// Peek the next token in the token queue. -func peek_token(parser *yaml_parser_t) *yaml_token_t { - if parser.token_available || yaml_parser_fetch_more_tokens(parser) { - return &parser.tokens[parser.tokens_head] - } - return nil -} - -// Remove the next token from the queue (must be called after peek_token). -func skip_token(parser *yaml_parser_t) { - parser.token_available = false - parser.tokens_parsed++ - parser.stream_end_produced = parser.tokens[parser.tokens_head].typ == yaml_STREAM_END_TOKEN - parser.tokens_head++ -} - -// Get the next event. -func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool { - // Erase the event object. - *event = yaml_event_t{} - - // No events after the end of the stream or error. - if parser.stream_end_produced || parser.error != yaml_NO_ERROR || parser.state == yaml_PARSE_END_STATE { - return true - } - - // Generate the next event. - return yaml_parser_state_machine(parser, event) -} - -// Set parser error. -func yaml_parser_set_parser_error(parser *yaml_parser_t, problem string, problem_mark yaml_mark_t) bool { - parser.error = yaml_PARSER_ERROR - parser.problem = problem - parser.problem_mark = problem_mark - return false -} - -func yaml_parser_set_parser_error_context(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string, problem_mark yaml_mark_t) bool { - parser.error = yaml_PARSER_ERROR - parser.context = context - parser.context_mark = context_mark - parser.problem = problem - parser.problem_mark = problem_mark - return false -} - -// State dispatcher. -func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool { - //trace("yaml_parser_state_machine", "state:", parser.state.String()) - - switch parser.state { - case yaml_PARSE_STREAM_START_STATE: - return yaml_parser_parse_stream_start(parser, event) - - case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: - return yaml_parser_parse_document_start(parser, event, true) - - case yaml_PARSE_DOCUMENT_START_STATE: - return yaml_parser_parse_document_start(parser, event, false) - - case yaml_PARSE_DOCUMENT_CONTENT_STATE: - return yaml_parser_parse_document_content(parser, event) - - case yaml_PARSE_DOCUMENT_END_STATE: - return yaml_parser_parse_document_end(parser, event) - - case yaml_PARSE_BLOCK_NODE_STATE: - return yaml_parser_parse_node(parser, event, true, false) - - case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: - return yaml_parser_parse_node(parser, event, true, true) - - case yaml_PARSE_FLOW_NODE_STATE: - return yaml_parser_parse_node(parser, event, false, false) - - case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: - return yaml_parser_parse_block_sequence_entry(parser, event, true) - - case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: - return yaml_parser_parse_block_sequence_entry(parser, event, false) - - case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: - return yaml_parser_parse_indentless_sequence_entry(parser, event) - - case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: - return yaml_parser_parse_block_mapping_key(parser, event, true) - - case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: - return yaml_parser_parse_block_mapping_key(parser, event, false) - - case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: - return yaml_parser_parse_block_mapping_value(parser, event) - - case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: - return yaml_parser_parse_flow_sequence_entry(parser, event, true) - - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: - return yaml_parser_parse_flow_sequence_entry(parser, event, false) - - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: - return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event) - - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: - return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event) - - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: - return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event) - - case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: - return yaml_parser_parse_flow_mapping_key(parser, event, true) - - case yaml_PARSE_FLOW_MAPPING_KEY_STATE: - return yaml_parser_parse_flow_mapping_key(parser, event, false) - - case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: - return yaml_parser_parse_flow_mapping_value(parser, event, false) - - case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: - return yaml_parser_parse_flow_mapping_value(parser, event, true) - - default: - panic("invalid parser state") - } -} - -// Parse the production: -// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END -// ************ -func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_STREAM_START_TOKEN { - return yaml_parser_set_parser_error(parser, "did not find expected ", token.start_mark) - } - parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE - *event = yaml_event_t{ - typ: yaml_STREAM_START_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - encoding: token.encoding, - } - skip_token(parser) - return true -} - -// Parse the productions: -// implicit_document ::= block_node DOCUMENT-END* -// * -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// ************************* -func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool { - - token := peek_token(parser) - if token == nil { - return false - } - - // Parse extra document end indicators. - if !implicit { - for token.typ == yaml_DOCUMENT_END_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } - } - - if implicit && token.typ != yaml_VERSION_DIRECTIVE_TOKEN && - token.typ != yaml_TAG_DIRECTIVE_TOKEN && - token.typ != yaml_DOCUMENT_START_TOKEN && - token.typ != yaml_STREAM_END_TOKEN { - // Parse an implicit document. - if !yaml_parser_process_directives(parser, nil, nil) { - return false - } - parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE) - parser.state = yaml_PARSE_BLOCK_NODE_STATE - - *event = yaml_event_t{ - typ: yaml_DOCUMENT_START_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - - } else if token.typ != yaml_STREAM_END_TOKEN { - // Parse an explicit document. - var version_directive *yaml_version_directive_t - var tag_directives []yaml_tag_directive_t - start_mark := token.start_mark - if !yaml_parser_process_directives(parser, &version_directive, &tag_directives) { - return false - } - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_DOCUMENT_START_TOKEN { - yaml_parser_set_parser_error(parser, - "did not find expected ", token.start_mark) - return false - } - parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE) - parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE - end_mark := token.end_mark - - *event = yaml_event_t{ - typ: yaml_DOCUMENT_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - version_directive: version_directive, - tag_directives: tag_directives, - implicit: false, - } - skip_token(parser) - - } else { - // Parse the stream end. - parser.state = yaml_PARSE_END_STATE - *event = yaml_event_t{ - typ: yaml_STREAM_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - skip_token(parser) - } - - return true -} - -// Parse the productions: -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// *********** -// -func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_VERSION_DIRECTIVE_TOKEN || - token.typ == yaml_TAG_DIRECTIVE_TOKEN || - token.typ == yaml_DOCUMENT_START_TOKEN || - token.typ == yaml_DOCUMENT_END_TOKEN || - token.typ == yaml_STREAM_END_TOKEN { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - return yaml_parser_process_empty_scalar(parser, event, - token.start_mark) - } - return yaml_parser_parse_node(parser, event, true, false) -} - -// Parse the productions: -// implicit_document ::= block_node DOCUMENT-END* -// ************* -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// -func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - - start_mark := token.start_mark - end_mark := token.start_mark - - implicit := true - if token.typ == yaml_DOCUMENT_END_TOKEN { - end_mark = token.end_mark - skip_token(parser) - implicit = false - } - - parser.tag_directives = parser.tag_directives[:0] - - parser.state = yaml_PARSE_DOCUMENT_START_STATE - *event = yaml_event_t{ - typ: yaml_DOCUMENT_END_EVENT, - start_mark: start_mark, - end_mark: end_mark, - implicit: implicit, - } - return true -} - -// Parse the productions: -// block_node_or_indentless_sequence ::= -// ALIAS -// ***** -// | properties (block_content | indentless_block_sequence)? -// ********** * -// | block_content | indentless_block_sequence -// * -// block_node ::= ALIAS -// ***** -// | properties block_content? -// ********** * -// | block_content -// * -// flow_node ::= ALIAS -// ***** -// | properties flow_content? -// ********** * -// | flow_content -// * -// properties ::= TAG ANCHOR? | ANCHOR TAG? -// ************************* -// block_content ::= block_collection | flow_collection | SCALAR -// ****** -// flow_content ::= flow_collection | SCALAR -// ****** -func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool { - //defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)() - - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ == yaml_ALIAS_TOKEN { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - *event = yaml_event_t{ - typ: yaml_ALIAS_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - anchor: token.value, - } - skip_token(parser) - return true - } - - start_mark := token.start_mark - end_mark := token.start_mark - - var tag_token bool - var tag_handle, tag_suffix, anchor []byte - var tag_mark yaml_mark_t - if token.typ == yaml_ANCHOR_TOKEN { - anchor = token.value - start_mark = token.start_mark - end_mark = token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_TAG_TOKEN { - tag_token = true - tag_handle = token.value - tag_suffix = token.suffix - tag_mark = token.start_mark - end_mark = token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } - } else if token.typ == yaml_TAG_TOKEN { - tag_token = true - tag_handle = token.value - tag_suffix = token.suffix - start_mark = token.start_mark - tag_mark = token.start_mark - end_mark = token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_ANCHOR_TOKEN { - anchor = token.value - end_mark = token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } - } - - var tag []byte - if tag_token { - if len(tag_handle) == 0 { - tag = tag_suffix - tag_suffix = nil - } else { - for i := range parser.tag_directives { - if bytes.Equal(parser.tag_directives[i].handle, tag_handle) { - tag = append([]byte(nil), parser.tag_directives[i].prefix...) - tag = append(tag, tag_suffix...) - break - } - } - if len(tag) == 0 { - yaml_parser_set_parser_error_context(parser, - "while parsing a node", start_mark, - "found undefined tag handle", tag_mark) - return false - } - } - } - - implicit := len(tag) == 0 - if indentless_sequence && token.typ == yaml_BLOCK_ENTRY_TOKEN { - end_mark = token.end_mark - parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE - *event = yaml_event_t{ - typ: yaml_SEQUENCE_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE), - } - return true - } - if token.typ == yaml_SCALAR_TOKEN { - var plain_implicit, quoted_implicit bool - end_mark = token.end_mark - if (len(tag) == 0 && token.style == yaml_PLAIN_SCALAR_STYLE) || (len(tag) == 1 && tag[0] == '!') { - plain_implicit = true - } else if len(tag) == 0 { - quoted_implicit = true - } - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - - *event = yaml_event_t{ - typ: yaml_SCALAR_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - value: token.value, - implicit: plain_implicit, - quoted_implicit: quoted_implicit, - style: yaml_style_t(token.style), - } - skip_token(parser) - return true - } - if token.typ == yaml_FLOW_SEQUENCE_START_TOKEN { - // [Go] Some of the events below can be merged as they differ only on style. - end_mark = token.end_mark - parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE - *event = yaml_event_t{ - typ: yaml_SEQUENCE_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_FLOW_SEQUENCE_STYLE), - } - return true - } - if token.typ == yaml_FLOW_MAPPING_START_TOKEN { - end_mark = token.end_mark - parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE - *event = yaml_event_t{ - typ: yaml_MAPPING_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_FLOW_MAPPING_STYLE), - } - return true - } - if block && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN { - end_mark = token.end_mark - parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE - *event = yaml_event_t{ - typ: yaml_SEQUENCE_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE), - } - return true - } - if block && token.typ == yaml_BLOCK_MAPPING_START_TOKEN { - end_mark = token.end_mark - parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE - *event = yaml_event_t{ - typ: yaml_MAPPING_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_BLOCK_MAPPING_STYLE), - } - return true - } - if len(anchor) > 0 || len(tag) > 0 { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - - *event = yaml_event_t{ - typ: yaml_SCALAR_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - quoted_implicit: false, - style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE), - } - return true - } - - context := "while parsing a flow node" - if block { - context = "while parsing a block node" - } - yaml_parser_set_parser_error_context(parser, context, start_mark, - "did not find expected node content", token.start_mark) - return false -} - -// Parse the productions: -// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END -// ******************** *********** * ********* -// -func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { - if first { - token := peek_token(parser) - parser.marks = append(parser.marks, token.start_mark) - skip_token(parser) - } - - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ == yaml_BLOCK_ENTRY_TOKEN { - mark := token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE) - return yaml_parser_parse_node(parser, event, true, false) - } else { - parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) - } - } - if token.typ == yaml_BLOCK_END_TOKEN { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - - *event = yaml_event_t{ - typ: yaml_SEQUENCE_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - - skip_token(parser) - return true - } - - context_mark := parser.marks[len(parser.marks)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - return yaml_parser_set_parser_error_context(parser, - "while parsing a block collection", context_mark, - "did not find expected '-' indicator", token.start_mark) -} - -// Parse the productions: -// indentless_sequence ::= (BLOCK-ENTRY block_node?)+ -// *********** * -func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ == yaml_BLOCK_ENTRY_TOKEN { - mark := token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_BLOCK_ENTRY_TOKEN && - token.typ != yaml_KEY_TOKEN && - token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_BLOCK_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE) - return yaml_parser_parse_node(parser, event, true, false) - } - parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) - } - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - - *event = yaml_event_t{ - typ: yaml_SEQUENCE_END_EVENT, - start_mark: token.start_mark, - end_mark: token.start_mark, // [Go] Shouldn't this be token.end_mark? - } - return true -} - -// Parse the productions: -// block_mapping ::= BLOCK-MAPPING_START -// ******************* -// ((KEY block_node_or_indentless_sequence?)? -// *** * -// (VALUE block_node_or_indentless_sequence?)?)* -// -// BLOCK-END -// ********* -// -func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { - if first { - token := peek_token(parser) - parser.marks = append(parser.marks, token.start_mark) - skip_token(parser) - } - - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ == yaml_KEY_TOKEN { - mark := token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_KEY_TOKEN && - token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_BLOCK_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE) - return yaml_parser_parse_node(parser, event, true, true) - } else { - parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) - } - } else if token.typ == yaml_BLOCK_END_TOKEN { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - *event = yaml_event_t{ - typ: yaml_MAPPING_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - skip_token(parser) - return true - } - - context_mark := parser.marks[len(parser.marks)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - return yaml_parser_set_parser_error_context(parser, - "while parsing a block mapping", context_mark, - "did not find expected key", token.start_mark) -} - -// Parse the productions: -// block_mapping ::= BLOCK-MAPPING_START -// -// ((KEY block_node_or_indentless_sequence?)? -// -// (VALUE block_node_or_indentless_sequence?)?)* -// ***** * -// BLOCK-END -// -// -func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_VALUE_TOKEN { - mark := token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_KEY_TOKEN && - token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_BLOCK_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE) - return yaml_parser_parse_node(parser, event, true, true) - } - parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) - } - parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) -} - -// Parse the productions: -// flow_sequence ::= FLOW-SEQUENCE-START -// ******************* -// (flow_sequence_entry FLOW-ENTRY)* -// * ********** -// flow_sequence_entry? -// * -// FLOW-SEQUENCE-END -// ***************** -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * -// -func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { - if first { - token := peek_token(parser) - parser.marks = append(parser.marks, token.start_mark) - skip_token(parser) - } - token := peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { - if !first { - if token.typ == yaml_FLOW_ENTRY_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } else { - context_mark := parser.marks[len(parser.marks)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - return yaml_parser_set_parser_error_context(parser, - "while parsing a flow sequence", context_mark, - "did not find expected ',' or ']'", token.start_mark) - } - } - - if token.typ == yaml_KEY_TOKEN { - parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE - *event = yaml_event_t{ - typ: yaml_MAPPING_START_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - implicit: true, - style: yaml_style_t(yaml_FLOW_MAPPING_STYLE), - } - skip_token(parser) - return true - } else if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - } - - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - - *event = yaml_event_t{ - typ: yaml_SEQUENCE_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - - skip_token(parser) - return true -} - -// -// Parse the productions: -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// *** * -// -func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_FLOW_ENTRY_TOKEN && - token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - mark := token.end_mark - skip_token(parser) - parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) -} - -// Parse the productions: -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// ***** * -// -func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_VALUE_TOKEN { - skip_token(parser) - token := peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - } - parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) -} - -// Parse the productions: -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * -// -func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE - *event = yaml_event_t{ - typ: yaml_MAPPING_END_EVENT, - start_mark: token.start_mark, - end_mark: token.start_mark, // [Go] Shouldn't this be end_mark? - } - return true -} - -// Parse the productions: -// flow_mapping ::= FLOW-MAPPING-START -// ****************** -// (flow_mapping_entry FLOW-ENTRY)* -// * ********** -// flow_mapping_entry? -// ****************** -// FLOW-MAPPING-END -// **************** -// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * *** * -// -func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { - if first { - token := peek_token(parser) - parser.marks = append(parser.marks, token.start_mark) - skip_token(parser) - } - - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ != yaml_FLOW_MAPPING_END_TOKEN { - if !first { - if token.typ == yaml_FLOW_ENTRY_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } else { - context_mark := parser.marks[len(parser.marks)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - return yaml_parser_set_parser_error_context(parser, - "while parsing a flow mapping", context_mark, - "did not find expected ',' or '}'", token.start_mark) - } - } - - if token.typ == yaml_KEY_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_FLOW_ENTRY_TOKEN && - token.typ != yaml_FLOW_MAPPING_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } else { - parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) - } - } else if token.typ != yaml_FLOW_MAPPING_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - } - - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - *event = yaml_event_t{ - typ: yaml_MAPPING_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - skip_token(parser) - return true -} - -// Parse the productions: -// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * ***** * -// -func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool { - token := peek_token(parser) - if token == nil { - return false - } - if empty { - parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) - } - if token.typ == yaml_VALUE_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - } - parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) -} - -// Generate an empty scalar event. -func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t, mark yaml_mark_t) bool { - *event = yaml_event_t{ - typ: yaml_SCALAR_EVENT, - start_mark: mark, - end_mark: mark, - value: nil, // Empty - implicit: true, - style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE), - } - return true -} - -var default_tag_directives = []yaml_tag_directive_t{ - {[]byte("!"), []byte("!")}, - {[]byte("!!"), []byte("tag:yaml.org,2002:")}, -} - -// Parse directives. -func yaml_parser_process_directives(parser *yaml_parser_t, - version_directive_ref **yaml_version_directive_t, - tag_directives_ref *[]yaml_tag_directive_t) bool { - - var version_directive *yaml_version_directive_t - var tag_directives []yaml_tag_directive_t - - token := peek_token(parser) - if token == nil { - return false - } - - for token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN { - if token.typ == yaml_VERSION_DIRECTIVE_TOKEN { - if version_directive != nil { - yaml_parser_set_parser_error(parser, - "found duplicate %YAML directive", token.start_mark) - return false - } - if token.major != 1 || token.minor != 1 { - yaml_parser_set_parser_error(parser, - "found incompatible YAML document", token.start_mark) - return false - } - version_directive = &yaml_version_directive_t{ - major: token.major, - minor: token.minor, - } - } else if token.typ == yaml_TAG_DIRECTIVE_TOKEN { - value := yaml_tag_directive_t{ - handle: token.value, - prefix: token.prefix, - } - if !yaml_parser_append_tag_directive(parser, value, false, token.start_mark) { - return false - } - tag_directives = append(tag_directives, value) - } - - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } - - for i := range default_tag_directives { - if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) { - return false - } - } - - if version_directive_ref != nil { - *version_directive_ref = version_directive - } - if tag_directives_ref != nil { - *tag_directives_ref = tag_directives - } - return true -} - -// Append a tag directive to the directives stack. -func yaml_parser_append_tag_directive(parser *yaml_parser_t, value yaml_tag_directive_t, allow_duplicates bool, mark yaml_mark_t) bool { - for i := range parser.tag_directives { - if bytes.Equal(value.handle, parser.tag_directives[i].handle) { - if allow_duplicates { - return true - } - return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark) - } - } - - // [Go] I suspect the copy is unnecessary. This was likely done - // because there was no way to track ownership of the data. - value_copy := yaml_tag_directive_t{ - handle: make([]byte, len(value.handle)), - prefix: make([]byte, len(value.prefix)), - } - copy(value_copy.handle, value.handle) - copy(value_copy.prefix, value.prefix) - parser.tag_directives = append(parser.tag_directives, value_copy) - return true -} diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/readerc.go b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/readerc.go deleted file mode 100755 index 7c1f5fa..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/readerc.go +++ /dev/null @@ -1,412 +0,0 @@ -package yaml - -import ( - "io" -) - -// Set the reader error and return 0. -func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool { - parser.error = yaml_READER_ERROR - parser.problem = problem - parser.problem_offset = offset - parser.problem_value = value - return false -} - -// Byte order marks. -const ( - bom_UTF8 = "\xef\xbb\xbf" - bom_UTF16LE = "\xff\xfe" - bom_UTF16BE = "\xfe\xff" -) - -// Determine the input stream encoding by checking the BOM symbol. If no BOM is -// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure. -func yaml_parser_determine_encoding(parser *yaml_parser_t) bool { - // Ensure that we had enough bytes in the raw buffer. - for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 { - if !yaml_parser_update_raw_buffer(parser) { - return false - } - } - - // Determine the encoding. - buf := parser.raw_buffer - pos := parser.raw_buffer_pos - avail := len(buf) - pos - if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] { - parser.encoding = yaml_UTF16LE_ENCODING - parser.raw_buffer_pos += 2 - parser.offset += 2 - } else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] { - parser.encoding = yaml_UTF16BE_ENCODING - parser.raw_buffer_pos += 2 - parser.offset += 2 - } else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] { - parser.encoding = yaml_UTF8_ENCODING - parser.raw_buffer_pos += 3 - parser.offset += 3 - } else { - parser.encoding = yaml_UTF8_ENCODING - } - return true -} - -// Update the raw buffer. -func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool { - size_read := 0 - - // Return if the raw buffer is full. - if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) { - return true - } - - // Return on EOF. - if parser.eof { - return true - } - - // Move the remaining bytes in the raw buffer to the beginning. - if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) { - copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:]) - } - parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos] - parser.raw_buffer_pos = 0 - - // Call the read handler to fill the buffer. - size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)]) - parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read] - if err == io.EOF { - parser.eof = true - } else if err != nil { - return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1) - } - return true -} - -// Ensure that the buffer contains at least `length` characters. -// Return true on success, false on failure. -// -// The length is supposed to be significantly less that the buffer size. -func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool { - if parser.read_handler == nil { - panic("read handler must be set") - } - - // [Go] This function was changed to guarantee the requested length size at EOF. - // The fact we need to do this is pretty awful, but the description above implies - // for that to be the case, and there are tests - - // If the EOF flag is set and the raw buffer is empty, do nothing. - if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) { - // [Go] ACTUALLY! Read the documentation of this function above. - // This is just broken. To return true, we need to have the - // given length in the buffer. Not doing that means every single - // check that calls this function to make sure the buffer has a - // given length is Go) panicking; or C) accessing invalid memory. - //return true - } - - // Return if the buffer contains enough characters. - if parser.unread >= length { - return true - } - - // Determine the input encoding if it is not known yet. - if parser.encoding == yaml_ANY_ENCODING { - if !yaml_parser_determine_encoding(parser) { - return false - } - } - - // Move the unread characters to the beginning of the buffer. - buffer_len := len(parser.buffer) - if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len { - copy(parser.buffer, parser.buffer[parser.buffer_pos:]) - buffer_len -= parser.buffer_pos - parser.buffer_pos = 0 - } else if parser.buffer_pos == buffer_len { - buffer_len = 0 - parser.buffer_pos = 0 - } - - // Open the whole buffer for writing, and cut it before returning. - parser.buffer = parser.buffer[:cap(parser.buffer)] - - // Fill the buffer until it has enough characters. - first := true - for parser.unread < length { - - // Fill the raw buffer if necessary. - if !first || parser.raw_buffer_pos == len(parser.raw_buffer) { - if !yaml_parser_update_raw_buffer(parser) { - parser.buffer = parser.buffer[:buffer_len] - return false - } - } - first = false - - // Decode the raw buffer. - inner: - for parser.raw_buffer_pos != len(parser.raw_buffer) { - var value rune - var width int - - raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos - - // Decode the next character. - switch parser.encoding { - case yaml_UTF8_ENCODING: - // Decode a UTF-8 character. Check RFC 3629 - // (http://www.ietf.org/rfc/rfc3629.txt) for more details. - // - // The following table (taken from the RFC) is used for - // decoding. - // - // Char. number range | UTF-8 octet sequence - // (hexadecimal) | (binary) - // --------------------+------------------------------------ - // 0000 0000-0000 007F | 0xxxxxxx - // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx - // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx - // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - // - // Additionally, the characters in the range 0xD800-0xDFFF - // are prohibited as they are reserved for use with UTF-16 - // surrogate pairs. - - // Determine the length of the UTF-8 sequence. - octet := parser.raw_buffer[parser.raw_buffer_pos] - switch { - case octet&0x80 == 0x00: - width = 1 - case octet&0xE0 == 0xC0: - width = 2 - case octet&0xF0 == 0xE0: - width = 3 - case octet&0xF8 == 0xF0: - width = 4 - default: - // The leading octet is invalid. - return yaml_parser_set_reader_error(parser, - "invalid leading UTF-8 octet", - parser.offset, int(octet)) - } - - // Check if the raw buffer contains an incomplete character. - if width > raw_unread { - if parser.eof { - return yaml_parser_set_reader_error(parser, - "incomplete UTF-8 octet sequence", - parser.offset, -1) - } - break inner - } - - // Decode the leading octet. - switch { - case octet&0x80 == 0x00: - value = rune(octet & 0x7F) - case octet&0xE0 == 0xC0: - value = rune(octet & 0x1F) - case octet&0xF0 == 0xE0: - value = rune(octet & 0x0F) - case octet&0xF8 == 0xF0: - value = rune(octet & 0x07) - default: - value = 0 - } - - // Check and decode the trailing octets. - for k := 1; k < width; k++ { - octet = parser.raw_buffer[parser.raw_buffer_pos+k] - - // Check if the octet is valid. - if (octet & 0xC0) != 0x80 { - return yaml_parser_set_reader_error(parser, - "invalid trailing UTF-8 octet", - parser.offset+k, int(octet)) - } - - // Decode the octet. - value = (value << 6) + rune(octet&0x3F) - } - - // Check the length of the sequence against the value. - switch { - case width == 1: - case width == 2 && value >= 0x80: - case width == 3 && value >= 0x800: - case width == 4 && value >= 0x10000: - default: - return yaml_parser_set_reader_error(parser, - "invalid length of a UTF-8 sequence", - parser.offset, -1) - } - - // Check the range of the value. - if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF { - return yaml_parser_set_reader_error(parser, - "invalid Unicode character", - parser.offset, int(value)) - } - - case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING: - var low, high int - if parser.encoding == yaml_UTF16LE_ENCODING { - low, high = 0, 1 - } else { - low, high = 1, 0 - } - - // The UTF-16 encoding is not as simple as one might - // naively think. Check RFC 2781 - // (http://www.ietf.org/rfc/rfc2781.txt). - // - // Normally, two subsequent bytes describe a Unicode - // character. However a special technique (called a - // surrogate pair) is used for specifying character - // values larger than 0xFFFF. - // - // A surrogate pair consists of two pseudo-characters: - // high surrogate area (0xD800-0xDBFF) - // low surrogate area (0xDC00-0xDFFF) - // - // The following formulas are used for decoding - // and encoding characters using surrogate pairs: - // - // U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF) - // U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF) - // W1 = 110110yyyyyyyyyy - // W2 = 110111xxxxxxxxxx - // - // where U is the character value, W1 is the high surrogate - // area, W2 is the low surrogate area. - - // Check for incomplete UTF-16 character. - if raw_unread < 2 { - if parser.eof { - return yaml_parser_set_reader_error(parser, - "incomplete UTF-16 character", - parser.offset, -1) - } - break inner - } - - // Get the character. - value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) + - (rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8) - - // Check for unexpected low surrogate area. - if value&0xFC00 == 0xDC00 { - return yaml_parser_set_reader_error(parser, - "unexpected low surrogate area", - parser.offset, int(value)) - } - - // Check for a high surrogate area. - if value&0xFC00 == 0xD800 { - width = 4 - - // Check for incomplete surrogate pair. - if raw_unread < 4 { - if parser.eof { - return yaml_parser_set_reader_error(parser, - "incomplete UTF-16 surrogate pair", - parser.offset, -1) - } - break inner - } - - // Get the next character. - value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) + - (rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8) - - // Check for a low surrogate area. - if value2&0xFC00 != 0xDC00 { - return yaml_parser_set_reader_error(parser, - "expected low surrogate area", - parser.offset+2, int(value2)) - } - - // Generate the value of the surrogate pair. - value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF) - } else { - width = 2 - } - - default: - panic("impossible") - } - - // Check if the character is in the allowed range: - // #x9 | #xA | #xD | [#x20-#x7E] (8 bit) - // | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit) - // | [#x10000-#x10FFFF] (32 bit) - switch { - case value == 0x09: - case value == 0x0A: - case value == 0x0D: - case value >= 0x20 && value <= 0x7E: - case value == 0x85: - case value >= 0xA0 && value <= 0xD7FF: - case value >= 0xE000 && value <= 0xFFFD: - case value >= 0x10000 && value <= 0x10FFFF: - default: - return yaml_parser_set_reader_error(parser, - "control characters are not allowed", - parser.offset, int(value)) - } - - // Move the raw pointers. - parser.raw_buffer_pos += width - parser.offset += width - - // Finally put the character into the buffer. - if value <= 0x7F { - // 0000 0000-0000 007F . 0xxxxxxx - parser.buffer[buffer_len+0] = byte(value) - buffer_len += 1 - } else if value <= 0x7FF { - // 0000 0080-0000 07FF . 110xxxxx 10xxxxxx - parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6)) - parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F)) - buffer_len += 2 - } else if value <= 0xFFFF { - // 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx - parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12)) - parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F)) - parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F)) - buffer_len += 3 - } else { - // 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18)) - parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F)) - parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F)) - parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F)) - buffer_len += 4 - } - - parser.unread++ - } - - // On EOF, put NUL into the buffer and return. - if parser.eof { - parser.buffer[buffer_len] = 0 - buffer_len++ - parser.unread++ - break - } - } - // [Go] Read the documentation of this function above. To return true, - // we need to have the given length in the buffer. Not doing that means - // every single check that calls this function to make sure the buffer - // has a given length is Go) panicking; or C) accessing invalid memory. - // This happens here due to the EOF above breaking early. - for buffer_len < length { - parser.buffer[buffer_len] = 0 - buffer_len++ - } - parser.buffer = parser.buffer[:buffer_len] - return true -} diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/resolve.go b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/resolve.go deleted file mode 100755 index 6c151db..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/resolve.go +++ /dev/null @@ -1,258 +0,0 @@ -package yaml - -import ( - "encoding/base64" - "math" - "regexp" - "strconv" - "strings" - "time" -) - -type resolveMapItem struct { - value interface{} - tag string -} - -var resolveTable = make([]byte, 256) -var resolveMap = make(map[string]resolveMapItem) - -func init() { - t := resolveTable - t[int('+')] = 'S' // Sign - t[int('-')] = 'S' - for _, c := range "0123456789" { - t[int(c)] = 'D' // Digit - } - for _, c := range "yYnNtTfFoO~" { - t[int(c)] = 'M' // In map - } - t[int('.')] = '.' // Float (potentially in map) - - var resolveMapList = []struct { - v interface{} - tag string - l []string - }{ - {true, yaml_BOOL_TAG, []string{"y", "Y", "yes", "Yes", "YES"}}, - {true, yaml_BOOL_TAG, []string{"true", "True", "TRUE"}}, - {true, yaml_BOOL_TAG, []string{"on", "On", "ON"}}, - {false, yaml_BOOL_TAG, []string{"n", "N", "no", "No", "NO"}}, - {false, yaml_BOOL_TAG, []string{"false", "False", "FALSE"}}, - {false, yaml_BOOL_TAG, []string{"off", "Off", "OFF"}}, - {nil, yaml_NULL_TAG, []string{"", "~", "null", "Null", "NULL"}}, - {math.NaN(), yaml_FLOAT_TAG, []string{".nan", ".NaN", ".NAN"}}, - {math.Inf(+1), yaml_FLOAT_TAG, []string{".inf", ".Inf", ".INF"}}, - {math.Inf(+1), yaml_FLOAT_TAG, []string{"+.inf", "+.Inf", "+.INF"}}, - {math.Inf(-1), yaml_FLOAT_TAG, []string{"-.inf", "-.Inf", "-.INF"}}, - {"<<", yaml_MERGE_TAG, []string{"<<"}}, - } - - m := resolveMap - for _, item := range resolveMapList { - for _, s := range item.l { - m[s] = resolveMapItem{item.v, item.tag} - } - } -} - -const longTagPrefix = "tag:yaml.org,2002:" - -func shortTag(tag string) string { - // TODO This can easily be made faster and produce less garbage. - if strings.HasPrefix(tag, longTagPrefix) { - return "!!" + tag[len(longTagPrefix):] - } - return tag -} - -func longTag(tag string) string { - if strings.HasPrefix(tag, "!!") { - return longTagPrefix + tag[2:] - } - return tag -} - -func resolvableTag(tag string) bool { - switch tag { - case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG, yaml_TIMESTAMP_TAG: - return true - } - return false -} - -var yamlStyleFloat = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+([eE][-+][0-9]+)?$`) - -func resolve(tag string, in string) (rtag string, out interface{}) { - if !resolvableTag(tag) { - return tag, in - } - - defer func() { - switch tag { - case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG: - return - case yaml_FLOAT_TAG: - if rtag == yaml_INT_TAG { - switch v := out.(type) { - case int64: - rtag = yaml_FLOAT_TAG - out = float64(v) - return - case int: - rtag = yaml_FLOAT_TAG - out = float64(v) - return - } - } - } - failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag)) - }() - - // Any data is accepted as a !!str or !!binary. - // Otherwise, the prefix is enough of a hint about what it might be. - hint := byte('N') - if in != "" { - hint = resolveTable[in[0]] - } - if hint != 0 && tag != yaml_STR_TAG && tag != yaml_BINARY_TAG { - // Handle things we can lookup in a map. - if item, ok := resolveMap[in]; ok { - return item.tag, item.value - } - - // Base 60 floats are a bad idea, were dropped in YAML 1.2, and - // are purposefully unsupported here. They're still quoted on - // the way out for compatibility with other parser, though. - - switch hint { - case 'M': - // We've already checked the map above. - - case '.': - // Not in the map, so maybe a normal float. - floatv, err := strconv.ParseFloat(in, 64) - if err == nil { - return yaml_FLOAT_TAG, floatv - } - - case 'D', 'S': - // Int, float, or timestamp. - // Only try values as a timestamp if the value is unquoted or there's an explicit - // !!timestamp tag. - if tag == "" || tag == yaml_TIMESTAMP_TAG { - t, ok := parseTimestamp(in) - if ok { - return yaml_TIMESTAMP_TAG, t - } - } - - plain := strings.Replace(in, "_", "", -1) - intv, err := strconv.ParseInt(plain, 0, 64) - if err == nil { - if intv == int64(int(intv)) { - return yaml_INT_TAG, int(intv) - } else { - return yaml_INT_TAG, intv - } - } - uintv, err := strconv.ParseUint(plain, 0, 64) - if err == nil { - return yaml_INT_TAG, uintv - } - if yamlStyleFloat.MatchString(plain) { - floatv, err := strconv.ParseFloat(plain, 64) - if err == nil { - return yaml_FLOAT_TAG, floatv - } - } - if strings.HasPrefix(plain, "0b") { - intv, err := strconv.ParseInt(plain[2:], 2, 64) - if err == nil { - if intv == int64(int(intv)) { - return yaml_INT_TAG, int(intv) - } else { - return yaml_INT_TAG, intv - } - } - uintv, err := strconv.ParseUint(plain[2:], 2, 64) - if err == nil { - return yaml_INT_TAG, uintv - } - } else if strings.HasPrefix(plain, "-0b") { - intv, err := strconv.ParseInt("-" + plain[3:], 2, 64) - if err == nil { - if true || intv == int64(int(intv)) { - return yaml_INT_TAG, int(intv) - } else { - return yaml_INT_TAG, intv - } - } - } - default: - panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")") - } - } - return yaml_STR_TAG, in -} - -// encodeBase64 encodes s as base64 that is broken up into multiple lines -// as appropriate for the resulting length. -func encodeBase64(s string) string { - const lineLen = 70 - encLen := base64.StdEncoding.EncodedLen(len(s)) - lines := encLen/lineLen + 1 - buf := make([]byte, encLen*2+lines) - in := buf[0:encLen] - out := buf[encLen:] - base64.StdEncoding.Encode(in, []byte(s)) - k := 0 - for i := 0; i < len(in); i += lineLen { - j := i + lineLen - if j > len(in) { - j = len(in) - } - k += copy(out[k:], in[i:j]) - if lines > 1 { - out[k] = '\n' - k++ - } - } - return string(out[:k]) -} - -// This is a subset of the formats allowed by the regular expression -// defined at http://yaml.org/type/timestamp.html. -var allowedTimestampFormats = []string{ - "2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields. - "2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t". - "2006-1-2 15:4:5.999999999", // space separated with no time zone - "2006-1-2", // date only - // Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5" - // from the set of examples. -} - -// parseTimestamp parses s as a timestamp string and -// returns the timestamp and reports whether it succeeded. -// Timestamp formats are defined at http://yaml.org/type/timestamp.html -func parseTimestamp(s string) (time.Time, bool) { - // TODO write code to check all the formats supported by - // http://yaml.org/type/timestamp.html instead of using time.Parse. - - // Quick check: all date formats start with YYYY-. - i := 0 - for ; i < len(s); i++ { - if c := s[i]; c < '0' || c > '9' { - break - } - } - if i != 4 || i == len(s) || s[i] != '-' { - return time.Time{}, false - } - for _, format := range allowedTimestampFormats { - if t, err := time.Parse(format, s); err == nil { - return t, true - } - } - return time.Time{}, false -} diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/scannerc.go b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/scannerc.go deleted file mode 100755 index 077fd1d..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/scannerc.go +++ /dev/null @@ -1,2696 +0,0 @@ -package yaml - -import ( - "bytes" - "fmt" -) - -// Introduction -// ************ -// -// The following notes assume that you are familiar with the YAML specification -// (http://yaml.org/spec/1.2/spec.html). We mostly follow it, although in -// some cases we are less restrictive that it requires. -// -// The process of transforming a YAML stream into a sequence of events is -// divided on two steps: Scanning and Parsing. -// -// The Scanner transforms the input stream into a sequence of tokens, while the -// parser transform the sequence of tokens produced by the Scanner into a -// sequence of parsing events. -// -// The Scanner is rather clever and complicated. The Parser, on the contrary, -// is a straightforward implementation of a recursive-descendant parser (or, -// LL(1) parser, as it is usually called). -// -// Actually there are two issues of Scanning that might be called "clever", the -// rest is quite straightforward. The issues are "block collection start" and -// "simple keys". Both issues are explained below in details. -// -// Here the Scanning step is explained and implemented. We start with the list -// of all the tokens produced by the Scanner together with short descriptions. -// -// Now, tokens: -// -// STREAM-START(encoding) # The stream start. -// STREAM-END # The stream end. -// VERSION-DIRECTIVE(major,minor) # The '%YAML' directive. -// TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive. -// DOCUMENT-START # '---' -// DOCUMENT-END # '...' -// BLOCK-SEQUENCE-START # Indentation increase denoting a block -// BLOCK-MAPPING-START # sequence or a block mapping. -// BLOCK-END # Indentation decrease. -// FLOW-SEQUENCE-START # '[' -// FLOW-SEQUENCE-END # ']' -// BLOCK-SEQUENCE-START # '{' -// BLOCK-SEQUENCE-END # '}' -// BLOCK-ENTRY # '-' -// FLOW-ENTRY # ',' -// KEY # '?' or nothing (simple keys). -// VALUE # ':' -// ALIAS(anchor) # '*anchor' -// ANCHOR(anchor) # '&anchor' -// TAG(handle,suffix) # '!handle!suffix' -// SCALAR(value,style) # A scalar. -// -// The following two tokens are "virtual" tokens denoting the beginning and the -// end of the stream: -// -// STREAM-START(encoding) -// STREAM-END -// -// We pass the information about the input stream encoding with the -// STREAM-START token. -// -// The next two tokens are responsible for tags: -// -// VERSION-DIRECTIVE(major,minor) -// TAG-DIRECTIVE(handle,prefix) -// -// Example: -// -// %YAML 1.1 -// %TAG ! !foo -// %TAG !yaml! tag:yaml.org,2002: -// --- -// -// The correspoding sequence of tokens: -// -// STREAM-START(utf-8) -// VERSION-DIRECTIVE(1,1) -// TAG-DIRECTIVE("!","!foo") -// TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:") -// DOCUMENT-START -// STREAM-END -// -// Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole -// line. -// -// The document start and end indicators are represented by: -// -// DOCUMENT-START -// DOCUMENT-END -// -// Note that if a YAML stream contains an implicit document (without '---' -// and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be -// produced. -// -// In the following examples, we present whole documents together with the -// produced tokens. -// -// 1. An implicit document: -// -// 'a scalar' -// -// Tokens: -// -// STREAM-START(utf-8) -// SCALAR("a scalar",single-quoted) -// STREAM-END -// -// 2. An explicit document: -// -// --- -// 'a scalar' -// ... -// -// Tokens: -// -// STREAM-START(utf-8) -// DOCUMENT-START -// SCALAR("a scalar",single-quoted) -// DOCUMENT-END -// STREAM-END -// -// 3. Several documents in a stream: -// -// 'a scalar' -// --- -// 'another scalar' -// --- -// 'yet another scalar' -// -// Tokens: -// -// STREAM-START(utf-8) -// SCALAR("a scalar",single-quoted) -// DOCUMENT-START -// SCALAR("another scalar",single-quoted) -// DOCUMENT-START -// SCALAR("yet another scalar",single-quoted) -// STREAM-END -// -// We have already introduced the SCALAR token above. The following tokens are -// used to describe aliases, anchors, tag, and scalars: -// -// ALIAS(anchor) -// ANCHOR(anchor) -// TAG(handle,suffix) -// SCALAR(value,style) -// -// The following series of examples illustrate the usage of these tokens: -// -// 1. A recursive sequence: -// -// &A [ *A ] -// -// Tokens: -// -// STREAM-START(utf-8) -// ANCHOR("A") -// FLOW-SEQUENCE-START -// ALIAS("A") -// FLOW-SEQUENCE-END -// STREAM-END -// -// 2. A tagged scalar: -// -// !!float "3.14" # A good approximation. -// -// Tokens: -// -// STREAM-START(utf-8) -// TAG("!!","float") -// SCALAR("3.14",double-quoted) -// STREAM-END -// -// 3. Various scalar styles: -// -// --- # Implicit empty plain scalars do not produce tokens. -// --- a plain scalar -// --- 'a single-quoted scalar' -// --- "a double-quoted scalar" -// --- |- -// a literal scalar -// --- >- -// a folded -// scalar -// -// Tokens: -// -// STREAM-START(utf-8) -// DOCUMENT-START -// DOCUMENT-START -// SCALAR("a plain scalar",plain) -// DOCUMENT-START -// SCALAR("a single-quoted scalar",single-quoted) -// DOCUMENT-START -// SCALAR("a double-quoted scalar",double-quoted) -// DOCUMENT-START -// SCALAR("a literal scalar",literal) -// DOCUMENT-START -// SCALAR("a folded scalar",folded) -// STREAM-END -// -// Now it's time to review collection-related tokens. We will start with -// flow collections: -// -// FLOW-SEQUENCE-START -// FLOW-SEQUENCE-END -// FLOW-MAPPING-START -// FLOW-MAPPING-END -// FLOW-ENTRY -// KEY -// VALUE -// -// The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and -// FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}' -// correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the -// indicators '?' and ':', which are used for denoting mapping keys and values, -// are represented by the KEY and VALUE tokens. -// -// The following examples show flow collections: -// -// 1. A flow sequence: -// -// [item 1, item 2, item 3] -// -// Tokens: -// -// STREAM-START(utf-8) -// FLOW-SEQUENCE-START -// SCALAR("item 1",plain) -// FLOW-ENTRY -// SCALAR("item 2",plain) -// FLOW-ENTRY -// SCALAR("item 3",plain) -// FLOW-SEQUENCE-END -// STREAM-END -// -// 2. A flow mapping: -// -// { -// a simple key: a value, # Note that the KEY token is produced. -// ? a complex key: another value, -// } -// -// Tokens: -// -// STREAM-START(utf-8) -// FLOW-MAPPING-START -// KEY -// SCALAR("a simple key",plain) -// VALUE -// SCALAR("a value",plain) -// FLOW-ENTRY -// KEY -// SCALAR("a complex key",plain) -// VALUE -// SCALAR("another value",plain) -// FLOW-ENTRY -// FLOW-MAPPING-END -// STREAM-END -// -// A simple key is a key which is not denoted by the '?' indicator. Note that -// the Scanner still produce the KEY token whenever it encounters a simple key. -// -// For scanning block collections, the following tokens are used (note that we -// repeat KEY and VALUE here): -// -// BLOCK-SEQUENCE-START -// BLOCK-MAPPING-START -// BLOCK-END -// BLOCK-ENTRY -// KEY -// VALUE -// -// The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation -// increase that precedes a block collection (cf. the INDENT token in Python). -// The token BLOCK-END denote indentation decrease that ends a block collection -// (cf. the DEDENT token in Python). However YAML has some syntax pecularities -// that makes detections of these tokens more complex. -// -// The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators -// '-', '?', and ':' correspondingly. -// -// The following examples show how the tokens BLOCK-SEQUENCE-START, -// BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner: -// -// 1. Block sequences: -// -// - item 1 -// - item 2 -// - -// - item 3.1 -// - item 3.2 -// - -// key 1: value 1 -// key 2: value 2 -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-ENTRY -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 3.1",plain) -// BLOCK-ENTRY -// SCALAR("item 3.2",plain) -// BLOCK-END -// BLOCK-ENTRY -// BLOCK-MAPPING-START -// KEY -// SCALAR("key 1",plain) -// VALUE -// SCALAR("value 1",plain) -// KEY -// SCALAR("key 2",plain) -// VALUE -// SCALAR("value 2",plain) -// BLOCK-END -// BLOCK-END -// STREAM-END -// -// 2. Block mappings: -// -// a simple key: a value # The KEY token is produced here. -// ? a complex key -// : another value -// a mapping: -// key 1: value 1 -// key 2: value 2 -// a sequence: -// - item 1 -// - item 2 -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-MAPPING-START -// KEY -// SCALAR("a simple key",plain) -// VALUE -// SCALAR("a value",plain) -// KEY -// SCALAR("a complex key",plain) -// VALUE -// SCALAR("another value",plain) -// KEY -// SCALAR("a mapping",plain) -// BLOCK-MAPPING-START -// KEY -// SCALAR("key 1",plain) -// VALUE -// SCALAR("value 1",plain) -// KEY -// SCALAR("key 2",plain) -// VALUE -// SCALAR("value 2",plain) -// BLOCK-END -// KEY -// SCALAR("a sequence",plain) -// VALUE -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-END -// BLOCK-END -// STREAM-END -// -// YAML does not always require to start a new block collection from a new -// line. If the current line contains only '-', '?', and ':' indicators, a new -// block collection may start at the current line. The following examples -// illustrate this case: -// -// 1. Collections in a sequence: -// -// - - item 1 -// - item 2 -// - key 1: value 1 -// key 2: value 2 -// - ? complex key -// : complex value -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-END -// BLOCK-ENTRY -// BLOCK-MAPPING-START -// KEY -// SCALAR("key 1",plain) -// VALUE -// SCALAR("value 1",plain) -// KEY -// SCALAR("key 2",plain) -// VALUE -// SCALAR("value 2",plain) -// BLOCK-END -// BLOCK-ENTRY -// BLOCK-MAPPING-START -// KEY -// SCALAR("complex key") -// VALUE -// SCALAR("complex value") -// BLOCK-END -// BLOCK-END -// STREAM-END -// -// 2. Collections in a mapping: -// -// ? a sequence -// : - item 1 -// - item 2 -// ? a mapping -// : key 1: value 1 -// key 2: value 2 -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-MAPPING-START -// KEY -// SCALAR("a sequence",plain) -// VALUE -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-END -// KEY -// SCALAR("a mapping",plain) -// VALUE -// BLOCK-MAPPING-START -// KEY -// SCALAR("key 1",plain) -// VALUE -// SCALAR("value 1",plain) -// KEY -// SCALAR("key 2",plain) -// VALUE -// SCALAR("value 2",plain) -// BLOCK-END -// BLOCK-END -// STREAM-END -// -// YAML also permits non-indented sequences if they are included into a block -// mapping. In this case, the token BLOCK-SEQUENCE-START is not produced: -// -// key: -// - item 1 # BLOCK-SEQUENCE-START is NOT produced here. -// - item 2 -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-MAPPING-START -// KEY -// SCALAR("key",plain) -// VALUE -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-END -// - -// Ensure that the buffer contains the required number of characters. -// Return true on success, false on failure (reader error or memory error). -func cache(parser *yaml_parser_t, length int) bool { - // [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B) - return parser.unread >= length || yaml_parser_update_buffer(parser, length) -} - -// Advance the buffer pointer. -func skip(parser *yaml_parser_t) { - parser.mark.index++ - parser.mark.column++ - parser.unread-- - parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) -} - -func skip_line(parser *yaml_parser_t) { - if is_crlf(parser.buffer, parser.buffer_pos) { - parser.mark.index += 2 - parser.mark.column = 0 - parser.mark.line++ - parser.unread -= 2 - parser.buffer_pos += 2 - } else if is_break(parser.buffer, parser.buffer_pos) { - parser.mark.index++ - parser.mark.column = 0 - parser.mark.line++ - parser.unread-- - parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) - } -} - -// Copy a character to a string buffer and advance pointers. -func read(parser *yaml_parser_t, s []byte) []byte { - w := width(parser.buffer[parser.buffer_pos]) - if w == 0 { - panic("invalid character sequence") - } - if len(s) == 0 { - s = make([]byte, 0, 32) - } - if w == 1 && len(s)+w <= cap(s) { - s = s[:len(s)+1] - s[len(s)-1] = parser.buffer[parser.buffer_pos] - parser.buffer_pos++ - } else { - s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...) - parser.buffer_pos += w - } - parser.mark.index++ - parser.mark.column++ - parser.unread-- - return s -} - -// Copy a line break character to a string buffer and advance pointers. -func read_line(parser *yaml_parser_t, s []byte) []byte { - buf := parser.buffer - pos := parser.buffer_pos - switch { - case buf[pos] == '\r' && buf[pos+1] == '\n': - // CR LF . LF - s = append(s, '\n') - parser.buffer_pos += 2 - parser.mark.index++ - parser.unread-- - case buf[pos] == '\r' || buf[pos] == '\n': - // CR|LF . LF - s = append(s, '\n') - parser.buffer_pos += 1 - case buf[pos] == '\xC2' && buf[pos+1] == '\x85': - // NEL . LF - s = append(s, '\n') - parser.buffer_pos += 2 - case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'): - // LS|PS . LS|PS - s = append(s, buf[parser.buffer_pos:pos+3]...) - parser.buffer_pos += 3 - default: - return s - } - parser.mark.index++ - parser.mark.column = 0 - parser.mark.line++ - parser.unread-- - return s -} - -// Get the next token. -func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool { - // Erase the token object. - *token = yaml_token_t{} // [Go] Is this necessary? - - // No tokens after STREAM-END or error. - if parser.stream_end_produced || parser.error != yaml_NO_ERROR { - return true - } - - // Ensure that the tokens queue contains enough tokens. - if !parser.token_available { - if !yaml_parser_fetch_more_tokens(parser) { - return false - } - } - - // Fetch the next token from the queue. - *token = parser.tokens[parser.tokens_head] - parser.tokens_head++ - parser.tokens_parsed++ - parser.token_available = false - - if token.typ == yaml_STREAM_END_TOKEN { - parser.stream_end_produced = true - } - return true -} - -// Set the scanner error and return false. -func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool { - parser.error = yaml_SCANNER_ERROR - parser.context = context - parser.context_mark = context_mark - parser.problem = problem - parser.problem_mark = parser.mark - return false -} - -func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool { - context := "while parsing a tag" - if directive { - context = "while parsing a %TAG directive" - } - return yaml_parser_set_scanner_error(parser, context, context_mark, problem) -} - -func trace(args ...interface{}) func() { - pargs := append([]interface{}{"+++"}, args...) - fmt.Println(pargs...) - pargs = append([]interface{}{"---"}, args...) - return func() { fmt.Println(pargs...) } -} - -// Ensure that the tokens queue contains at least one token which can be -// returned to the Parser. -func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool { - // While we need more tokens to fetch, do it. - for { - // Check if we really need to fetch more tokens. - need_more_tokens := false - - if parser.tokens_head == len(parser.tokens) { - // Queue is empty. - need_more_tokens = true - } else { - // Check if any potential simple key may occupy the head position. - if !yaml_parser_stale_simple_keys(parser) { - return false - } - - for i := range parser.simple_keys { - simple_key := &parser.simple_keys[i] - if simple_key.possible && simple_key.token_number == parser.tokens_parsed { - need_more_tokens = true - break - } - } - } - - // We are finished. - if !need_more_tokens { - break - } - // Fetch the next token. - if !yaml_parser_fetch_next_token(parser) { - return false - } - } - - parser.token_available = true - return true -} - -// The dispatcher for token fetchers. -func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool { - // Ensure that the buffer is initialized. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - // Check if we just started scanning. Fetch STREAM-START then. - if !parser.stream_start_produced { - return yaml_parser_fetch_stream_start(parser) - } - - // Eat whitespaces and comments until we reach the next token. - if !yaml_parser_scan_to_next_token(parser) { - return false - } - - // Remove obsolete potential simple keys. - if !yaml_parser_stale_simple_keys(parser) { - return false - } - - // Check the indentation level against the current column. - if !yaml_parser_unroll_indent(parser, parser.mark.column) { - return false - } - - // Ensure that the buffer contains at least 4 characters. 4 is the length - // of the longest indicators ('--- ' and '... '). - if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { - return false - } - - // Is it the end of the stream? - if is_z(parser.buffer, parser.buffer_pos) { - return yaml_parser_fetch_stream_end(parser) - } - - // Is it a directive? - if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' { - return yaml_parser_fetch_directive(parser) - } - - buf := parser.buffer - pos := parser.buffer_pos - - // Is it the document start indicator? - if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) { - return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN) - } - - // Is it the document end indicator? - if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) { - return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN) - } - - // Is it the flow sequence start indicator? - if buf[pos] == '[' { - return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN) - } - - // Is it the flow mapping start indicator? - if parser.buffer[parser.buffer_pos] == '{' { - return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN) - } - - // Is it the flow sequence end indicator? - if parser.buffer[parser.buffer_pos] == ']' { - return yaml_parser_fetch_flow_collection_end(parser, - yaml_FLOW_SEQUENCE_END_TOKEN) - } - - // Is it the flow mapping end indicator? - if parser.buffer[parser.buffer_pos] == '}' { - return yaml_parser_fetch_flow_collection_end(parser, - yaml_FLOW_MAPPING_END_TOKEN) - } - - // Is it the flow entry indicator? - if parser.buffer[parser.buffer_pos] == ',' { - return yaml_parser_fetch_flow_entry(parser) - } - - // Is it the block entry indicator? - if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) { - return yaml_parser_fetch_block_entry(parser) - } - - // Is it the key indicator? - if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { - return yaml_parser_fetch_key(parser) - } - - // Is it the value indicator? - if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { - return yaml_parser_fetch_value(parser) - } - - // Is it an alias? - if parser.buffer[parser.buffer_pos] == '*' { - return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN) - } - - // Is it an anchor? - if parser.buffer[parser.buffer_pos] == '&' { - return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN) - } - - // Is it a tag? - if parser.buffer[parser.buffer_pos] == '!' { - return yaml_parser_fetch_tag(parser) - } - - // Is it a literal scalar? - if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 { - return yaml_parser_fetch_block_scalar(parser, true) - } - - // Is it a folded scalar? - if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 { - return yaml_parser_fetch_block_scalar(parser, false) - } - - // Is it a single-quoted scalar? - if parser.buffer[parser.buffer_pos] == '\'' { - return yaml_parser_fetch_flow_scalar(parser, true) - } - - // Is it a double-quoted scalar? - if parser.buffer[parser.buffer_pos] == '"' { - return yaml_parser_fetch_flow_scalar(parser, false) - } - - // Is it a plain scalar? - // - // A plain scalar may start with any non-blank characters except - // - // '-', '?', ':', ',', '[', ']', '{', '}', - // '#', '&', '*', '!', '|', '>', '\'', '\"', - // '%', '@', '`'. - // - // In the block context (and, for the '-' indicator, in the flow context - // too), it may also start with the characters - // - // '-', '?', ':' - // - // if it is followed by a non-space character. - // - // The last rule is more restrictive than the specification requires. - // [Go] Make this logic more reasonable. - //switch parser.buffer[parser.buffer_pos] { - //case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`': - //} - if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' || - parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' || - parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' || - parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || - parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' || - parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' || - parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' || - parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' || - parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' || - parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') || - (parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) || - (parser.flow_level == 0 && - (parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') && - !is_blankz(parser.buffer, parser.buffer_pos+1)) { - return yaml_parser_fetch_plain_scalar(parser) - } - - // If we don't determine the token type so far, it is an error. - return yaml_parser_set_scanner_error(parser, - "while scanning for the next token", parser.mark, - "found character that cannot start any token") -} - -// Check the list of potential simple keys and remove the positions that -// cannot contain simple keys anymore. -func yaml_parser_stale_simple_keys(parser *yaml_parser_t) bool { - // Check for a potential simple key for each flow level. - for i := range parser.simple_keys { - simple_key := &parser.simple_keys[i] - - // The specification requires that a simple key - // - // - is limited to a single line, - // - is shorter than 1024 characters. - if simple_key.possible && (simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index) { - - // Check if the potential simple key to be removed is required. - if simple_key.required { - return yaml_parser_set_scanner_error(parser, - "while scanning a simple key", simple_key.mark, - "could not find expected ':'") - } - simple_key.possible = false - } - } - return true -} - -// Check if a simple key may start at the current position and add it if -// needed. -func yaml_parser_save_simple_key(parser *yaml_parser_t) bool { - // A simple key is required at the current position if the scanner is in - // the block context and the current column coincides with the indentation - // level. - - required := parser.flow_level == 0 && parser.indent == parser.mark.column - - // - // If the current position may start a simple key, save it. - // - if parser.simple_key_allowed { - simple_key := yaml_simple_key_t{ - possible: true, - required: required, - token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head), - } - simple_key.mark = parser.mark - - if !yaml_parser_remove_simple_key(parser) { - return false - } - parser.simple_keys[len(parser.simple_keys)-1] = simple_key - } - return true -} - -// Remove a potential simple key at the current flow level. -func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool { - i := len(parser.simple_keys) - 1 - if parser.simple_keys[i].possible { - // If the key is required, it is an error. - if parser.simple_keys[i].required { - return yaml_parser_set_scanner_error(parser, - "while scanning a simple key", parser.simple_keys[i].mark, - "could not find expected ':'") - } - } - // Remove the key from the stack. - parser.simple_keys[i].possible = false - return true -} - -// Increase the flow level and resize the simple key list if needed. -func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool { - // Reset the simple key on the next level. - parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{}) - - // Increase the flow level. - parser.flow_level++ - return true -} - -// Decrease the flow level. -func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool { - if parser.flow_level > 0 { - parser.flow_level-- - parser.simple_keys = parser.simple_keys[:len(parser.simple_keys)-1] - } - return true -} - -// Push the current indentation level to the stack and set the new level -// the current column is greater than the indentation level. In this case, -// append or insert the specified token into the token queue. -func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool { - // In the flow context, do nothing. - if parser.flow_level > 0 { - return true - } - - if parser.indent < column { - // Push the current indentation level to the stack and set the new - // indentation level. - parser.indents = append(parser.indents, parser.indent) - parser.indent = column - - // Create a token and insert it into the queue. - token := yaml_token_t{ - typ: typ, - start_mark: mark, - end_mark: mark, - } - if number > -1 { - number -= parser.tokens_parsed - } - yaml_insert_token(parser, number, &token) - } - return true -} - -// Pop indentation levels from the indents stack until the current level -// becomes less or equal to the column. For each indentation level, append -// the BLOCK-END token. -func yaml_parser_unroll_indent(parser *yaml_parser_t, column int) bool { - // In the flow context, do nothing. - if parser.flow_level > 0 { - return true - } - - // Loop through the indentation levels in the stack. - for parser.indent > column { - // Create a token and append it to the queue. - token := yaml_token_t{ - typ: yaml_BLOCK_END_TOKEN, - start_mark: parser.mark, - end_mark: parser.mark, - } - yaml_insert_token(parser, -1, &token) - - // Pop the indentation level. - parser.indent = parser.indents[len(parser.indents)-1] - parser.indents = parser.indents[:len(parser.indents)-1] - } - return true -} - -// Initialize the scanner and produce the STREAM-START token. -func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool { - - // Set the initial indentation. - parser.indent = -1 - - // Initialize the simple key stack. - parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{}) - - // A simple key is allowed at the beginning of the stream. - parser.simple_key_allowed = true - - // We have started. - parser.stream_start_produced = true - - // Create the STREAM-START token and append it to the queue. - token := yaml_token_t{ - typ: yaml_STREAM_START_TOKEN, - start_mark: parser.mark, - end_mark: parser.mark, - encoding: parser.encoding, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the STREAM-END token and shut down the scanner. -func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool { - - // Force new line. - if parser.mark.column != 0 { - parser.mark.column = 0 - parser.mark.line++ - } - - // Reset the indentation level. - if !yaml_parser_unroll_indent(parser, -1) { - return false - } - - // Reset simple keys. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - parser.simple_key_allowed = false - - // Create the STREAM-END token and append it to the queue. - token := yaml_token_t{ - typ: yaml_STREAM_END_TOKEN, - start_mark: parser.mark, - end_mark: parser.mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token. -func yaml_parser_fetch_directive(parser *yaml_parser_t) bool { - // Reset the indentation level. - if !yaml_parser_unroll_indent(parser, -1) { - return false - } - - // Reset simple keys. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - parser.simple_key_allowed = false - - // Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. - token := yaml_token_t{} - if !yaml_parser_scan_directive(parser, &token) { - return false - } - // Append the token to the queue. - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the DOCUMENT-START or DOCUMENT-END token. -func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool { - // Reset the indentation level. - if !yaml_parser_unroll_indent(parser, -1) { - return false - } - - // Reset simple keys. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - parser.simple_key_allowed = false - - // Consume the token. - start_mark := parser.mark - - skip(parser) - skip(parser) - skip(parser) - - end_mark := parser.mark - - // Create the DOCUMENT-START or DOCUMENT-END token. - token := yaml_token_t{ - typ: typ, - start_mark: start_mark, - end_mark: end_mark, - } - // Append the token to the queue. - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token. -func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool { - // The indicators '[' and '{' may start a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // Increase the flow level. - if !yaml_parser_increase_flow_level(parser) { - return false - } - - // A simple key may follow the indicators '[' and '{'. - parser.simple_key_allowed = true - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. - token := yaml_token_t{ - typ: typ, - start_mark: start_mark, - end_mark: end_mark, - } - // Append the token to the queue. - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token. -func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool { - // Reset any potential simple key on the current flow level. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // Decrease the flow level. - if !yaml_parser_decrease_flow_level(parser) { - return false - } - - // No simple keys after the indicators ']' and '}'. - parser.simple_key_allowed = false - - // Consume the token. - - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. - token := yaml_token_t{ - typ: typ, - start_mark: start_mark, - end_mark: end_mark, - } - // Append the token to the queue. - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the FLOW-ENTRY token. -func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool { - // Reset any potential simple keys on the current flow level. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // Simple keys are allowed after ','. - parser.simple_key_allowed = true - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the FLOW-ENTRY token and append it to the queue. - token := yaml_token_t{ - typ: yaml_FLOW_ENTRY_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the BLOCK-ENTRY token. -func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool { - // Check if the scanner is in the block context. - if parser.flow_level == 0 { - // Check if we are allowed to start a new entry. - if !parser.simple_key_allowed { - return yaml_parser_set_scanner_error(parser, "", parser.mark, - "block sequence entries are not allowed in this context") - } - // Add the BLOCK-SEQUENCE-START token if needed. - if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) { - return false - } - } else { - // It is an error for the '-' indicator to occur in the flow context, - // but we let the Parser detect and report about it because the Parser - // is able to point to the context. - } - - // Reset any potential simple keys on the current flow level. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // Simple keys are allowed after '-'. - parser.simple_key_allowed = true - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the BLOCK-ENTRY token and append it to the queue. - token := yaml_token_t{ - typ: yaml_BLOCK_ENTRY_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the KEY token. -func yaml_parser_fetch_key(parser *yaml_parser_t) bool { - - // In the block context, additional checks are required. - if parser.flow_level == 0 { - // Check if we are allowed to start a new key (not nessesary simple). - if !parser.simple_key_allowed { - return yaml_parser_set_scanner_error(parser, "", parser.mark, - "mapping keys are not allowed in this context") - } - // Add the BLOCK-MAPPING-START token if needed. - if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { - return false - } - } - - // Reset any potential simple keys on the current flow level. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // Simple keys are allowed after '?' in the block context. - parser.simple_key_allowed = parser.flow_level == 0 - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the KEY token and append it to the queue. - token := yaml_token_t{ - typ: yaml_KEY_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the VALUE token. -func yaml_parser_fetch_value(parser *yaml_parser_t) bool { - - simple_key := &parser.simple_keys[len(parser.simple_keys)-1] - - // Have we found a simple key? - if simple_key.possible { - // Create the KEY token and insert it into the queue. - token := yaml_token_t{ - typ: yaml_KEY_TOKEN, - start_mark: simple_key.mark, - end_mark: simple_key.mark, - } - yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token) - - // In the block context, we may need to add the BLOCK-MAPPING-START token. - if !yaml_parser_roll_indent(parser, simple_key.mark.column, - simple_key.token_number, - yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) { - return false - } - - // Remove the simple key. - simple_key.possible = false - - // A simple key cannot follow another simple key. - parser.simple_key_allowed = false - - } else { - // The ':' indicator follows a complex key. - - // In the block context, extra checks are required. - if parser.flow_level == 0 { - - // Check if we are allowed to start a complex value. - if !parser.simple_key_allowed { - return yaml_parser_set_scanner_error(parser, "", parser.mark, - "mapping values are not allowed in this context") - } - - // Add the BLOCK-MAPPING-START token if needed. - if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { - return false - } - } - - // Simple keys after ':' are allowed in the block context. - parser.simple_key_allowed = parser.flow_level == 0 - } - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the VALUE token and append it to the queue. - token := yaml_token_t{ - typ: yaml_VALUE_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the ALIAS or ANCHOR token. -func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool { - // An anchor or an alias could be a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // A simple key cannot follow an anchor or an alias. - parser.simple_key_allowed = false - - // Create the ALIAS or ANCHOR token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_anchor(parser, &token, typ) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the TAG token. -func yaml_parser_fetch_tag(parser *yaml_parser_t) bool { - // A tag could be a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // A simple key cannot follow a tag. - parser.simple_key_allowed = false - - // Create the TAG token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_tag(parser, &token) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens. -func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool { - // Remove any potential simple keys. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // A simple key may follow a block scalar. - parser.simple_key_allowed = true - - // Create the SCALAR token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_block_scalar(parser, &token, literal) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens. -func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool { - // A plain scalar could be a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // A simple key cannot follow a flow scalar. - parser.simple_key_allowed = false - - // Create the SCALAR token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_flow_scalar(parser, &token, single) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the SCALAR(...,plain) token. -func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool { - // A plain scalar could be a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // A simple key cannot follow a flow scalar. - parser.simple_key_allowed = false - - // Create the SCALAR token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_plain_scalar(parser, &token) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Eat whitespaces and comments until the next token is found. -func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool { - - // Until the next token is not found. - for { - // Allow the BOM mark to start a line. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) { - skip(parser) - } - - // Eat whitespaces. - // Tabs are allowed: - // - in the flow context - // - in the block context, but not at the beginning of the line or - // after '-', '?', or ':' (complex value). - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Eat a comment until a line break. - if parser.buffer[parser.buffer_pos] == '#' { - for !is_breakz(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - } - - // If it is a line break, eat it. - if is_break(parser.buffer, parser.buffer_pos) { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - skip_line(parser) - - // In the block context, a new line may start a simple key. - if parser.flow_level == 0 { - parser.simple_key_allowed = true - } - } else { - break // We have found a token. - } - } - - return true -} - -// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token. -// -// Scope: -// %YAML 1.1 # a comment \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// -func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool { - // Eat '%'. - start_mark := parser.mark - skip(parser) - - // Scan the directive name. - var name []byte - if !yaml_parser_scan_directive_name(parser, start_mark, &name) { - return false - } - - // Is it a YAML directive? - if bytes.Equal(name, []byte("YAML")) { - // Scan the VERSION directive value. - var major, minor int8 - if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) { - return false - } - end_mark := parser.mark - - // Create a VERSION-DIRECTIVE token. - *token = yaml_token_t{ - typ: yaml_VERSION_DIRECTIVE_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - major: major, - minor: minor, - } - - // Is it a TAG directive? - } else if bytes.Equal(name, []byte("TAG")) { - // Scan the TAG directive value. - var handle, prefix []byte - if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) { - return false - } - end_mark := parser.mark - - // Create a TAG-DIRECTIVE token. - *token = yaml_token_t{ - typ: yaml_TAG_DIRECTIVE_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: handle, - prefix: prefix, - } - - // Unknown directive. - } else { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "found unknown directive name") - return false - } - - // Eat the rest of the line including any comments. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - if parser.buffer[parser.buffer_pos] == '#' { - for !is_breakz(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - } - - // Check if we are at the end of the line. - if !is_breakz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "did not find expected comment or line break") - return false - } - - // Eat a line break. - if is_break(parser.buffer, parser.buffer_pos) { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - skip_line(parser) - } - - return true -} - -// Scan the directive name. -// -// Scope: -// %YAML 1.1 # a comment \n -// ^^^^ -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^ -// -func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool { - // Consume the directive name. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - var s []byte - for is_alpha(parser.buffer, parser.buffer_pos) { - s = read(parser, s) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Check if the name is empty. - if len(s) == 0 { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "could not find expected directive name") - return false - } - - // Check for an blank character after the name. - if !is_blankz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "found unexpected non-alphabetical character") - return false - } - *name = s - return true -} - -// Scan the value of VERSION-DIRECTIVE. -// -// Scope: -// %YAML 1.1 # a comment \n -// ^^^^^^ -func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool { - // Eat whitespaces. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Consume the major version number. - if !yaml_parser_scan_version_directive_number(parser, start_mark, major) { - return false - } - - // Eat '.'. - if parser.buffer[parser.buffer_pos] != '.' { - return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", - start_mark, "did not find expected digit or '.' character") - } - - skip(parser) - - // Consume the minor version number. - if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) { - return false - } - return true -} - -const max_number_length = 2 - -// Scan the version number of VERSION-DIRECTIVE. -// -// Scope: -// %YAML 1.1 # a comment \n -// ^ -// %YAML 1.1 # a comment \n -// ^ -func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool { - - // Repeat while the next character is digit. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - var value, length int8 - for is_digit(parser.buffer, parser.buffer_pos) { - // Check if the number is too long. - length++ - if length > max_number_length { - return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", - start_mark, "found extremely long version number") - } - value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos)) - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Check if the number was present. - if length == 0 { - return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", - start_mark, "did not find expected version number") - } - *number = value - return true -} - -// Scan the value of a TAG-DIRECTIVE token. -// -// Scope: -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// -func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool { - var handle_value, prefix_value []byte - - // Eat whitespaces. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Scan a handle. - if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) { - return false - } - - // Expect a whitespace. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if !is_blank(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", - start_mark, "did not find expected whitespace") - return false - } - - // Eat whitespaces. - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Scan a prefix. - if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) { - return false - } - - // Expect a whitespace or line break. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if !is_blankz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", - start_mark, "did not find expected whitespace or line break") - return false - } - - *handle = handle_value - *prefix = prefix_value - return true -} - -func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool { - var s []byte - - // Eat the indicator character. - start_mark := parser.mark - skip(parser) - - // Consume the value. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_alpha(parser.buffer, parser.buffer_pos) { - s = read(parser, s) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - end_mark := parser.mark - - /* - * Check if length of the anchor is greater than 0 and it is followed by - * a whitespace character or one of the indicators: - * - * '?', ':', ',', ']', '}', '%', '@', '`'. - */ - - if len(s) == 0 || - !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' || - parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' || - parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' || - parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' || - parser.buffer[parser.buffer_pos] == '`') { - context := "while scanning an alias" - if typ == yaml_ANCHOR_TOKEN { - context = "while scanning an anchor" - } - yaml_parser_set_scanner_error(parser, context, start_mark, - "did not find expected alphabetic or numeric character") - return false - } - - // Create a token. - *token = yaml_token_t{ - typ: typ, - start_mark: start_mark, - end_mark: end_mark, - value: s, - } - - return true -} - -/* - * Scan a TAG token. - */ - -func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool { - var handle, suffix []byte - - start_mark := parser.mark - - // Check if the tag is in the canonical form. - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - - if parser.buffer[parser.buffer_pos+1] == '<' { - // Keep the handle as '' - - // Eat '!<' - skip(parser) - skip(parser) - - // Consume the tag value. - if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { - return false - } - - // Check for '>' and eat it. - if parser.buffer[parser.buffer_pos] != '>' { - yaml_parser_set_scanner_error(parser, "while scanning a tag", - start_mark, "did not find the expected '>'") - return false - } - - skip(parser) - } else { - // The tag has either the '!suffix' or the '!handle!suffix' form. - - // First, try to scan a handle. - if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) { - return false - } - - // Check if it is, indeed, handle. - if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' { - // Scan the suffix now. - if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { - return false - } - } else { - // It wasn't a handle after all. Scan the rest of the tag. - if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) { - return false - } - - // Set the handle to '!'. - handle = []byte{'!'} - - // A special case: the '!' tag. Set the handle to '' and the - // suffix to '!'. - if len(suffix) == 0 { - handle, suffix = suffix, handle - } - } - } - - // Check the character which ends the tag. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if !is_blankz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a tag", - start_mark, "did not find expected whitespace or line break") - return false - } - - end_mark := parser.mark - - // Create a token. - *token = yaml_token_t{ - typ: yaml_TAG_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: handle, - suffix: suffix, - } - return true -} - -// Scan a tag handle. -func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool { - // Check the initial '!' character. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if parser.buffer[parser.buffer_pos] != '!' { - yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "did not find expected '!'") - return false - } - - var s []byte - - // Copy the '!' character. - s = read(parser, s) - - // Copy all subsequent alphabetical and numerical characters. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - for is_alpha(parser.buffer, parser.buffer_pos) { - s = read(parser, s) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Check if the trailing character is '!' and copy it. - if parser.buffer[parser.buffer_pos] == '!' { - s = read(parser, s) - } else { - // It's either the '!' tag or not really a tag handle. If it's a %TAG - // directive, it's an error. If it's a tag token, it must be a part of URI. - if directive && string(s) != "!" { - yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "did not find expected '!'") - return false - } - } - - *handle = s - return true -} - -// Scan a tag. -func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool { - //size_t length = head ? strlen((char *)head) : 0 - var s []byte - hasTag := len(head) > 0 - - // Copy the head if needed. - // - // Note that we don't copy the leading '!' character. - if len(head) > 1 { - s = append(s, head[1:]...) - } - - // Scan the tag. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - // The set of characters that may appear in URI is as follows: - // - // '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&', - // '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']', - // '%'. - // [Go] Convert this into more reasonable logic. - for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' || - parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' || - parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' || - parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' || - parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' || - parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' || - parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' || - parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' || - parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' || - parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' || - parser.buffer[parser.buffer_pos] == '%' { - // Check if it is a URI-escape sequence. - if parser.buffer[parser.buffer_pos] == '%' { - if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) { - return false - } - } else { - s = read(parser, s) - } - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - hasTag = true - } - - if !hasTag { - yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "did not find expected tag URI") - return false - } - *uri = s - return true -} - -// Decode an URI-escape sequence corresponding to a single UTF-8 character. -func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool { - - // Decode the required number of characters. - w := 1024 - for w > 0 { - // Check for a URI-escaped octet. - if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { - return false - } - - if !(parser.buffer[parser.buffer_pos] == '%' && - is_hex(parser.buffer, parser.buffer_pos+1) && - is_hex(parser.buffer, parser.buffer_pos+2)) { - return yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "did not find URI escaped octet") - } - - // Get the octet. - octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2)) - - // If it is the leading octet, determine the length of the UTF-8 sequence. - if w == 1024 { - w = width(octet) - if w == 0 { - return yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "found an incorrect leading UTF-8 octet") - } - } else { - // Check if the trailing octet is correct. - if octet&0xC0 != 0x80 { - return yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "found an incorrect trailing UTF-8 octet") - } - } - - // Copy the octet and move the pointers. - *s = append(*s, octet) - skip(parser) - skip(parser) - skip(parser) - w-- - } - return true -} - -// Scan a block scalar. -func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool { - // Eat the indicator '|' or '>'. - start_mark := parser.mark - skip(parser) - - // Scan the additional block scalar indicators. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - // Check for a chomping indicator. - var chomping, increment int - if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { - // Set the chomping method and eat the indicator. - if parser.buffer[parser.buffer_pos] == '+' { - chomping = +1 - } else { - chomping = -1 - } - skip(parser) - - // Check for an indentation indicator. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if is_digit(parser.buffer, parser.buffer_pos) { - // Check that the indentation is greater than 0. - if parser.buffer[parser.buffer_pos] == '0' { - yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "found an indentation indicator equal to 0") - return false - } - - // Get the indentation level and eat the indicator. - increment = as_digit(parser.buffer, parser.buffer_pos) - skip(parser) - } - - } else if is_digit(parser.buffer, parser.buffer_pos) { - // Do the same as above, but in the opposite order. - - if parser.buffer[parser.buffer_pos] == '0' { - yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "found an indentation indicator equal to 0") - return false - } - increment = as_digit(parser.buffer, parser.buffer_pos) - skip(parser) - - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { - if parser.buffer[parser.buffer_pos] == '+' { - chomping = +1 - } else { - chomping = -1 - } - skip(parser) - } - } - - // Eat whitespaces and comments to the end of the line. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - if parser.buffer[parser.buffer_pos] == '#' { - for !is_breakz(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - } - - // Check if we are at the end of the line. - if !is_breakz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "did not find expected comment or line break") - return false - } - - // Eat a line break. - if is_break(parser.buffer, parser.buffer_pos) { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - skip_line(parser) - } - - end_mark := parser.mark - - // Set the indentation level if it was specified. - var indent int - if increment > 0 { - if parser.indent >= 0 { - indent = parser.indent + increment - } else { - indent = increment - } - } - - // Scan the leading line breaks and determine the indentation level if needed. - var s, leading_break, trailing_breaks []byte - if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { - return false - } - - // Scan the block scalar content. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - var leading_blank, trailing_blank bool - for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) { - // We are at the beginning of a non-empty line. - - // Is it a trailing whitespace? - trailing_blank = is_blank(parser.buffer, parser.buffer_pos) - - // Check if we need to fold the leading line break. - if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' { - // Do we need to join the lines by space? - if len(trailing_breaks) == 0 { - s = append(s, ' ') - } - } else { - s = append(s, leading_break...) - } - leading_break = leading_break[:0] - - // Append the remaining line breaks. - s = append(s, trailing_breaks...) - trailing_breaks = trailing_breaks[:0] - - // Is it a leading whitespace? - leading_blank = is_blank(parser.buffer, parser.buffer_pos) - - // Consume the current line. - for !is_breakz(parser.buffer, parser.buffer_pos) { - s = read(parser, s) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Consume the line break. - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - - leading_break = read_line(parser, leading_break) - - // Eat the following indentation spaces and line breaks. - if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { - return false - } - } - - // Chomp the tail. - if chomping != -1 { - s = append(s, leading_break...) - } - if chomping == 1 { - s = append(s, trailing_breaks...) - } - - // Create a token. - *token = yaml_token_t{ - typ: yaml_SCALAR_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: s, - style: yaml_LITERAL_SCALAR_STYLE, - } - if !literal { - token.style = yaml_FOLDED_SCALAR_STYLE - } - return true -} - -// Scan indentation spaces and line breaks for a block scalar. Determine the -// indentation level if needed. -func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool { - *end_mark = parser.mark - - // Eat the indentation spaces and line breaks. - max_indent := 0 - for { - // Eat the indentation spaces. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - if parser.mark.column > max_indent { - max_indent = parser.mark.column - } - - // Check for a tab character messing the indentation. - if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) { - return yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "found a tab character where an indentation space is expected") - } - - // Have we found a non-empty line? - if !is_break(parser.buffer, parser.buffer_pos) { - break - } - - // Consume the line break. - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - // [Go] Should really be returning breaks instead. - *breaks = read_line(parser, *breaks) - *end_mark = parser.mark - } - - // Determine the indentation level if needed. - if *indent == 0 { - *indent = max_indent - if *indent < parser.indent+1 { - *indent = parser.indent + 1 - } - if *indent < 1 { - *indent = 1 - } - } - return true -} - -// Scan a quoted scalar. -func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool { - // Eat the left quote. - start_mark := parser.mark - skip(parser) - - // Consume the content of the quoted scalar. - var s, leading_break, trailing_breaks, whitespaces []byte - for { - // Check that there are no document indicators at the beginning of the line. - if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { - return false - } - - if parser.mark.column == 0 && - ((parser.buffer[parser.buffer_pos+0] == '-' && - parser.buffer[parser.buffer_pos+1] == '-' && - parser.buffer[parser.buffer_pos+2] == '-') || - (parser.buffer[parser.buffer_pos+0] == '.' && - parser.buffer[parser.buffer_pos+1] == '.' && - parser.buffer[parser.buffer_pos+2] == '.')) && - is_blankz(parser.buffer, parser.buffer_pos+3) { - yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", - start_mark, "found unexpected document indicator") - return false - } - - // Check for EOF. - if is_z(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", - start_mark, "found unexpected end of stream") - return false - } - - // Consume non-blank characters. - leading_blanks := false - for !is_blankz(parser.buffer, parser.buffer_pos) { - if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' { - // Is is an escaped single quote. - s = append(s, '\'') - skip(parser) - skip(parser) - - } else if single && parser.buffer[parser.buffer_pos] == '\'' { - // It is a right single quote. - break - } else if !single && parser.buffer[parser.buffer_pos] == '"' { - // It is a right double quote. - break - - } else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) { - // It is an escaped line break. - if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { - return false - } - skip(parser) - skip_line(parser) - leading_blanks = true - break - - } else if !single && parser.buffer[parser.buffer_pos] == '\\' { - // It is an escape sequence. - code_length := 0 - - // Check the escape character. - switch parser.buffer[parser.buffer_pos+1] { - case '0': - s = append(s, 0) - case 'a': - s = append(s, '\x07') - case 'b': - s = append(s, '\x08') - case 't', '\t': - s = append(s, '\x09') - case 'n': - s = append(s, '\x0A') - case 'v': - s = append(s, '\x0B') - case 'f': - s = append(s, '\x0C') - case 'r': - s = append(s, '\x0D') - case 'e': - s = append(s, '\x1B') - case ' ': - s = append(s, '\x20') - case '"': - s = append(s, '"') - case '\'': - s = append(s, '\'') - case '\\': - s = append(s, '\\') - case 'N': // NEL (#x85) - s = append(s, '\xC2') - s = append(s, '\x85') - case '_': // #xA0 - s = append(s, '\xC2') - s = append(s, '\xA0') - case 'L': // LS (#x2028) - s = append(s, '\xE2') - s = append(s, '\x80') - s = append(s, '\xA8') - case 'P': // PS (#x2029) - s = append(s, '\xE2') - s = append(s, '\x80') - s = append(s, '\xA9') - case 'x': - code_length = 2 - case 'u': - code_length = 4 - case 'U': - code_length = 8 - default: - yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", - start_mark, "found unknown escape character") - return false - } - - skip(parser) - skip(parser) - - // Consume an arbitrary escape code. - if code_length > 0 { - var value int - - // Scan the character value. - if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) { - return false - } - for k := 0; k < code_length; k++ { - if !is_hex(parser.buffer, parser.buffer_pos+k) { - yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", - start_mark, "did not find expected hexdecimal number") - return false - } - value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k) - } - - // Check the value and write the character. - if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF { - yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", - start_mark, "found invalid Unicode character escape code") - return false - } - if value <= 0x7F { - s = append(s, byte(value)) - } else if value <= 0x7FF { - s = append(s, byte(0xC0+(value>>6))) - s = append(s, byte(0x80+(value&0x3F))) - } else if value <= 0xFFFF { - s = append(s, byte(0xE0+(value>>12))) - s = append(s, byte(0x80+((value>>6)&0x3F))) - s = append(s, byte(0x80+(value&0x3F))) - } else { - s = append(s, byte(0xF0+(value>>18))) - s = append(s, byte(0x80+((value>>12)&0x3F))) - s = append(s, byte(0x80+((value>>6)&0x3F))) - s = append(s, byte(0x80+(value&0x3F))) - } - - // Advance the pointer. - for k := 0; k < code_length; k++ { - skip(parser) - } - } - } else { - // It is a non-escaped non-blank character. - s = read(parser, s) - } - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - } - - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - // Check if we are at the end of the scalar. - if single { - if parser.buffer[parser.buffer_pos] == '\'' { - break - } - } else { - if parser.buffer[parser.buffer_pos] == '"' { - break - } - } - - // Consume blank characters. - for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { - if is_blank(parser.buffer, parser.buffer_pos) { - // Consume a space or a tab character. - if !leading_blanks { - whitespaces = read(parser, whitespaces) - } else { - skip(parser) - } - } else { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - - // Check if it is a first line break. - if !leading_blanks { - whitespaces = whitespaces[:0] - leading_break = read_line(parser, leading_break) - leading_blanks = true - } else { - trailing_breaks = read_line(parser, trailing_breaks) - } - } - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Join the whitespaces or fold line breaks. - if leading_blanks { - // Do we need to fold line breaks? - if len(leading_break) > 0 && leading_break[0] == '\n' { - if len(trailing_breaks) == 0 { - s = append(s, ' ') - } else { - s = append(s, trailing_breaks...) - } - } else { - s = append(s, leading_break...) - s = append(s, trailing_breaks...) - } - trailing_breaks = trailing_breaks[:0] - leading_break = leading_break[:0] - } else { - s = append(s, whitespaces...) - whitespaces = whitespaces[:0] - } - } - - // Eat the right quote. - skip(parser) - end_mark := parser.mark - - // Create a token. - *token = yaml_token_t{ - typ: yaml_SCALAR_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: s, - style: yaml_SINGLE_QUOTED_SCALAR_STYLE, - } - if !single { - token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - return true -} - -// Scan a plain scalar. -func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool { - - var s, leading_break, trailing_breaks, whitespaces []byte - var leading_blanks bool - var indent = parser.indent + 1 - - start_mark := parser.mark - end_mark := parser.mark - - // Consume the content of the plain scalar. - for { - // Check for a document indicator. - if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { - return false - } - if parser.mark.column == 0 && - ((parser.buffer[parser.buffer_pos+0] == '-' && - parser.buffer[parser.buffer_pos+1] == '-' && - parser.buffer[parser.buffer_pos+2] == '-') || - (parser.buffer[parser.buffer_pos+0] == '.' && - parser.buffer[parser.buffer_pos+1] == '.' && - parser.buffer[parser.buffer_pos+2] == '.')) && - is_blankz(parser.buffer, parser.buffer_pos+3) { - break - } - - // Check for a comment. - if parser.buffer[parser.buffer_pos] == '#' { - break - } - - // Consume non-blank characters. - for !is_blankz(parser.buffer, parser.buffer_pos) { - - // Check for indicators that may end a plain scalar. - if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) || - (parser.flow_level > 0 && - (parser.buffer[parser.buffer_pos] == ',' || - parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' || - parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || - parser.buffer[parser.buffer_pos] == '}')) { - break - } - - // Check if we need to join whitespaces and breaks. - if leading_blanks || len(whitespaces) > 0 { - if leading_blanks { - // Do we need to fold line breaks? - if leading_break[0] == '\n' { - if len(trailing_breaks) == 0 { - s = append(s, ' ') - } else { - s = append(s, trailing_breaks...) - } - } else { - s = append(s, leading_break...) - s = append(s, trailing_breaks...) - } - trailing_breaks = trailing_breaks[:0] - leading_break = leading_break[:0] - leading_blanks = false - } else { - s = append(s, whitespaces...) - whitespaces = whitespaces[:0] - } - } - - // Copy the character. - s = read(parser, s) - - end_mark = parser.mark - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - } - - // Is it the end? - if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) { - break - } - - // Consume blank characters. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { - if is_blank(parser.buffer, parser.buffer_pos) { - - // Check for tab characters that abuse indentation. - if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", - start_mark, "found a tab character that violates indentation") - return false - } - - // Consume a space or a tab character. - if !leading_blanks { - whitespaces = read(parser, whitespaces) - } else { - skip(parser) - } - } else { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - - // Check if it is a first line break. - if !leading_blanks { - whitespaces = whitespaces[:0] - leading_break = read_line(parser, leading_break) - leading_blanks = true - } else { - trailing_breaks = read_line(parser, trailing_breaks) - } - } - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Check indentation level. - if parser.flow_level == 0 && parser.mark.column < indent { - break - } - } - - // Create a token. - *token = yaml_token_t{ - typ: yaml_SCALAR_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: s, - style: yaml_PLAIN_SCALAR_STYLE, - } - - // Note that we change the 'simple_key_allowed' flag. - if leading_blanks { - parser.simple_key_allowed = true - } - return true -} diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/sorter.go b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/sorter.go deleted file mode 100755 index 4c45e66..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/sorter.go +++ /dev/null @@ -1,113 +0,0 @@ -package yaml - -import ( - "reflect" - "unicode" -) - -type keyList []reflect.Value - -func (l keyList) Len() int { return len(l) } -func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } -func (l keyList) Less(i, j int) bool { - a := l[i] - b := l[j] - ak := a.Kind() - bk := b.Kind() - for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { - a = a.Elem() - ak = a.Kind() - } - for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { - b = b.Elem() - bk = b.Kind() - } - af, aok := keyFloat(a) - bf, bok := keyFloat(b) - if aok && bok { - if af != bf { - return af < bf - } - if ak != bk { - return ak < bk - } - return numLess(a, b) - } - if ak != reflect.String || bk != reflect.String { - return ak < bk - } - ar, br := []rune(a.String()), []rune(b.String()) - for i := 0; i < len(ar) && i < len(br); i++ { - if ar[i] == br[i] { - continue - } - al := unicode.IsLetter(ar[i]) - bl := unicode.IsLetter(br[i]) - if al && bl { - return ar[i] < br[i] - } - if al || bl { - return bl - } - var ai, bi int - var an, bn int64 - if ar[i] == '0' || br[i] == '0' { - for j := i-1; j >= 0 && unicode.IsDigit(ar[j]); j-- { - if ar[j] != '0' { - an = 1 - bn = 1 - break - } - } - } - for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { - an = an*10 + int64(ar[ai]-'0') - } - for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { - bn = bn*10 + int64(br[bi]-'0') - } - if an != bn { - return an < bn - } - if ai != bi { - return ai < bi - } - return ar[i] < br[i] - } - return len(ar) < len(br) -} - -// keyFloat returns a float value for v if it is a number/bool -// and whether it is a number/bool or not. -func keyFloat(v reflect.Value) (f float64, ok bool) { - switch v.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return float64(v.Int()), true - case reflect.Float32, reflect.Float64: - return v.Float(), true - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return float64(v.Uint()), true - case reflect.Bool: - if v.Bool() { - return 1, true - } - return 0, true - } - return 0, false -} - -// numLess returns whether a < b. -// a and b must necessarily have the same kind. -func numLess(a, b reflect.Value) bool { - switch a.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return a.Int() < b.Int() - case reflect.Float32, reflect.Float64: - return a.Float() < b.Float() - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return a.Uint() < b.Uint() - case reflect.Bool: - return !a.Bool() && b.Bool() - } - panic("not a number") -} diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/writerc.go b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/writerc.go deleted file mode 100755 index a2dde60..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/writerc.go +++ /dev/null @@ -1,26 +0,0 @@ -package yaml - -// Set the writer error and return false. -func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { - emitter.error = yaml_WRITER_ERROR - emitter.problem = problem - return false -} - -// Flush the output buffer. -func yaml_emitter_flush(emitter *yaml_emitter_t) bool { - if emitter.write_handler == nil { - panic("write handler not set") - } - - // Check if the buffer is empty. - if emitter.buffer_pos == 0 { - return true - } - - if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { - return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) - } - emitter.buffer_pos = 0 - return true -} diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/yaml.go b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/yaml.go deleted file mode 100755 index de85aa4..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/yaml.go +++ /dev/null @@ -1,466 +0,0 @@ -// Package yaml implements YAML support for the Go language. -// -// Source code and other details for the project are available at GitHub: -// -// https://github.com/go-yaml/yaml -// -package yaml - -import ( - "errors" - "fmt" - "io" - "reflect" - "strings" - "sync" -) - -// MapSlice encodes and decodes as a YAML map. -// The order of keys is preserved when encoding and decoding. -type MapSlice []MapItem - -// MapItem is an item in a MapSlice. -type MapItem struct { - Key, Value interface{} -} - -// The Unmarshaler interface may be implemented by types to customize their -// behavior when being unmarshaled from a YAML document. The UnmarshalYAML -// method receives a function that may be called to unmarshal the original -// YAML value into a field or variable. It is safe to call the unmarshal -// function parameter more than once if necessary. -type Unmarshaler interface { - UnmarshalYAML(unmarshal func(interface{}) error) error -} - -// The Marshaler interface may be implemented by types to customize their -// behavior when being marshaled into a YAML document. The returned value -// is marshaled in place of the original value implementing Marshaler. -// -// If an error is returned by MarshalYAML, the marshaling procedure stops -// and returns with the provided error. -type Marshaler interface { - MarshalYAML() (interface{}, error) -} - -// Unmarshal decodes the first document found within the in byte slice -// and assigns decoded values into the out value. -// -// Maps and pointers (to a struct, string, int, etc) are accepted as out -// values. If an internal pointer within a struct is not initialized, -// the yaml package will initialize it if necessary for unmarshalling -// the provided data. The out parameter must not be nil. -// -// The type of the decoded values should be compatible with the respective -// values in out. If one or more values cannot be decoded due to a type -// mismatches, decoding continues partially until the end of the YAML -// content, and a *yaml.TypeError is returned with details for all -// missed values. -// -// Struct fields are only unmarshalled if they are exported (have an -// upper case first letter), and are unmarshalled using the field name -// lowercased as the default key. Custom keys may be defined via the -// "yaml" name in the field tag: the content preceding the first comma -// is used as the key, and the following comma-separated options are -// used to tweak the marshalling process (see Marshal). -// Conflicting names result in a runtime error. -// -// For example: -// -// type T struct { -// F int `yaml:"a,omitempty"` -// B int -// } -// var t T -// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) -// -// See the documentation of Marshal for the format of tags and a list of -// supported tag options. -// -func Unmarshal(in []byte, out interface{}) (err error) { - return unmarshal(in, out, false) -} - -// UnmarshalStrict is like Unmarshal except that any fields that are found -// in the data that do not have corresponding struct members, or mapping -// keys that are duplicates, will result in -// an error. -func UnmarshalStrict(in []byte, out interface{}) (err error) { - return unmarshal(in, out, true) -} - -// A Decorder reads and decodes YAML values from an input stream. -type Decoder struct { - strict bool - parser *parser -} - -// NewDecoder returns a new decoder that reads from r. -// -// The decoder introduces its own buffering and may read -// data from r beyond the YAML values requested. -func NewDecoder(r io.Reader) *Decoder { - return &Decoder{ - parser: newParserFromReader(r), - } -} - -// SetStrict sets whether strict decoding behaviour is enabled when -// decoding items in the data (see UnmarshalStrict). By default, decoding is not strict. -func (dec *Decoder) SetStrict(strict bool) { - dec.strict = strict -} - -// Decode reads the next YAML-encoded value from its input -// and stores it in the value pointed to by v. -// -// See the documentation for Unmarshal for details about the -// conversion of YAML into a Go value. -func (dec *Decoder) Decode(v interface{}) (err error) { - d := newDecoder(dec.strict) - defer handleErr(&err) - node := dec.parser.parse() - if node == nil { - return io.EOF - } - out := reflect.ValueOf(v) - if out.Kind() == reflect.Ptr && !out.IsNil() { - out = out.Elem() - } - d.unmarshal(node, out) - if len(d.terrors) > 0 { - return &TypeError{d.terrors} - } - return nil -} - -func unmarshal(in []byte, out interface{}, strict bool) (err error) { - defer handleErr(&err) - d := newDecoder(strict) - p := newParser(in) - defer p.destroy() - node := p.parse() - if node != nil { - v := reflect.ValueOf(out) - if v.Kind() == reflect.Ptr && !v.IsNil() { - v = v.Elem() - } - d.unmarshal(node, v) - } - if len(d.terrors) > 0 { - return &TypeError{d.terrors} - } - return nil -} - -// Marshal serializes the value provided into a YAML document. The structure -// of the generated document will reflect the structure of the value itself. -// Maps and pointers (to struct, string, int, etc) are accepted as the in value. -// -// Struct fields are only marshalled if they are exported (have an upper case -// first letter), and are marshalled using the field name lowercased as the -// default key. Custom keys may be defined via the "yaml" name in the field -// tag: the content preceding the first comma is used as the key, and the -// following comma-separated options are used to tweak the marshalling process. -// Conflicting names result in a runtime error. -// -// The field tag format accepted is: -// -// `(...) yaml:"[][,[,]]" (...)` -// -// The following flags are currently supported: -// -// omitempty Only include the field if it's not set to the zero -// value for the type or to empty slices or maps. -// Zero valued structs will be omitted if all their public -// fields are zero, unless they implement an IsZero -// method (see the IsZeroer interface type), in which -// case the field will be included if that method returns true. -// -// flow Marshal using a flow style (useful for structs, -// sequences and maps). -// -// inline Inline the field, which must be a struct or a map, -// causing all of its fields or keys to be processed as if -// they were part of the outer struct. For maps, keys must -// not conflict with the yaml keys of other struct fields. -// -// In addition, if the key is "-", the field is ignored. -// -// For example: -// -// type T struct { -// F int `yaml:"a,omitempty"` -// B int -// } -// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" -// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n" -// -func Marshal(in interface{}) (out []byte, err error) { - defer handleErr(&err) - e := newEncoder() - defer e.destroy() - e.marshalDoc("", reflect.ValueOf(in)) - e.finish() - out = e.out - return -} - -// An Encoder writes YAML values to an output stream. -type Encoder struct { - encoder *encoder -} - -// NewEncoder returns a new encoder that writes to w. -// The Encoder should be closed after use to flush all data -// to w. -func NewEncoder(w io.Writer) *Encoder { - return &Encoder{ - encoder: newEncoderWithWriter(w), - } -} - -// Encode writes the YAML encoding of v to the stream. -// If multiple items are encoded to the stream, the -// second and subsequent document will be preceded -// with a "---" document separator, but the first will not. -// -// See the documentation for Marshal for details about the conversion of Go -// values to YAML. -func (e *Encoder) Encode(v interface{}) (err error) { - defer handleErr(&err) - e.encoder.marshalDoc("", reflect.ValueOf(v)) - return nil -} - -// Close closes the encoder by writing any remaining data. -// It does not write a stream terminating string "...". -func (e *Encoder) Close() (err error) { - defer handleErr(&err) - e.encoder.finish() - return nil -} - -func handleErr(err *error) { - if v := recover(); v != nil { - if e, ok := v.(yamlError); ok { - *err = e.err - } else { - panic(v) - } - } -} - -type yamlError struct { - err error -} - -func fail(err error) { - panic(yamlError{err}) -} - -func failf(format string, args ...interface{}) { - panic(yamlError{fmt.Errorf("yaml: "+format, args...)}) -} - -// A TypeError is returned by Unmarshal when one or more fields in -// the YAML document cannot be properly decoded into the requested -// types. When this error is returned, the value is still -// unmarshaled partially. -type TypeError struct { - Errors []string -} - -func (e *TypeError) Error() string { - return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n ")) -} - -// -------------------------------------------------------------------------- -// Maintain a mapping of keys to structure field indexes - -// The code in this section was copied from mgo/bson. - -// structInfo holds details for the serialization of fields of -// a given struct. -type structInfo struct { - FieldsMap map[string]fieldInfo - FieldsList []fieldInfo - - // InlineMap is the number of the field in the struct that - // contains an ,inline map, or -1 if there's none. - InlineMap int -} - -type fieldInfo struct { - Key string - Num int - OmitEmpty bool - Flow bool - // Id holds the unique field identifier, so we can cheaply - // check for field duplicates without maintaining an extra map. - Id int - - // Inline holds the field index if the field is part of an inlined struct. - Inline []int -} - -var structMap = make(map[reflect.Type]*structInfo) -var fieldMapMutex sync.RWMutex - -func getStructInfo(st reflect.Type) (*structInfo, error) { - fieldMapMutex.RLock() - sinfo, found := structMap[st] - fieldMapMutex.RUnlock() - if found { - return sinfo, nil - } - - n := st.NumField() - fieldsMap := make(map[string]fieldInfo) - fieldsList := make([]fieldInfo, 0, n) - inlineMap := -1 - for i := 0; i != n; i++ { - field := st.Field(i) - if field.PkgPath != "" && !field.Anonymous { - continue // Private field - } - - info := fieldInfo{Num: i} - - tag := field.Tag.Get("yaml") - if tag == "" && strings.Index(string(field.Tag), ":") < 0 { - tag = string(field.Tag) - } - if tag == "-" { - continue - } - - inline := false - fields := strings.Split(tag, ",") - if len(fields) > 1 { - for _, flag := range fields[1:] { - switch flag { - case "omitempty": - info.OmitEmpty = true - case "flow": - info.Flow = true - case "inline": - inline = true - default: - return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st)) - } - } - tag = fields[0] - } - - if inline { - switch field.Type.Kind() { - case reflect.Map: - if inlineMap >= 0 { - return nil, errors.New("Multiple ,inline maps in struct " + st.String()) - } - if field.Type.Key() != reflect.TypeOf("") { - return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String()) - } - inlineMap = info.Num - case reflect.Struct: - sinfo, err := getStructInfo(field.Type) - if err != nil { - return nil, err - } - for _, finfo := range sinfo.FieldsList { - if _, found := fieldsMap[finfo.Key]; found { - msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String() - return nil, errors.New(msg) - } - if finfo.Inline == nil { - finfo.Inline = []int{i, finfo.Num} - } else { - finfo.Inline = append([]int{i}, finfo.Inline...) - } - finfo.Id = len(fieldsList) - fieldsMap[finfo.Key] = finfo - fieldsList = append(fieldsList, finfo) - } - default: - //return nil, errors.New("Option ,inline needs a struct value or map field") - return nil, errors.New("Option ,inline needs a struct value field") - } - continue - } - - if tag != "" { - info.Key = tag - } else { - info.Key = strings.ToLower(field.Name) - } - - if _, found = fieldsMap[info.Key]; found { - msg := "Duplicated key '" + info.Key + "' in struct " + st.String() - return nil, errors.New(msg) - } - - info.Id = len(fieldsList) - fieldsList = append(fieldsList, info) - fieldsMap[info.Key] = info - } - - sinfo = &structInfo{ - FieldsMap: fieldsMap, - FieldsList: fieldsList, - InlineMap: inlineMap, - } - - fieldMapMutex.Lock() - structMap[st] = sinfo - fieldMapMutex.Unlock() - return sinfo, nil -} - -// IsZeroer is used to check whether an object is zero to -// determine whether it should be omitted when marshaling -// with the omitempty flag. One notable implementation -// is time.Time. -type IsZeroer interface { - IsZero() bool -} - -func isZero(v reflect.Value) bool { - kind := v.Kind() - if z, ok := v.Interface().(IsZeroer); ok { - if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() { - return true - } - return z.IsZero() - } - switch kind { - case reflect.String: - return len(v.String()) == 0 - case reflect.Interface, reflect.Ptr: - return v.IsNil() - case reflect.Slice: - return v.Len() == 0 - case reflect.Map: - return v.Len() == 0 - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Bool: - return !v.Bool() - case reflect.Struct: - vt := v.Type() - for i := v.NumField() - 1; i >= 0; i-- { - if vt.Field(i).PkgPath != "" { - continue // Private field - } - if !isZero(v.Field(i)) { - return false - } - } - return true - } - return false -} diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/yamlh.go b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/yamlh.go deleted file mode 100755 index e25cee5..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/yamlh.go +++ /dev/null @@ -1,738 +0,0 @@ -package yaml - -import ( - "fmt" - "io" -) - -// The version directive data. -type yaml_version_directive_t struct { - major int8 // The major version number. - minor int8 // The minor version number. -} - -// The tag directive data. -type yaml_tag_directive_t struct { - handle []byte // The tag handle. - prefix []byte // The tag prefix. -} - -type yaml_encoding_t int - -// The stream encoding. -const ( - // Let the parser choose the encoding. - yaml_ANY_ENCODING yaml_encoding_t = iota - - yaml_UTF8_ENCODING // The default UTF-8 encoding. - yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM. - yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM. -) - -type yaml_break_t int - -// Line break types. -const ( - // Let the parser choose the break type. - yaml_ANY_BREAK yaml_break_t = iota - - yaml_CR_BREAK // Use CR for line breaks (Mac style). - yaml_LN_BREAK // Use LN for line breaks (Unix style). - yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style). -) - -type yaml_error_type_t int - -// Many bad things could happen with the parser and emitter. -const ( - // No error is produced. - yaml_NO_ERROR yaml_error_type_t = iota - - yaml_MEMORY_ERROR // Cannot allocate or reallocate a block of memory. - yaml_READER_ERROR // Cannot read or decode the input stream. - yaml_SCANNER_ERROR // Cannot scan the input stream. - yaml_PARSER_ERROR // Cannot parse the input stream. - yaml_COMPOSER_ERROR // Cannot compose a YAML document. - yaml_WRITER_ERROR // Cannot write to the output stream. - yaml_EMITTER_ERROR // Cannot emit a YAML stream. -) - -// The pointer position. -type yaml_mark_t struct { - index int // The position index. - line int // The position line. - column int // The position column. -} - -// Node Styles - -type yaml_style_t int8 - -type yaml_scalar_style_t yaml_style_t - -// Scalar styles. -const ( - // Let the emitter choose the style. - yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = iota - - yaml_PLAIN_SCALAR_STYLE // The plain scalar style. - yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style. - yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style. - yaml_LITERAL_SCALAR_STYLE // The literal scalar style. - yaml_FOLDED_SCALAR_STYLE // The folded scalar style. -) - -type yaml_sequence_style_t yaml_style_t - -// Sequence styles. -const ( - // Let the emitter choose the style. - yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota - - yaml_BLOCK_SEQUENCE_STYLE // The block sequence style. - yaml_FLOW_SEQUENCE_STYLE // The flow sequence style. -) - -type yaml_mapping_style_t yaml_style_t - -// Mapping styles. -const ( - // Let the emitter choose the style. - yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota - - yaml_BLOCK_MAPPING_STYLE // The block mapping style. - yaml_FLOW_MAPPING_STYLE // The flow mapping style. -) - -// Tokens - -type yaml_token_type_t int - -// Token types. -const ( - // An empty token. - yaml_NO_TOKEN yaml_token_type_t = iota - - yaml_STREAM_START_TOKEN // A STREAM-START token. - yaml_STREAM_END_TOKEN // A STREAM-END token. - - yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token. - yaml_TAG_DIRECTIVE_TOKEN // A TAG-DIRECTIVE token. - yaml_DOCUMENT_START_TOKEN // A DOCUMENT-START token. - yaml_DOCUMENT_END_TOKEN // A DOCUMENT-END token. - - yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token. - yaml_BLOCK_MAPPING_START_TOKEN // A BLOCK-SEQUENCE-END token. - yaml_BLOCK_END_TOKEN // A BLOCK-END token. - - yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token. - yaml_FLOW_SEQUENCE_END_TOKEN // A FLOW-SEQUENCE-END token. - yaml_FLOW_MAPPING_START_TOKEN // A FLOW-MAPPING-START token. - yaml_FLOW_MAPPING_END_TOKEN // A FLOW-MAPPING-END token. - - yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token. - yaml_FLOW_ENTRY_TOKEN // A FLOW-ENTRY token. - yaml_KEY_TOKEN // A KEY token. - yaml_VALUE_TOKEN // A VALUE token. - - yaml_ALIAS_TOKEN // An ALIAS token. - yaml_ANCHOR_TOKEN // An ANCHOR token. - yaml_TAG_TOKEN // A TAG token. - yaml_SCALAR_TOKEN // A SCALAR token. -) - -func (tt yaml_token_type_t) String() string { - switch tt { - case yaml_NO_TOKEN: - return "yaml_NO_TOKEN" - case yaml_STREAM_START_TOKEN: - return "yaml_STREAM_START_TOKEN" - case yaml_STREAM_END_TOKEN: - return "yaml_STREAM_END_TOKEN" - case yaml_VERSION_DIRECTIVE_TOKEN: - return "yaml_VERSION_DIRECTIVE_TOKEN" - case yaml_TAG_DIRECTIVE_TOKEN: - return "yaml_TAG_DIRECTIVE_TOKEN" - case yaml_DOCUMENT_START_TOKEN: - return "yaml_DOCUMENT_START_TOKEN" - case yaml_DOCUMENT_END_TOKEN: - return "yaml_DOCUMENT_END_TOKEN" - case yaml_BLOCK_SEQUENCE_START_TOKEN: - return "yaml_BLOCK_SEQUENCE_START_TOKEN" - case yaml_BLOCK_MAPPING_START_TOKEN: - return "yaml_BLOCK_MAPPING_START_TOKEN" - case yaml_BLOCK_END_TOKEN: - return "yaml_BLOCK_END_TOKEN" - case yaml_FLOW_SEQUENCE_START_TOKEN: - return "yaml_FLOW_SEQUENCE_START_TOKEN" - case yaml_FLOW_SEQUENCE_END_TOKEN: - return "yaml_FLOW_SEQUENCE_END_TOKEN" - case yaml_FLOW_MAPPING_START_TOKEN: - return "yaml_FLOW_MAPPING_START_TOKEN" - case yaml_FLOW_MAPPING_END_TOKEN: - return "yaml_FLOW_MAPPING_END_TOKEN" - case yaml_BLOCK_ENTRY_TOKEN: - return "yaml_BLOCK_ENTRY_TOKEN" - case yaml_FLOW_ENTRY_TOKEN: - return "yaml_FLOW_ENTRY_TOKEN" - case yaml_KEY_TOKEN: - return "yaml_KEY_TOKEN" - case yaml_VALUE_TOKEN: - return "yaml_VALUE_TOKEN" - case yaml_ALIAS_TOKEN: - return "yaml_ALIAS_TOKEN" - case yaml_ANCHOR_TOKEN: - return "yaml_ANCHOR_TOKEN" - case yaml_TAG_TOKEN: - return "yaml_TAG_TOKEN" - case yaml_SCALAR_TOKEN: - return "yaml_SCALAR_TOKEN" - } - return "" -} - -// The token structure. -type yaml_token_t struct { - // The token type. - typ yaml_token_type_t - - // The start/end of the token. - start_mark, end_mark yaml_mark_t - - // The stream encoding (for yaml_STREAM_START_TOKEN). - encoding yaml_encoding_t - - // The alias/anchor/scalar value or tag/tag directive handle - // (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN). - value []byte - - // The tag suffix (for yaml_TAG_TOKEN). - suffix []byte - - // The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN). - prefix []byte - - // The scalar style (for yaml_SCALAR_TOKEN). - style yaml_scalar_style_t - - // The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN). - major, minor int8 -} - -// Events - -type yaml_event_type_t int8 - -// Event types. -const ( - // An empty event. - yaml_NO_EVENT yaml_event_type_t = iota - - yaml_STREAM_START_EVENT // A STREAM-START event. - yaml_STREAM_END_EVENT // A STREAM-END event. - yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event. - yaml_DOCUMENT_END_EVENT // A DOCUMENT-END event. - yaml_ALIAS_EVENT // An ALIAS event. - yaml_SCALAR_EVENT // A SCALAR event. - yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event. - yaml_SEQUENCE_END_EVENT // A SEQUENCE-END event. - yaml_MAPPING_START_EVENT // A MAPPING-START event. - yaml_MAPPING_END_EVENT // A MAPPING-END event. -) - -var eventStrings = []string{ - yaml_NO_EVENT: "none", - yaml_STREAM_START_EVENT: "stream start", - yaml_STREAM_END_EVENT: "stream end", - yaml_DOCUMENT_START_EVENT: "document start", - yaml_DOCUMENT_END_EVENT: "document end", - yaml_ALIAS_EVENT: "alias", - yaml_SCALAR_EVENT: "scalar", - yaml_SEQUENCE_START_EVENT: "sequence start", - yaml_SEQUENCE_END_EVENT: "sequence end", - yaml_MAPPING_START_EVENT: "mapping start", - yaml_MAPPING_END_EVENT: "mapping end", -} - -func (e yaml_event_type_t) String() string { - if e < 0 || int(e) >= len(eventStrings) { - return fmt.Sprintf("unknown event %d", e) - } - return eventStrings[e] -} - -// The event structure. -type yaml_event_t struct { - - // The event type. - typ yaml_event_type_t - - // The start and end of the event. - start_mark, end_mark yaml_mark_t - - // The document encoding (for yaml_STREAM_START_EVENT). - encoding yaml_encoding_t - - // The version directive (for yaml_DOCUMENT_START_EVENT). - version_directive *yaml_version_directive_t - - // The list of tag directives (for yaml_DOCUMENT_START_EVENT). - tag_directives []yaml_tag_directive_t - - // The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT). - anchor []byte - - // The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). - tag []byte - - // The scalar value (for yaml_SCALAR_EVENT). - value []byte - - // Is the document start/end indicator implicit, or the tag optional? - // (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT). - implicit bool - - // Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT). - quoted_implicit bool - - // The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). - style yaml_style_t -} - -func (e *yaml_event_t) scalar_style() yaml_scalar_style_t { return yaml_scalar_style_t(e.style) } -func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) } -func (e *yaml_event_t) mapping_style() yaml_mapping_style_t { return yaml_mapping_style_t(e.style) } - -// Nodes - -const ( - yaml_NULL_TAG = "tag:yaml.org,2002:null" // The tag !!null with the only possible value: null. - yaml_BOOL_TAG = "tag:yaml.org,2002:bool" // The tag !!bool with the values: true and false. - yaml_STR_TAG = "tag:yaml.org,2002:str" // The tag !!str for string values. - yaml_INT_TAG = "tag:yaml.org,2002:int" // The tag !!int for integer values. - yaml_FLOAT_TAG = "tag:yaml.org,2002:float" // The tag !!float for float values. - yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values. - - yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences. - yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping. - - // Not in original libyaml. - yaml_BINARY_TAG = "tag:yaml.org,2002:binary" - yaml_MERGE_TAG = "tag:yaml.org,2002:merge" - - yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG // The default scalar tag is !!str. - yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq. - yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG // The default mapping tag is !!map. -) - -type yaml_node_type_t int - -// Node types. -const ( - // An empty node. - yaml_NO_NODE yaml_node_type_t = iota - - yaml_SCALAR_NODE // A scalar node. - yaml_SEQUENCE_NODE // A sequence node. - yaml_MAPPING_NODE // A mapping node. -) - -// An element of a sequence node. -type yaml_node_item_t int - -// An element of a mapping node. -type yaml_node_pair_t struct { - key int // The key of the element. - value int // The value of the element. -} - -// The node structure. -type yaml_node_t struct { - typ yaml_node_type_t // The node type. - tag []byte // The node tag. - - // The node data. - - // The scalar parameters (for yaml_SCALAR_NODE). - scalar struct { - value []byte // The scalar value. - length int // The length of the scalar value. - style yaml_scalar_style_t // The scalar style. - } - - // The sequence parameters (for YAML_SEQUENCE_NODE). - sequence struct { - items_data []yaml_node_item_t // The stack of sequence items. - style yaml_sequence_style_t // The sequence style. - } - - // The mapping parameters (for yaml_MAPPING_NODE). - mapping struct { - pairs_data []yaml_node_pair_t // The stack of mapping pairs (key, value). - pairs_start *yaml_node_pair_t // The beginning of the stack. - pairs_end *yaml_node_pair_t // The end of the stack. - pairs_top *yaml_node_pair_t // The top of the stack. - style yaml_mapping_style_t // The mapping style. - } - - start_mark yaml_mark_t // The beginning of the node. - end_mark yaml_mark_t // The end of the node. - -} - -// The document structure. -type yaml_document_t struct { - - // The document nodes. - nodes []yaml_node_t - - // The version directive. - version_directive *yaml_version_directive_t - - // The list of tag directives. - tag_directives_data []yaml_tag_directive_t - tag_directives_start int // The beginning of the tag directives list. - tag_directives_end int // The end of the tag directives list. - - start_implicit int // Is the document start indicator implicit? - end_implicit int // Is the document end indicator implicit? - - // The start/end of the document. - start_mark, end_mark yaml_mark_t -} - -// The prototype of a read handler. -// -// The read handler is called when the parser needs to read more bytes from the -// source. The handler should write not more than size bytes to the buffer. -// The number of written bytes should be set to the size_read variable. -// -// [in,out] data A pointer to an application data specified by -// yaml_parser_set_input(). -// [out] buffer The buffer to write the data from the source. -// [in] size The size of the buffer. -// [out] size_read The actual number of bytes read from the source. -// -// On success, the handler should return 1. If the handler failed, -// the returned value should be 0. On EOF, the handler should set the -// size_read to 0 and return 1. -type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error) - -// This structure holds information about a potential simple key. -type yaml_simple_key_t struct { - possible bool // Is a simple key possible? - required bool // Is a simple key required? - token_number int // The number of the token. - mark yaml_mark_t // The position mark. -} - -// The states of the parser. -type yaml_parser_state_t int - -const ( - yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota - - yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE // Expect the beginning of an implicit document. - yaml_PARSE_DOCUMENT_START_STATE // Expect DOCUMENT-START. - yaml_PARSE_DOCUMENT_CONTENT_STATE // Expect the content of a document. - yaml_PARSE_DOCUMENT_END_STATE // Expect DOCUMENT-END. - yaml_PARSE_BLOCK_NODE_STATE // Expect a block node. - yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence. - yaml_PARSE_FLOW_NODE_STATE // Expect a flow node. - yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a block sequence. - yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE // Expect an entry of a block sequence. - yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE // Expect an entry of an indentless sequence. - yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. - yaml_PARSE_BLOCK_MAPPING_KEY_STATE // Expect a block mapping key. - yaml_PARSE_BLOCK_MAPPING_VALUE_STATE // Expect a block mapping value. - yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a flow sequence. - yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE // Expect an entry of a flow sequence. - yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE // Expect a key of an ordered mapping. - yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping. - yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE // Expect the and of an ordered mapping entry. - yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. - yaml_PARSE_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. - yaml_PARSE_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. - yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE // Expect an empty value of a flow mapping. - yaml_PARSE_END_STATE // Expect nothing. -) - -func (ps yaml_parser_state_t) String() string { - switch ps { - case yaml_PARSE_STREAM_START_STATE: - return "yaml_PARSE_STREAM_START_STATE" - case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: - return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE" - case yaml_PARSE_DOCUMENT_START_STATE: - return "yaml_PARSE_DOCUMENT_START_STATE" - case yaml_PARSE_DOCUMENT_CONTENT_STATE: - return "yaml_PARSE_DOCUMENT_CONTENT_STATE" - case yaml_PARSE_DOCUMENT_END_STATE: - return "yaml_PARSE_DOCUMENT_END_STATE" - case yaml_PARSE_BLOCK_NODE_STATE: - return "yaml_PARSE_BLOCK_NODE_STATE" - case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: - return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE" - case yaml_PARSE_FLOW_NODE_STATE: - return "yaml_PARSE_FLOW_NODE_STATE" - case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: - return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE" - case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: - return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE" - case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: - return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE" - case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: - return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE" - case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: - return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE" - case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: - return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE" - case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE" - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE" - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE" - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE" - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE" - case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: - return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE" - case yaml_PARSE_FLOW_MAPPING_KEY_STATE: - return "yaml_PARSE_FLOW_MAPPING_KEY_STATE" - case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: - return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE" - case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: - return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE" - case yaml_PARSE_END_STATE: - return "yaml_PARSE_END_STATE" - } - return "" -} - -// This structure holds aliases data. -type yaml_alias_data_t struct { - anchor []byte // The anchor. - index int // The node id. - mark yaml_mark_t // The anchor mark. -} - -// The parser structure. -// -// All members are internal. Manage the structure using the -// yaml_parser_ family of functions. -type yaml_parser_t struct { - - // Error handling - - error yaml_error_type_t // Error type. - - problem string // Error description. - - // The byte about which the problem occurred. - problem_offset int - problem_value int - problem_mark yaml_mark_t - - // The error context. - context string - context_mark yaml_mark_t - - // Reader stuff - - read_handler yaml_read_handler_t // Read handler. - - input_reader io.Reader // File input data. - input []byte // String input data. - input_pos int - - eof bool // EOF flag - - buffer []byte // The working buffer. - buffer_pos int // The current position of the buffer. - - unread int // The number of unread characters in the buffer. - - raw_buffer []byte // The raw buffer. - raw_buffer_pos int // The current position of the buffer. - - encoding yaml_encoding_t // The input encoding. - - offset int // The offset of the current position (in bytes). - mark yaml_mark_t // The mark of the current position. - - // Scanner stuff - - stream_start_produced bool // Have we started to scan the input stream? - stream_end_produced bool // Have we reached the end of the input stream? - - flow_level int // The number of unclosed '[' and '{' indicators. - - tokens []yaml_token_t // The tokens queue. - tokens_head int // The head of the tokens queue. - tokens_parsed int // The number of tokens fetched from the queue. - token_available bool // Does the tokens queue contain a token ready for dequeueing. - - indent int // The current indentation level. - indents []int // The indentation levels stack. - - simple_key_allowed bool // May a simple key occur at the current position? - simple_keys []yaml_simple_key_t // The stack of simple keys. - - // Parser stuff - - state yaml_parser_state_t // The current parser state. - states []yaml_parser_state_t // The parser states stack. - marks []yaml_mark_t // The stack of marks. - tag_directives []yaml_tag_directive_t // The list of TAG directives. - - // Dumper stuff - - aliases []yaml_alias_data_t // The alias data. - - document *yaml_document_t // The currently parsed document. -} - -// Emitter Definitions - -// The prototype of a write handler. -// -// The write handler is called when the emitter needs to flush the accumulated -// characters to the output. The handler should write @a size bytes of the -// @a buffer to the output. -// -// @param[in,out] data A pointer to an application data specified by -// yaml_emitter_set_output(). -// @param[in] buffer The buffer with bytes to be written. -// @param[in] size The size of the buffer. -// -// @returns On success, the handler should return @c 1. If the handler failed, -// the returned value should be @c 0. -// -type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error - -type yaml_emitter_state_t int - -// The emitter states. -const ( - // Expect STREAM-START. - yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota - - yaml_EMIT_FIRST_DOCUMENT_START_STATE // Expect the first DOCUMENT-START or STREAM-END. - yaml_EMIT_DOCUMENT_START_STATE // Expect DOCUMENT-START or STREAM-END. - yaml_EMIT_DOCUMENT_CONTENT_STATE // Expect the content of a document. - yaml_EMIT_DOCUMENT_END_STATE // Expect DOCUMENT-END. - yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a flow sequence. - yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE // Expect an item of a flow sequence. - yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. - yaml_EMIT_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. - yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a flow mapping. - yaml_EMIT_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. - yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a block sequence. - yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE // Expect an item of a block sequence. - yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. - yaml_EMIT_BLOCK_MAPPING_KEY_STATE // Expect the key of a block mapping. - yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping. - yaml_EMIT_BLOCK_MAPPING_VALUE_STATE // Expect a value of a block mapping. - yaml_EMIT_END_STATE // Expect nothing. -) - -// The emitter structure. -// -// All members are internal. Manage the structure using the @c yaml_emitter_ -// family of functions. -type yaml_emitter_t struct { - - // Error handling - - error yaml_error_type_t // Error type. - problem string // Error description. - - // Writer stuff - - write_handler yaml_write_handler_t // Write handler. - - output_buffer *[]byte // String output data. - output_writer io.Writer // File output data. - - buffer []byte // The working buffer. - buffer_pos int // The current position of the buffer. - - raw_buffer []byte // The raw buffer. - raw_buffer_pos int // The current position of the buffer. - - encoding yaml_encoding_t // The stream encoding. - - // Emitter stuff - - canonical bool // If the output is in the canonical style? - best_indent int // The number of indentation spaces. - best_width int // The preferred width of the output lines. - unicode bool // Allow unescaped non-ASCII characters? - line_break yaml_break_t // The preferred line break. - - state yaml_emitter_state_t // The current emitter state. - states []yaml_emitter_state_t // The stack of states. - - events []yaml_event_t // The event queue. - events_head int // The head of the event queue. - - indents []int // The stack of indentation levels. - - tag_directives []yaml_tag_directive_t // The list of tag directives. - - indent int // The current indentation level. - - flow_level int // The current flow level. - - root_context bool // Is it the document root context? - sequence_context bool // Is it a sequence context? - mapping_context bool // Is it a mapping context? - simple_key_context bool // Is it a simple mapping key context? - - line int // The current line. - column int // The current column. - whitespace bool // If the last character was a whitespace? - indention bool // If the last character was an indentation character (' ', '-', '?', ':')? - open_ended bool // If an explicit document end is required? - - // Anchor analysis. - anchor_data struct { - anchor []byte // The anchor value. - alias bool // Is it an alias? - } - - // Tag analysis. - tag_data struct { - handle []byte // The tag handle. - suffix []byte // The tag suffix. - } - - // Scalar analysis. - scalar_data struct { - value []byte // The scalar value. - multiline bool // Does the scalar contain line breaks? - flow_plain_allowed bool // Can the scalar be expessed in the flow plain style? - block_plain_allowed bool // Can the scalar be expressed in the block plain style? - single_quoted_allowed bool // Can the scalar be expressed in the single quoted style? - block_allowed bool // Can the scalar be expressed in the literal or folded styles? - style yaml_scalar_style_t // The output style. - } - - // Dumper stuff - - opened bool // If the stream was already opened? - closed bool // If the stream was already closed? - - // The information associated with the document nodes. - anchors *struct { - references int // The number of references. - anchor int // The anchor id. - serialized bool // If the node has been emitted? - } - - last_anchor_id int // The last assigned anchor id. - - document *yaml_document_t // The currently emitted document. -} diff --git a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/yamlprivateh.go b/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/yamlprivateh.go deleted file mode 100755 index 8110ce3..0000000 --- a/vender/github.com/astaxie/beego/vendor/gopkg.in/yaml.v2/yamlprivateh.go +++ /dev/null @@ -1,173 +0,0 @@ -package yaml - -const ( - // The size of the input raw buffer. - input_raw_buffer_size = 512 - - // The size of the input buffer. - // It should be possible to decode the whole raw buffer. - input_buffer_size = input_raw_buffer_size * 3 - - // The size of the output buffer. - output_buffer_size = 128 - - // The size of the output raw buffer. - // It should be possible to encode the whole output buffer. - output_raw_buffer_size = (output_buffer_size*2 + 2) - - // The size of other stacks and queues. - initial_stack_size = 16 - initial_queue_size = 16 - initial_string_size = 16 -) - -// Check if the character at the specified position is an alphabetical -// character, a digit, '_', or '-'. -func is_alpha(b []byte, i int) bool { - return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-' -} - -// Check if the character at the specified position is a digit. -func is_digit(b []byte, i int) bool { - return b[i] >= '0' && b[i] <= '9' -} - -// Get the value of a digit. -func as_digit(b []byte, i int) int { - return int(b[i]) - '0' -} - -// Check if the character at the specified position is a hex-digit. -func is_hex(b []byte, i int) bool { - return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f' -} - -// Get the value of a hex-digit. -func as_hex(b []byte, i int) int { - bi := b[i] - if bi >= 'A' && bi <= 'F' { - return int(bi) - 'A' + 10 - } - if bi >= 'a' && bi <= 'f' { - return int(bi) - 'a' + 10 - } - return int(bi) - '0' -} - -// Check if the character is ASCII. -func is_ascii(b []byte, i int) bool { - return b[i] <= 0x7F -} - -// Check if the character at the start of the buffer can be printed unescaped. -func is_printable(b []byte, i int) bool { - return ((b[i] == 0x0A) || // . == #x0A - (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E - (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF - (b[i] > 0xC2 && b[i] < 0xED) || - (b[i] == 0xED && b[i+1] < 0xA0) || - (b[i] == 0xEE) || - (b[i] == 0xEF && // #xE000 <= . <= #xFFFD - !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF - !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF)))) -} - -// Check if the character at the specified position is NUL. -func is_z(b []byte, i int) bool { - return b[i] == 0x00 -} - -// Check if the beginning of the buffer is a BOM. -func is_bom(b []byte, i int) bool { - return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF -} - -// Check if the character at the specified position is space. -func is_space(b []byte, i int) bool { - return b[i] == ' ' -} - -// Check if the character at the specified position is tab. -func is_tab(b []byte, i int) bool { - return b[i] == '\t' -} - -// Check if the character at the specified position is blank (space or tab). -func is_blank(b []byte, i int) bool { - //return is_space(b, i) || is_tab(b, i) - return b[i] == ' ' || b[i] == '\t' -} - -// Check if the character at the specified position is a line break. -func is_break(b []byte, i int) bool { - return (b[i] == '\r' || // CR (#xD) - b[i] == '\n' || // LF (#xA) - b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029) -} - -func is_crlf(b []byte, i int) bool { - return b[i] == '\r' && b[i+1] == '\n' -} - -// Check if the character is a line break or NUL. -func is_breakz(b []byte, i int) bool { - //return is_break(b, i) || is_z(b, i) - return ( // is_break: - b[i] == '\r' || // CR (#xD) - b[i] == '\n' || // LF (#xA) - b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) - // is_z: - b[i] == 0) -} - -// Check if the character is a line break, space, or NUL. -func is_spacez(b []byte, i int) bool { - //return is_space(b, i) || is_breakz(b, i) - return ( // is_space: - b[i] == ' ' || - // is_breakz: - b[i] == '\r' || // CR (#xD) - b[i] == '\n' || // LF (#xA) - b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) - b[i] == 0) -} - -// Check if the character is a line break, space, tab, or NUL. -func is_blankz(b []byte, i int) bool { - //return is_blank(b, i) || is_breakz(b, i) - return ( // is_blank: - b[i] == ' ' || b[i] == '\t' || - // is_breakz: - b[i] == '\r' || // CR (#xD) - b[i] == '\n' || // LF (#xA) - b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) - b[i] == 0) -} - -// Determine the width of the character. -func width(b byte) int { - // Don't replace these by a switch without first - // confirming that it is being inlined. - if b&0x80 == 0x00 { - return 1 - } - if b&0xE0 == 0xC0 { - return 2 - } - if b&0xF0 == 0xE0 { - return 3 - } - if b&0xF8 == 0xF0 { - return 4 - } - return 0 - -} diff --git a/vender/github.com/astaxie/beego/vendor/vendor.json b/vender/github.com/astaxie/beego/vendor/vendor.json deleted file mode 100755 index e549f65..0000000 --- a/vender/github.com/astaxie/beego/vendor/vendor.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "comment": "", - "ignore": "test", - "package": [ - { - "checksumSHA1": "J6lNRPdrYhKft6S8x33K9brxyhE=", - "path": "golang.org/x/crypto/acme", - "revision": "c126467f60eb25f8f27e5a981f32a87e3965053f", - "revisionTime": "2018-07-23T15:26:11Z" - }, - { - "checksumSHA1": "EFjIi/zCZ1Cte0MQtyxGCTgSzk8=", - "path": "golang.org/x/crypto/acme/autocert", - "revision": "c126467f60eb25f8f27e5a981f32a87e3965053f", - "revisionTime": "2018-07-23T15:26:11Z" - }, - { - "checksumSHA1": "1MGpGDQqnUoRpv7VEcQrXOBydXE=", - "path": "golang.org/x/crypto/pbkdf2", - "revision": "c126467f60eb25f8f27e5a981f32a87e3965053f", - "revisionTime": "2018-07-23T15:26:11Z" - }, - { - "checksumSHA1": "dr5+PfIRzXeN+l1VG+s0lea9qz8=", - "path": "golang.org/x/net/context", - "revision": "b60f3a92103dfd93dfcb900ec77c6d0643510868", - "revisionTime": "2017-09-18T06:10:02Z" - }, - { - "checksumSHA1": "LiyXfqOzaeQ8vgYZH3t2hUEdVTw=", - "path": "google.golang.org/appengine/cloudsql", - "revision": "b1f26356af11148e710935ed1ac8a7f5702c7612", - "revisionTime": "2018-05-21T22:34:13Z" - }, - { - "checksumSHA1": "ZSWoOPUNRr5+3dhkLK3C4cZAQPk=", - "path": "gopkg.in/yaml.v2", - "revision": "5420a8b6744d3b0345ab293f6fcba19c978f1183", - "revisionTime": "2018-03-28T19:50:20Z" - } - ], - "rootPath": "github.com/astaxie/beego" -} diff --git a/vender/github.com/ccding/go-stun/.gitignore b/vender/github.com/ccding/go-stun/.gitignore deleted file mode 100755 index a1b4a2e..0000000 --- a/vender/github.com/ccding/go-stun/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -# Temporary files for running example -go-stun - -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe diff --git a/vender/github.com/ccding/go-stun/LICENSE b/vender/github.com/ccding/go-stun/LICENSE deleted file mode 100755 index 37ec93a..0000000 --- a/vender/github.com/ccding/go-stun/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such -Derivative Works in Source or Object form. - -3. Grant of Patent License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where -such license applies only to those patent claims licensable by such Contributor -that are necessarily infringed by their Contribution(s) alone or by combination -of their Contribution(s) with the Work to which such Contribution(s) was -submitted. If You institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work or a -Contribution incorporated within the Work constitutes direct or contributory -patent infringement, then any patent licenses granted to You under this License -for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. - -You may reproduce and distribute copies of the Work or Derivative Works thereof -in any medium, with or without modifications, and in Source or Object form, -provided that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of -this License; and -You must cause any modified files to carry prominent notices stating that You -changed the files; and -You must retain, in the Source form of any Derivative Works that You distribute, -all copyright, patent, trademark, and attribution notices from the Source form -of the Work, excluding those notices that do not pertain to any part of the -Derivative Works; and -If the Work includes a "NOTICE" text file as part of its distribution, then any -Derivative Works that You distribute must include a readable copy of the -attribution notices contained within such NOTICE file, excluding those notices -that do not pertain to any part of the Derivative Works, in at least one of the -following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. - -Unless You explicitly state otherwise, any Contribution intentionally submitted -for inclusion in the Work by You to the Licensor shall be under the terms and -conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of -any separate license agreement you may have executed with Licensor regarding -such Contributions. - -6. Trademarks. - -This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for -reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. - -Unless required by applicable law or agreed to in writing, Licensor provides the -Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, -including, without limitation, any warranties or conditions of TITLE, -NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are -solely responsible for determining the appropriateness of using or -redistributing the Work and assume any risks associated with Your exercise of -permissions under this License. - -8. Limitation of Liability. - -In no event and under no legal theory, whether in tort (including negligence), -contract, or otherwise, unless required by applicable law (such as deliberate -and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, -or consequential damages of any character arising as a result of this License or -out of the use or inability to use the Work (including but not limited to -damages for loss of goodwill, work stoppage, computer failure or malfunction, or -any and all other commercial damages or losses), even if such Contributor has -been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. - -While redistributing the Work or Derivative Works thereof, You may choose to -offer, and charge a fee for, acceptance of support, warranty, indemnity, or -other liability obligations and/or rights consistent with this License. However, -in accepting such obligations, You may act only on Your own behalf and on Your -sole responsibility, not on behalf of any other Contributor, and only if You -agree to indemnify, defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason of your -accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/vender/github.com/ccding/go-stun/linter_config.json b/vender/github.com/ccding/go-stun/linter_config.json deleted file mode 100755 index 3f88246..0000000 --- a/vender/github.com/ccding/go-stun/linter_config.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "Vendor": true, - "DisableAll": true, - "Enable": [ - "vet", - "safesql", - "errcheck", - "goconst", - "goimports", - "varcheck", - "gas", - "staticcheck", - "gosimple", - "lll", - "unconvert", - "misspell", - "unconvert" - ], - "Aggregate": true, - "WarnUnmatchedNolint": true, - "LineLength": 240, - "Exclude": [ - "stun/const.go" - ], - "Deadline": "300s", - "Skip": [] -} diff --git a/vender/github.com/ccding/go-stun/main.go b/vender/github.com/ccding/go-stun/main.go deleted file mode 100755 index 925f7d2..0000000 --- a/vender/github.com/ccding/go-stun/main.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2013, Cong Ding. 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. -// -// author: Cong Ding - -package main - -import ( - "flag" - "fmt" - - "github.com/ccding/go-stun/stun" -) - -func main() { - var serverAddr = flag.String("s", stun.DefaultServerAddr, "STUN server address") - var v = flag.Bool("v", false, "verbose mode") - var vv = flag.Bool("vv", false, "double verbose mode (includes -v)") - var vvv = flag.Bool("vvv", false, "triple verbose mode (includes -v and -vv)") - flag.Parse() - - // Creates a STUN client. NewClientWithConnection can also be used if - // you want to handle the UDP listener by yourself. - client := stun.NewClient() - // The default addr (stun.DefaultServerAddr) will be used unless we - // call SetServerAddr. - client.SetServerAddr(*serverAddr) - // Non verbose mode will be used by default unless we call - // SetVerbose(true) or SetVVerbose(true). - client.SetVerbose(*v || *vv || *vvv) - client.SetVVerbose(*vv || *vvv) - // Discover the NAT and return the result. - nat, host, err := client.Discover() - if err != nil { - fmt.Println(err) - return - } - - fmt.Println("NAT Type:", nat) - if host != nil { - fmt.Println("External IP Family:", host.Family()) - fmt.Println("External IP:", host.IP()) - fmt.Println("External Port:", host.Port()) - } -} diff --git a/vender/github.com/ccding/go-stun/stun/attribute.go b/vender/github.com/ccding/go-stun/stun/attribute.go deleted file mode 100755 index 61732a9..0000000 --- a/vender/github.com/ccding/go-stun/stun/attribute.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2013, Cong Ding. 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. -// -// Author: Cong Ding - -package stun - -import ( - "encoding/binary" - "hash/crc32" - "net" -) - -type attribute struct { - types uint16 - length uint16 - value []byte -} - -func newAttribute(types uint16, value []byte) *attribute { - att := new(attribute) - att.types = types - att.value = padding(value) - att.length = uint16(len(att.value)) - return att -} - -func newFingerprintAttribute(packet *packet) *attribute { - crc := crc32.ChecksumIEEE(packet.bytes()) ^ fingerprint - buf := make([]byte, 4) - binary.BigEndian.PutUint32(buf, crc) - return newAttribute(attributeFingerprint, buf) -} - -func newSoftwareAttribute(name string) *attribute { - return newAttribute(attributeSoftware, []byte(name)) -} - -func newChangeReqAttribute(changeIP bool, changePort bool) *attribute { - value := make([]byte, 4) - if changeIP { - value[3] |= 0x04 - } - if changePort { - value[3] |= 0x02 - } - return newAttribute(attributeChangeRequest, value) -} - -// 0 1 2 3 -// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// |x x x x x x x x| Family | X-Port | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | X-Address (Variable) -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// -// Figure 6: Format of XOR-MAPPED-ADDRESS Attribute -func (v *attribute) xorAddr(transID []byte) *Host { - xorIP := make([]byte, 16) - for i := 0; i < len(v.value)-4; i++ { - xorIP[i] = v.value[i+4] ^ transID[i] - } - family := uint16(v.value[1]) - port := binary.BigEndian.Uint16(v.value[2:4]) - // Truncate if IPv4, otherwise net.IP sometimes renders it as an IPv6 address. - if family == attributeFamilyIPv4 { - xorIP = xorIP[:4] - } - x := binary.BigEndian.Uint16(transID[:2]) - return &Host{family, net.IP(xorIP).String(), port ^ x} -} - -// 0 1 2 3 -// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// |0 0 0 0 0 0 0 0| Family | Port | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | | -// | Address (32 bits or 128 bits) | -// | | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// -// Figure 5: Format of MAPPED-ADDRESS Attribute -func (v *attribute) rawAddr() *Host { - host := new(Host) - host.family = uint16(v.value[1]) - host.port = binary.BigEndian.Uint16(v.value[2:4]) - // Truncate if IPv4, otherwise net.IP sometimes renders it as an IPv6 address. - if host.family == attributeFamilyIPv4 { - v.value = v.value[:8] - } - host.ip = net.IP(v.value[4:]).String() - return host -} diff --git a/vender/github.com/ccding/go-stun/stun/client.go b/vender/github.com/ccding/go-stun/stun/client.go deleted file mode 100755 index 89be704..0000000 --- a/vender/github.com/ccding/go-stun/stun/client.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2013, Cong Ding. 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. -// -// Author: Cong Ding - -package stun - -import ( - "errors" - "net" - "strconv" -) - -// Client is a STUN client, which can be set STUN server address and is used -// to discover NAT type. -type Client struct { - serverAddr string - softwareName string - conn net.PacketConn - logger *Logger -} - -// NewClient returns a client without network connection. The network -// connection will be build when calling Discover function. -func NewClient() *Client { - c := new(Client) - c.SetSoftwareName(DefaultSoftwareName) - c.logger = NewLogger() - return c -} - -// NewClientWithConnection returns a client which uses the given connection. -// Please note the connection should be acquired via net.Listen* method. -func NewClientWithConnection(conn net.PacketConn) *Client { - c := new(Client) - c.conn = conn - c.SetSoftwareName(DefaultSoftwareName) - c.logger = NewLogger() - return c -} - -// SetVerbose sets the client to be in the verbose mode, which prints -// information in the discover process. -func (c *Client) SetVerbose(v bool) { - c.logger.SetDebug(v) -} - -// SetVVerbose sets the client to be in the double verbose mode, which prints -// information and packet in the discover process. -func (c *Client) SetVVerbose(v bool) { - c.logger.SetInfo(v) -} - -// SetServerHost allows user to set the STUN hostname and port. -func (c *Client) SetServerHost(host string, port int) { - c.serverAddr = net.JoinHostPort(host, strconv.Itoa(port)) -} - -// SetServerAddr allows user to set the transport layer STUN server address. -func (c *Client) SetServerAddr(address string) { - c.serverAddr = address -} - -// SetSoftwareName allows user to set the name of the software, which is used -// for logging purpose (NOT used in the current implementation). -func (c *Client) SetSoftwareName(name string) { - c.softwareName = name -} - -// Discover contacts the STUN server and gets the response of NAT type, host -// for UDP punching. -func (c *Client) Discover() (NATType, *Host, error) { - if c.serverAddr == "" { - c.SetServerAddr(DefaultServerAddr) - } - serverUDPAddr, err := net.ResolveUDPAddr("udp", c.serverAddr) - if err != nil { - return NATError, nil, err - } - // Use the connection passed to the client if it is not nil, otherwise - // create a connection and close it at the end. - conn := c.conn - if conn == nil { - conn, err = net.ListenUDP("udp", nil) - if err != nil { - return NATError, nil, err - } - defer conn.Close() - } - return c.discover(conn, serverUDPAddr) -} - -// Keepalive sends and receives a bind request, which ensures the mapping stays open -// Only applicable when client was created with a connection. -func (c *Client) Keepalive() (*Host, error) { - if c.conn == nil { - return nil, errors.New("no connection available") - } - if c.serverAddr == "" { - c.SetServerAddr(DefaultServerAddr) - } - serverUDPAddr, err := net.ResolveUDPAddr("udp", c.serverAddr) - if err != nil { - return nil, err - } - - resp, err := c.test1(c.conn, serverUDPAddr) - if err != nil { - return nil, err - } - if resp == nil || resp.packet == nil { - return nil, errors.New("failed to contact") - } - return resp.mappedAddr, nil -} diff --git a/vender/github.com/ccding/go-stun/stun/const.go b/vender/github.com/ccding/go-stun/stun/const.go deleted file mode 100755 index 3980e8a..0000000 --- a/vender/github.com/ccding/go-stun/stun/const.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2013, Cong Ding. 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. -// -// Author: Cong Ding - -package stun - -// Default server address and client name. -const ( - DefaultServerAddr = "stun.voiparound.com:3478" - DefaultSoftwareName = "StunClient" -) - -const ( - magicCookie = 0x2112A442 - fingerprint = 0x5354554e -) - -// NATType is the type of NAT described by int. -type NATType int - -// NAT types. -const ( - NATError NATType = iota - NATUnknown - NATNone - NATBlocked - NATFull - NATSymmetric - NATRestricted - NATPortRestricted - NATSymmetricUDPFirewall - - // Deprecated spellings of these constants - NATSymetric = NATSymmetric - NATSymetricUDPFirewall = NATSymmetricUDPFirewall -) - -var natStr map[NATType]string - -func init() { - natStr = map[NATType]string{ - NATError: "Test failed", - NATUnknown: "Unexpected response from the STUN server", - NATBlocked: "UDP is blocked", - NATFull: "Full cone NAT", - NATSymmetric: "Symmetric NAT", - NATRestricted: "Restricted NAT", - NATPortRestricted: "Port restricted NAT", - NATNone: "Not behind a NAT", - NATSymmetricUDPFirewall: "Symmetric UDP firewall", - } -} - -func (nat NATType) String() string { - if s, ok := natStr[nat]; ok { - return s - } - return "Unknown" -} - -const ( - errorTryAlternate = 300 - errorBadRequest = 400 - errorUnauthorized = 401 - errorUnassigned402 = 402 - errorForbidden = 403 - errorUnknownAttribute = 420 - errorAllocationMismatch = 437 - errorStaleNonce = 438 - errorUnassigned439 = 439 - errorAddressFamilyNotSupported = 440 - errorWrongCredentials = 441 - errorUnsupportedTransportProtocol = 442 - errorPeerAddressFamilyMismatch = 443 - errorConnectionAlreadyExists = 446 - errorConnectionTimeoutOrFailure = 447 - errorAllocationQuotaReached = 486 - errorRoleConflict = 487 - errorServerError = 500 - errorInsufficientCapacity = 508 -) -const ( - attributeFamilyIPv4 = 0x01 - attributeFamilyIPV6 = 0x02 -) - -const ( - attributeMappedAddress = 0x0001 - attributeResponseAddress = 0x0002 - attributeChangeRequest = 0x0003 - attributeSourceAddress = 0x0004 - attributeChangedAddress = 0x0005 - attributeUsername = 0x0006 - attributePassword = 0x0007 - attributeMessageIntegrity = 0x0008 - attributeErrorCode = 0x0009 - attributeUnknownAttributes = 0x000a - attributeReflectedFrom = 0x000b - attributeChannelNumber = 0x000c - attributeLifetime = 0x000d - attributeBandwidth = 0x0010 - attributeXorPeerAddress = 0x0012 - attributeData = 0x0013 - attributeRealm = 0x0014 - attributeNonce = 0x0015 - attributeXorRelayedAddress = 0x0016 - attributeRequestedAddressFamily = 0x0017 - attributeEvenPort = 0x0018 - attributeRequestedTransport = 0x0019 - attributeDontFragment = 0x001a - attributeXorMappedAddress = 0x0020 - attributeTimerVal = 0x0021 - attributeReservationToken = 0x0022 - attributePriority = 0x0024 - attributeUseCandidate = 0x0025 - attributePadding = 0x0026 - attributeResponsePort = 0x0027 - attributeConnectionID = 0x002a - attributeXorMappedAddressExp = 0x8020 - attributeSoftware = 0x8022 - attributeAlternateServer = 0x8023 - attributeCacheTimeout = 0x8027 - attributeFingerprint = 0x8028 - attributeIceControlled = 0x8029 - attributeIceControlling = 0x802a - attributeResponseOrigin = 0x802b - attributeOtherAddress = 0x802c - attributeEcnCheckStun = 0x802d - attributeCiscoFlowdata = 0xc000 -) - -const ( - typeBindingRequest = 0x0001 - typeBindingResponse = 0x0101 - typeBindingErrorResponse = 0x0111 - typeSharedSecretRequest = 0x0002 - typeSharedSecretResponse = 0x0102 - typeSharedErrorResponse = 0x0112 - typeAllocate = 0x0003 - typeAllocateResponse = 0x0103 - typeAllocateErrorResponse = 0x0113 - typeRefresh = 0x0004 - typeRefreshResponse = 0x0104 - typeRefreshErrorResponse = 0x0114 - typeSend = 0x0006 - typeSendResponse = 0x0106 - typeSendErrorResponse = 0x0116 - typeData = 0x0007 - typeDataResponse = 0x0107 - typeDataErrorResponse = 0x0117 - typeCreatePermisiion = 0x0008 - typeCreatePermisiionResponse = 0x0108 - typeCreatePermisiionErrorResponse = 0x0118 - typeChannelBinding = 0x0009 - typeChannelBindingResponse = 0x0109 - typeChannelBindingErrorResponse = 0x0119 - typeConnect = 0x000a - typeConnectResponse = 0x010a - typeConnectErrorResponse = 0x011a - typeConnectionBind = 0x000b - typeConnectionBindResponse = 0x010b - typeConnectionBindErrorResponse = 0x011b - typeConnectionAttempt = 0x000c - typeConnectionAttemptResponse = 0x010c - typeConnectionAttemptErrorResponse = 0x011c -) diff --git a/vender/github.com/ccding/go-stun/stun/discover.go b/vender/github.com/ccding/go-stun/stun/discover.go deleted file mode 100755 index f60d2c5..0000000 --- a/vender/github.com/ccding/go-stun/stun/discover.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2013, Cong Ding. 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. -// -// Author: Cong Ding - -package stun - -import ( - "errors" - "net" -) - -// Follow RFC 3489 and RFC 5389. -// Figure 2: Flow for type discovery process (from RFC 3489). -// +--------+ -// | Test | -// | I | -// +--------+ -// | -// | -// V -// /\ /\ -// N / \ Y / \ Y +--------+ -// UDP <-------/Resp\--------->/ IP \------------->| Test | -// Blocked \ ? / \Same/ | II | -// \ / \? / +--------+ -// \/ \/ | -// | N | -// | V -// V /\ -// +--------+ Sym. N / \ -// | Test | UDP <---/Resp\ -// | II | Firewall \ ? / -// +--------+ \ / -// | \/ -// V |Y -// /\ /\ | -// Symmetric N / \ +--------+ N / \ V -// NAT <--- / IP \<-----| Test |<--- /Resp\ Open -// \Same/ | I | \ ? / Internet -// \? / +--------+ \ / -// \/ \/ -// |Y |Y -// | | -// | V -// | Full -// | Cone -// V /\ -// +--------+ / \ Y -// | Test |------>/Resp\---->Restricted -// | III | \ ? / -// +--------+ \ / -// \/ -// |N -// | Port -// +------>Restricted -func (c *Client) discover(conn net.PacketConn, addr *net.UDPAddr) (NATType, *Host, error) { - // Perform test1 to check if it is under NAT. - c.logger.Debugln("Do Test1") - c.logger.Debugln("Send To:", addr) - resp, err := c.test1(conn, addr) - if err != nil { - return NATError, nil, err - } - c.logger.Debugln("Received:", resp) - if resp == nil { - return NATBlocked, nil, nil - } - // identical used to check if it is open Internet or not. - identical := resp.identical - // changedAddr is used to perform second time test1 and test3. - changedAddr := resp.changedAddr - // mappedAddr is used as the return value, its IP is used for tests - mappedAddr := resp.mappedAddr - // Make sure IP and port are not changed. - if resp.serverAddr.IP() != addr.IP.String() || - resp.serverAddr.Port() != uint16(addr.Port) { - return NATError, mappedAddr, errors.New("Server error: response IP/port") - } - // if changedAddr is not available, use otherAddr as changedAddr, - // which is updated in RFC 5780 - if changedAddr == nil { - changedAddr = resp.otherAddr - } - // changedAddr shall not be nil - if changedAddr == nil { - return NATError, mappedAddr, errors.New("Server error: no changed address.") - } - // Perform test2 to see if the client can receive packet sent from - // another IP and port. - c.logger.Debugln("Do Test2") - c.logger.Debugln("Send To:", addr) - resp, err = c.test2(conn, addr) - if err != nil { - return NATError, mappedAddr, err - } - c.logger.Debugln("Received:", resp) - // Make sure IP and port are changed. - if resp != nil && - (resp.serverAddr.IP() == addr.IP.String() || - resp.serverAddr.Port() == uint16(addr.Port)) { - return NATError, mappedAddr, errors.New("Server error: response IP/port") - } - if identical { - if resp == nil { - return NATSymmetricUDPFirewall, mappedAddr, nil - } - return NATNone, mappedAddr, nil - } - if resp != nil { - return NATFull, mappedAddr, nil - } - // Perform test1 to another IP and port to see if the NAT use the same - // external IP. - c.logger.Debugln("Do Test1") - c.logger.Debugln("Send To:", changedAddr) - caddr, err := net.ResolveUDPAddr("udp", changedAddr.String()) - if err != nil { - c.logger.Debugf("ResolveUDPAddr error: %v", err) - } - resp, err = c.test1(conn, caddr) - if err != nil { - return NATError, mappedAddr, err - } - c.logger.Debugln("Received:", resp) - if resp == nil { - // It should be NAT_BLOCKED, but will be detected in the first - // step. So this will never happen. - return NATUnknown, mappedAddr, nil - } - // Make sure IP/port is not changed. - if resp.serverAddr.IP() != caddr.IP.String() || - resp.serverAddr.Port() != uint16(caddr.Port) { - return NATError, mappedAddr, errors.New("Server error: response IP/port") - } - if mappedAddr.IP() == resp.mappedAddr.IP() && mappedAddr.Port() == resp.mappedAddr.Port() { - // Perform test3 to see if the client can receive packet sent - // from another port. - c.logger.Debugln("Do Test3") - c.logger.Debugln("Send To:", caddr) - resp, err = c.test3(conn, caddr) - if err != nil { - return NATError, mappedAddr, err - } - c.logger.Debugln("Received:", resp) - if resp == nil { - return NATPortRestricted, mappedAddr, nil - } - // Make sure IP is not changed, and port is changed. - if resp.serverAddr.IP() != caddr.IP.String() || - resp.serverAddr.Port() == uint16(caddr.Port) { - return NATError, mappedAddr, errors.New("Server error: response IP/port") - } - return NATRestricted, mappedAddr, nil - } - return NATSymmetric, mappedAddr, nil -} diff --git a/vender/github.com/ccding/go-stun/stun/doc.go b/vender/github.com/ccding/go-stun/stun/doc.go deleted file mode 100755 index d1c9aba..0000000 --- a/vender/github.com/ccding/go-stun/stun/doc.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2013, Cong Ding. 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. -// -// Author: Cong Ding - -// Package stun is a STUN (RFC 3489 and RFC 5389) client implementation in -// golang. -// -// It is extremely easy to use -- just one line of code. -// -// nat, host, err := stun.NewClient().Discover() -// -// More details please go to `main.go`. -package stun diff --git a/vender/github.com/ccding/go-stun/stun/host.go b/vender/github.com/ccding/go-stun/stun/host.go deleted file mode 100755 index cee1e9d..0000000 --- a/vender/github.com/ccding/go-stun/stun/host.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2013, Cong Ding. 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. -// -// Author: Cong Ding - -package stun - -import ( - "net" - "strconv" -) - -// Host defines the network address including address family, IP address and port. -type Host struct { - family uint16 - ip string - port uint16 -} - -func newHostFromStr(s string) *Host { - udpAddr, err := net.ResolveUDPAddr("udp", s) - if err != nil { - return nil - } - host := new(Host) - if udpAddr.IP.To4() != nil { - host.family = attributeFamilyIPv4 - } else { - host.family = attributeFamilyIPV6 - } - host.ip = udpAddr.IP.String() - host.port = uint16(udpAddr.Port) - return host -} - -// Family returns the family type of a host (IPv4 or IPv6). -func (h *Host) Family() uint16 { - return h.family -} - -// IP returns the internet protocol address of the host. -func (h *Host) IP() string { - return h.ip -} - -// Port returns the port number of the host. -func (h *Host) Port() uint16 { - return h.port -} - -// TransportAddr returns the transport layer address of the host. -func (h *Host) TransportAddr() string { - return net.JoinHostPort(h.ip, strconv.Itoa(int(h.port))) -} - -// String returns the string representation of the host address. -func (h *Host) String() string { - return h.TransportAddr() -} diff --git a/vender/github.com/ccding/go-stun/stun/log.go b/vender/github.com/ccding/go-stun/stun/log.go deleted file mode 100755 index 52f9fd2..0000000 --- a/vender/github.com/ccding/go-stun/stun/log.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2016, Cong Ding. 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. -// -// Author: Cong Ding - -package stun - -import ( - "log" - "os" -) - -// Logger is a simple logger specified for this STUN client. -type Logger struct { - log.Logger - debug bool - info bool -} - -// NewLogger creates a default logger. -func NewLogger() *Logger { - logger := &Logger{*log.New(os.Stdout, "", log.LstdFlags), false, false} - return logger -} - -// SetDebug sets the logger running in debug mode or not. -func (l *Logger) SetDebug(v bool) { - l.debug = v -} - -// SetInfo sets the logger running in info mode or not. -func (l *Logger) SetInfo(v bool) { - l.info = v -} - -// Debug outputs the log in the format of log.Print. -func (l *Logger) Debug(v ...interface{}) { - if l.debug { - l.Print(v...) - } -} - -// Debugf outputs the log in the format of log.Printf. -func (l *Logger) Debugf(format string, v ...interface{}) { - if l.debug { - l.Printf(format, v...) - } -} - -// Debugln outputs the log in the format of log.Println. -func (l *Logger) Debugln(v ...interface{}) { - if l.debug { - l.Println(v...) - } -} - -// Info outputs the log in the format of log.Print. -func (l *Logger) Info(v ...interface{}) { - if l.info { - l.Print(v...) - } -} - -// Infof outputs the log in the format of log.Printf. -func (l *Logger) Infof(format string, v ...interface{}) { - if l.info { - l.Printf(format, v...) - } -} - -// Infoln outputs the log in the format of log.Println. -func (l *Logger) Infoln(v ...interface{}) { - if l.info { - l.Println(v...) - } -} diff --git a/vender/github.com/ccding/go-stun/stun/net.go b/vender/github.com/ccding/go-stun/stun/net.go deleted file mode 100755 index f067f3e..0000000 --- a/vender/github.com/ccding/go-stun/stun/net.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2016, Cong Ding. 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. -// -// Author: Cong Ding - -package stun - -import ( - "bytes" - "encoding/hex" - "errors" - "net" - "time" -) - -const ( - numRetransmit = 9 - defaultTimeout = 100 - maxTimeout = 1600 - maxPacketSize = 1024 -) - -func (c *Client) sendBindingReq(conn net.PacketConn, addr net.Addr, changeIP bool, changePort bool) (*response, error) { - // Construct packet. - pkt, err := newPacket() - if err != nil { - return nil, err - } - pkt.types = typeBindingRequest - attribute := newSoftwareAttribute(c.softwareName) - pkt.addAttribute(*attribute) - if changeIP || changePort { - attribute = newChangeReqAttribute(changeIP, changePort) - pkt.addAttribute(*attribute) - } - // length of fingerprint attribute must be included into crc, - // so we add it before calculating crc, then subtract it after calculating crc. - pkt.length += 8 - attribute = newFingerprintAttribute(pkt) - pkt.length -= 8 - pkt.addAttribute(*attribute) - // Send packet. - return c.send(pkt, conn, addr) -} - -// RFC 3489: Clients SHOULD retransmit the request starting with an interval -// of 100ms, doubling every retransmit until the interval reaches 1.6s. -// Retransmissions continue with intervals of 1.6s until a response is -// received, or a total of 9 requests have been sent. -func (c *Client) send(pkt *packet, conn net.PacketConn, addr net.Addr) (*response, error) { - c.logger.Info("\n" + hex.Dump(pkt.bytes())) - timeout := defaultTimeout - packetBytes := make([]byte, maxPacketSize) - for i := 0; i < numRetransmit; i++ { - // Send packet to the server. - length, err := conn.WriteTo(pkt.bytes(), addr) - if err != nil { - return nil, err - } - if length != len(pkt.bytes()) { - return nil, errors.New("Error in sending data.") - } - err = conn.SetReadDeadline(time.Now().Add(time.Duration(timeout) * time.Millisecond)) - if err != nil { - return nil, err - } - if timeout < maxTimeout { - timeout *= 2 - } - for { - // Read from the port. - length, raddr, err := conn.ReadFrom(packetBytes) - if err != nil { - if nerr, ok := err.(net.Error); ok && nerr.Timeout() { - break - } - return nil, err - } - p, err := newPacketFromBytes(packetBytes[0:length]) - if err != nil { - return nil, err - } - // If transId mismatches, keep reading until get a - // matched packet or timeout. - if !bytes.Equal(pkt.transID, p.transID) { - continue - } - c.logger.Info("\n" + hex.Dump(packetBytes[0:length])) - resp := newResponse(p, conn) - resp.serverAddr = newHostFromStr(raddr.String()) - return resp, err - } - } - return nil, nil -} diff --git a/vender/github.com/ccding/go-stun/stun/packet.go b/vender/github.com/ccding/go-stun/stun/packet.go deleted file mode 100755 index ca56900..0000000 --- a/vender/github.com/ccding/go-stun/stun/packet.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2013, Cong Ding. 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. -// -// Author: Cong Ding - -package stun - -import ( - "crypto/rand" - "encoding/binary" - "errors" -) - -type packet struct { - types uint16 - length uint16 - transID []byte // 4 bytes magic cookie + 12 bytes transaction id - attributes []attribute -} - -func newPacket() (*packet, error) { - v := new(packet) - v.transID = make([]byte, 16) - binary.BigEndian.PutUint32(v.transID[:4], magicCookie) - _, err := rand.Read(v.transID[4:]) - if err != nil { - return nil, err - } - v.attributes = make([]attribute, 0, 10) - v.length = 0 - return v, nil -} - -func newPacketFromBytes(packetBytes []byte) (*packet, error) { - if len(packetBytes) < 24 { - return nil, errors.New("Received data length too short.") - } - pkt := new(packet) - pkt.types = binary.BigEndian.Uint16(packetBytes[0:2]) - pkt.length = binary.BigEndian.Uint16(packetBytes[2:4]) - pkt.transID = packetBytes[4:20] - pkt.attributes = make([]attribute, 0, 10) - for pos := uint16(20); pos < uint16(len(packetBytes)); { - types := binary.BigEndian.Uint16(packetBytes[pos : pos+2]) - length := binary.BigEndian.Uint16(packetBytes[pos+2 : pos+4]) - if pos+4+length > uint16(len(packetBytes)) { - return nil, errors.New("Received data format mismatch.") - } - value := packetBytes[pos+4 : pos+4+length] - attribute := newAttribute(types, value) - pkt.addAttribute(*attribute) - pos += align(length) + 4 - } - return pkt, nil -} - -func (v *packet) addAttribute(a attribute) { - v.attributes = append(v.attributes, a) - v.length += align(a.length) + 4 -} - -func (v *packet) bytes() []byte { - packetBytes := make([]byte, 4) - binary.BigEndian.PutUint16(packetBytes[0:2], v.types) - binary.BigEndian.PutUint16(packetBytes[2:4], v.length) - packetBytes = append(packetBytes, v.transID...) - for _, a := range v.attributes { - buf := make([]byte, 2) - binary.BigEndian.PutUint16(buf, a.types) - packetBytes = append(packetBytes, buf...) - binary.BigEndian.PutUint16(buf, a.length) - packetBytes = append(packetBytes, buf...) - packetBytes = append(packetBytes, a.value...) - } - return packetBytes -} - -func (v *packet) getSourceAddr() *Host { - return v.getRawAddr(attributeSourceAddress) -} - -func (v *packet) getMappedAddr() *Host { - return v.getRawAddr(attributeMappedAddress) -} - -func (v *packet) getChangedAddr() *Host { - return v.getRawAddr(attributeChangedAddress) -} - -func (v *packet) getOtherAddr() *Host { - return v.getRawAddr(attributeOtherAddress) -} - -func (v *packet) getRawAddr(attribute uint16) *Host { - for _, a := range v.attributes { - if a.types == attribute { - return a.rawAddr() - } - } - return nil -} - -func (v *packet) getXorMappedAddr() *Host { - addr := v.getXorAddr(attributeXorMappedAddress) - if addr == nil { - addr = v.getXorAddr(attributeXorMappedAddressExp) - } - return addr -} - -func (v *packet) getXorAddr(attribute uint16) *Host { - for _, a := range v.attributes { - if a.types == attribute { - return a.xorAddr(v.transID) - } - } - return nil -} diff --git a/vender/github.com/ccding/go-stun/stun/packet_test.go b/vender/github.com/ccding/go-stun/stun/packet_test.go deleted file mode 100755 index a061e8b..0000000 --- a/vender/github.com/ccding/go-stun/stun/packet_test.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2016, Cong Ding. 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. -// -// Author: Cong Ding - -package stun - -import ( - "testing" -) - -func TestNewPacketFromBytes(t *testing.T) { - b := make([]byte, 23) - _, err := newPacketFromBytes(b) - if err == nil { - t.Errorf("newPacketFromBytes error") - } - b = make([]byte, 24) - _, err = newPacketFromBytes(b) - if err != nil { - t.Errorf("newPacketFromBytes error") - } -} - -func TestNewPacket(t *testing.T) { - _, err := newPacket() - if err != nil { - t.Errorf("newPacket error") - } -} - -func TestPacketAll(t *testing.T) { - p, err := newPacket() - if err != nil { - t.Errorf("newPacket error") - } - p.addAttribute(*newChangeReqAttribute(true, true)) - p.addAttribute(*newSoftwareAttribute("aaa")) - p.addAttribute(*newFingerprintAttribute(p)) - pkt, err := newPacketFromBytes(p.bytes()) - if err != nil { - t.Errorf("newPacketFromBytes error") - } - if pkt.types != 0 { - t.Errorf("newPacketFromBytes error") - } - if pkt.length < 24 { - t.Errorf("newPacketFromBytes error") - } -} diff --git a/vender/github.com/ccding/go-stun/stun/response.go b/vender/github.com/ccding/go-stun/stun/response.go deleted file mode 100755 index c9a75cb..0000000 --- a/vender/github.com/ccding/go-stun/stun/response.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2016, Cong Ding. 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. -// -// Author: Cong Ding - -package stun - -import ( - "fmt" - "net" -) - -type response struct { - packet *packet // the original packet from the server - serverAddr *Host // the address received packet - changedAddr *Host // parsed from packet - mappedAddr *Host // parsed from packet, external addr of client NAT - otherAddr *Host // parsed from packet, to replace changedAddr in RFC 5780 - identical bool // if mappedAddr is in local addr list -} - -func newResponse(pkt *packet, conn net.PacketConn) *response { - resp := &response{pkt, nil, nil, nil, nil, false} - if pkt == nil { - return resp - } - // RFC 3489 doesn't require the server return XOR mapped address. - mappedAddr := pkt.getXorMappedAddr() - if mappedAddr == nil { - mappedAddr = pkt.getMappedAddr() - } - resp.mappedAddr = mappedAddr - // compute identical - localAddrStr := conn.LocalAddr().String() - if mappedAddr != nil { - mappedAddrStr := mappedAddr.String() - resp.identical = isLocalAddress(localAddrStr, mappedAddrStr) - } - // compute changedAddr - changedAddr := pkt.getChangedAddr() - if changedAddr != nil { - changedAddrHost := newHostFromStr(changedAddr.String()) - resp.changedAddr = changedAddrHost - } - // compute otherAddr - otherAddr := pkt.getOtherAddr() - if otherAddr != nil { - otherAddrHost := newHostFromStr(otherAddr.String()) - resp.otherAddr = otherAddrHost - } - - return resp -} - -// String is only used for verbose mode output. -func (r *response) String() string { - if r == nil { - return "Nil" - } - return fmt.Sprintf("{packet nil: %v, local: %v, remote: %v, changed: %v, other: %v, identical: %v}", - r.packet == nil, - r.mappedAddr, - r.serverAddr, - r.changedAddr, - r.otherAddr, - r.identical) -} diff --git a/vender/github.com/ccding/go-stun/stun/tests.go b/vender/github.com/ccding/go-stun/stun/tests.go deleted file mode 100755 index 013c803..0000000 --- a/vender/github.com/ccding/go-stun/stun/tests.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2016, Cong Ding. 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. -// -// Author: Cong Ding - -package stun - -import ( - "net" -) - -func (c *Client) test1(conn net.PacketConn, addr net.Addr) (*response, error) { - return c.sendBindingReq(conn, addr, false, false) -} - -func (c *Client) test2(conn net.PacketConn, addr net.Addr) (*response, error) { - return c.sendBindingReq(conn, addr, true, true) -} - -func (c *Client) test3(conn net.PacketConn, addr net.Addr) (*response, error) { - return c.sendBindingReq(conn, addr, false, true) -} diff --git a/vender/github.com/ccding/go-stun/stun/utils.go b/vender/github.com/ccding/go-stun/stun/utils.go deleted file mode 100755 index 7242316..0000000 --- a/vender/github.com/ccding/go-stun/stun/utils.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2016, Cong Ding. 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. -// -// Author: Cong Ding - -package stun - -import ( - "net" -) - -// Padding the length of the byte slice to multiple of 4. -func padding(bytes []byte) []byte { - length := uint16(len(bytes)) - return append(bytes, make([]byte, align(length)-length)...) -} - -// Align the uint16 number to the smallest multiple of 4, which is larger than -// or equal to the uint16 number. -func align(n uint16) uint16 { - return (n + 3) & 0xfffc -} - -// isLocalAddress check if localRemote is a local address. -func isLocalAddress(local, localRemote string) bool { - // Resolve the IP returned by the STUN server first. - localRemoteAddr, err := net.ResolveUDPAddr("udp", localRemote) - if err != nil { - return false - } - // Try comparing with the local address on the socket first, but only if - // it's actually specified. - addr, err := net.ResolveUDPAddr("udp", local) - if err == nil && addr.IP != nil && !addr.IP.IsUnspecified() { - return addr.IP.Equal(localRemoteAddr.IP) - } - // Fallback to checking IPs of all interfaces - addrs, err := net.InterfaceAddrs() - if err != nil { - return false - } - for _, addr := range addrs { - ip, _, err := net.ParseCIDR(addr.String()) - if err != nil { - continue - } - if ip.Equal(localRemoteAddr.IP) { - return true - } - } - return false -} diff --git a/vender/github.com/ccding/go-stun/stun/utils_test.go b/vender/github.com/ccding/go-stun/stun/utils_test.go deleted file mode 100755 index 6f0088d..0000000 --- a/vender/github.com/ccding/go-stun/stun/utils_test.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2015, Cong Ding. 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. -// -// Author: Cong Ding - -package stun - -import ( - "testing" -) - -func TestPadding(t *testing.T) { - b := []byte{1, 2} - expected := []byte{1, 2, 0, 0} - result := padding(b) - if len(result) != len(expected) { - t.Errorf("Padding error: result size wrong.\n") - } - for i := range expected { - if expected[i] != result[i] { - t.Errorf("Padding error: data wrong in bit %d.\n", i) - } - } -} - -func TestAlign(t *testing.T) { - d := make(map[uint16]uint16) - d[1] = 4 - d[4] = 4 - d[5] = 8 - d[6] = 8 - d[7] = 8 - d[8] = 8 - d[65528] = 65528 - d[65529] = 65532 - d[65531] = 65532 - d[65532] = 65532 - for k, v := range d { - if align(k) != v { - t.Errorf("Align error: expected %d, get %d", align(k), v) - } - } -} - -func TestIsLocalAddress(t *testing.T) { - if !isLocalAddress(":1234", "127.0.0.1:8888") { - t.Errorf("isLocal error") - } - if !isLocalAddress("192.168.0.1:1234", "192.168.0.1:8888") { - t.Errorf("isLocal error") - } - if !isLocalAddress("8.8.8.8:1234", "8.8.8.8:8888") { - t.Errorf("isLocal error") - } - if isLocalAddress(":1234", "8.8.8.8:8888") { - t.Errorf("isLocal error") - } -} diff --git a/vender/github.com/golang/snappy/decode.go b/vender/github.com/golang/snappy/decode.go deleted file mode 100644 index 72efb03..0000000 --- a/vender/github.com/golang/snappy/decode.go +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright 2011 The Snappy-Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package snappy - -import ( - "encoding/binary" - "errors" - "io" -) - -var ( - // ErrCorrupt reports that the input is invalid. - ErrCorrupt = errors.New("snappy: corrupt input") - // ErrTooLarge reports that the uncompressed length is too large. - ErrTooLarge = errors.New("snappy: decoded block is too large") - // ErrUnsupported reports that the input isn't supported. - ErrUnsupported = errors.New("snappy: unsupported input") - - errUnsupportedLiteralLength = errors.New("snappy: unsupported literal length") -) - -// DecodedLen returns the length of the decoded block. -func DecodedLen(src []byte) (int, error) { - v, _, err := decodedLen(src) - return v, err -} - -// decodedLen returns the length of the decoded block and the number of bytes -// that the length header occupied. -func decodedLen(src []byte) (blockLen, headerLen int, err error) { - v, n := binary.Uvarint(src) - if n <= 0 || v > 0xffffffff { - return 0, 0, ErrCorrupt - } - - const wordSize = 32 << (^uint(0) >> 32 & 1) - if wordSize == 32 && v > 0x7fffffff { - return 0, 0, ErrTooLarge - } - return int(v), n, nil -} - -const ( - decodeErrCodeCorrupt = 1 - decodeErrCodeUnsupportedLiteralLength = 2 -) - -// Decode returns the decoded form of src. The returned slice may be a sub- -// slice of dst if dst was large enough to hold the entire decoded block. -// Otherwise, a newly allocated slice will be returned. -// -// The dst and src must not overlap. It is valid to pass a nil dst. -func Decode(dst, src []byte) ([]byte, error) { - dLen, s, err := decodedLen(src) - if err != nil { - return nil, err - } - if dLen <= len(dst) { - dst = dst[:dLen] - } else { - dst = make([]byte, dLen) - } - switch decode(dst, src[s:]) { - case 0: - return dst, nil - case decodeErrCodeUnsupportedLiteralLength: - return nil, errUnsupportedLiteralLength - } - return nil, ErrCorrupt -} - -// NewReader returns a new Reader that decompresses from r, using the framing -// format described at -// https://github.com/google/snappy/blob/master/framing_format.txt -func NewReader(r io.Reader) *Reader { - return &Reader{ - r: r, - decoded: make([]byte, maxBlockSize), - buf: make([]byte, maxEncodedLenOfMaxBlockSize+checksumSize), - } -} - -// Reader is an io.Reader that can read Snappy-compressed bytes. -type Reader struct { - r io.Reader - err error - decoded []byte - buf []byte - // decoded[i:j] contains decoded bytes that have not yet been passed on. - i, j int - readHeader bool -} - -// Reset discards any buffered data, resets all state, and switches the Snappy -// reader to read from r. This permits reusing a Reader rather than allocating -// a new one. -func (r *Reader) Reset(reader io.Reader) { - r.r = reader - r.err = nil - r.i = 0 - r.j = 0 - r.readHeader = false -} - -func (r *Reader) readFull(p []byte, allowEOF bool) (ok bool) { - if _, r.err = io.ReadFull(r.r, p); r.err != nil { - if r.err == io.ErrUnexpectedEOF || (r.err == io.EOF && !allowEOF) { - r.err = ErrCorrupt - } - return false - } - return true -} - -// Read satisfies the io.Reader interface. -func (r *Reader) Read(p []byte) (int, error) { - if r.err != nil { - return 0, r.err - } - for { - if r.i < r.j { - n := copy(p, r.decoded[r.i:r.j]) - r.i += n - return n, nil - } - if !r.readFull(r.buf[:4], true) { - return 0, r.err - } - chunkType := r.buf[0] - if !r.readHeader { - if chunkType != chunkTypeStreamIdentifier { - r.err = ErrCorrupt - return 0, r.err - } - r.readHeader = true - } - chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16 - if chunkLen > len(r.buf) { - r.err = ErrUnsupported - return 0, r.err - } - - // The chunk types are specified at - // https://github.com/google/snappy/blob/master/framing_format.txt - switch chunkType { - case chunkTypeCompressedData: - // Section 4.2. Compressed data (chunk type 0x00). - if chunkLen < checksumSize { - r.err = ErrCorrupt - return 0, r.err - } - buf := r.buf[:chunkLen] - if !r.readFull(buf, false) { - return 0, r.err - } - checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24 - buf = buf[checksumSize:] - - n, err := DecodedLen(buf) - if err != nil { - r.err = err - return 0, r.err - } - if n > len(r.decoded) { - r.err = ErrCorrupt - return 0, r.err - } - if _, err := Decode(r.decoded, buf); err != nil { - r.err = err - return 0, r.err - } - if crc(r.decoded[:n]) != checksum { - r.err = ErrCorrupt - return 0, r.err - } - r.i, r.j = 0, n - continue - - case chunkTypeUncompressedData: - // Section 4.3. Uncompressed data (chunk type 0x01). - if chunkLen < checksumSize { - r.err = ErrCorrupt - return 0, r.err - } - buf := r.buf[:checksumSize] - if !r.readFull(buf, false) { - return 0, r.err - } - checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24 - // Read directly into r.decoded instead of via r.buf. - n := chunkLen - checksumSize - if n > len(r.decoded) { - r.err = ErrCorrupt - return 0, r.err - } - if !r.readFull(r.decoded[:n], false) { - return 0, r.err - } - if crc(r.decoded[:n]) != checksum { - r.err = ErrCorrupt - return 0, r.err - } - r.i, r.j = 0, n - continue - - case chunkTypeStreamIdentifier: - // Section 4.1. Stream identifier (chunk type 0xff). - if chunkLen != len(magicBody) { - r.err = ErrCorrupt - return 0, r.err - } - if !r.readFull(r.buf[:len(magicBody)], false) { - return 0, r.err - } - for i := 0; i < len(magicBody); i++ { - if r.buf[i] != magicBody[i] { - r.err = ErrCorrupt - return 0, r.err - } - } - continue - } - - if chunkType <= 0x7f { - // Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f). - r.err = ErrUnsupported - return 0, r.err - } - // Section 4.4 Padding (chunk type 0xfe). - // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd). - if !r.readFull(r.buf[:chunkLen], false) { - return 0, r.err - } - } -} diff --git a/vender/github.com/golang/snappy/decode_amd64.go b/vender/github.com/golang/snappy/decode_amd64.go deleted file mode 100644 index fcd192b..0000000 --- a/vender/github.com/golang/snappy/decode_amd64.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2016 The Snappy-Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !appengine -// +build gc -// +build !noasm - -package snappy - -// decode has the same semantics as in decode_other.go. -// -//go:noescape -func decode(dst, src []byte) int diff --git a/vender/github.com/golang/snappy/decode_amd64.s b/vender/github.com/golang/snappy/decode_amd64.s deleted file mode 100644 index d16e44c..0000000 --- a/vender/github.com/golang/snappy/decode_amd64.s +++ /dev/null @@ -1,490 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !appengine -// +build gc -// +build !noasm - -#include "textflag.h" - -// The asm code generally follows the pure Go code in decode_other.go, except -// where marked with a "!!!". - -// func decode(dst, src []byte) int -// -// All local variables fit into registers. The non-zero stack size is only to -// spill registers and push args when issuing a CALL. The register allocation: -// - AX scratch -// - BX scratch -// - CX length or x -// - DX offset -// - SI &src[s] -// - DI &dst[d] -// + R8 dst_base -// + R9 dst_len -// + R10 dst_base + dst_len -// + R11 src_base -// + R12 src_len -// + R13 src_base + src_len -// - R14 used by doCopy -// - R15 used by doCopy -// -// The registers R8-R13 (marked with a "+") are set at the start of the -// function, and after a CALL returns, and are not otherwise modified. -// -// The d variable is implicitly DI - R8, and len(dst)-d is R10 - DI. -// The s variable is implicitly SI - R11, and len(src)-s is R13 - SI. -TEXT ·decode(SB), NOSPLIT, $48-56 - // Initialize SI, DI and R8-R13. - MOVQ dst_base+0(FP), R8 - MOVQ dst_len+8(FP), R9 - MOVQ R8, DI - MOVQ R8, R10 - ADDQ R9, R10 - MOVQ src_base+24(FP), R11 - MOVQ src_len+32(FP), R12 - MOVQ R11, SI - MOVQ R11, R13 - ADDQ R12, R13 - -loop: - // for s < len(src) - CMPQ SI, R13 - JEQ end - - // CX = uint32(src[s]) - // - // switch src[s] & 0x03 - MOVBLZX (SI), CX - MOVL CX, BX - ANDL $3, BX - CMPL BX, $1 - JAE tagCopy - - // ---------------------------------------- - // The code below handles literal tags. - - // case tagLiteral: - // x := uint32(src[s] >> 2) - // switch - SHRL $2, CX - CMPL CX, $60 - JAE tagLit60Plus - - // case x < 60: - // s++ - INCQ SI - -doLit: - // This is the end of the inner "switch", when we have a literal tag. - // - // We assume that CX == x and x fits in a uint32, where x is the variable - // used in the pure Go decode_other.go code. - - // length = int(x) + 1 - // - // Unlike the pure Go code, we don't need to check if length <= 0 because - // CX can hold 64 bits, so the increment cannot overflow. - INCQ CX - - // Prepare to check if copying length bytes will run past the end of dst or - // src. - // - // AX = len(dst) - d - // BX = len(src) - s - MOVQ R10, AX - SUBQ DI, AX - MOVQ R13, BX - SUBQ SI, BX - - // !!! Try a faster technique for short (16 or fewer bytes) copies. - // - // if length > 16 || len(dst)-d < 16 || len(src)-s < 16 { - // goto callMemmove // Fall back on calling runtime·memmove. - // } - // - // The C++ snappy code calls this TryFastAppend. It also checks len(src)-s - // against 21 instead of 16, because it cannot assume that all of its input - // is contiguous in memory and so it needs to leave enough source bytes to - // read the next tag without refilling buffers, but Go's Decode assumes - // contiguousness (the src argument is a []byte). - CMPQ CX, $16 - JGT callMemmove - CMPQ AX, $16 - JLT callMemmove - CMPQ BX, $16 - JLT callMemmove - - // !!! Implement the copy from src to dst as a 16-byte load and store. - // (Decode's documentation says that dst and src must not overlap.) - // - // This always copies 16 bytes, instead of only length bytes, but that's - // OK. If the input is a valid Snappy encoding then subsequent iterations - // will fix up the overserver. Otherwise, Decode returns a nil []byte (and a - // non-nil error), so the overrun will be ignored. - // - // Note that on amd64, it is legal and cheap to issue unaligned 8-byte or - // 16-byte loads and stores. This technique probably wouldn't be as - // effective on architectures that are fussier about alignment. - MOVOU 0(SI), X0 - MOVOU X0, 0(DI) - - // d += length - // s += length - ADDQ CX, DI - ADDQ CX, SI - JMP loop - -callMemmove: - // if length > len(dst)-d || length > len(src)-s { etc } - CMPQ CX, AX - JGT errCorrupt - CMPQ CX, BX - JGT errCorrupt - - // copy(dst[d:], src[s:s+length]) - // - // This means calling runtime·memmove(&dst[d], &src[s], length), so we push - // DI, SI and CX as arguments. Coincidentally, we also need to spill those - // three registers to the stack, to save local variables across the CALL. - MOVQ DI, 0(SP) - MOVQ SI, 8(SP) - MOVQ CX, 16(SP) - MOVQ DI, 24(SP) - MOVQ SI, 32(SP) - MOVQ CX, 40(SP) - CALL runtime·memmove(SB) - - // Restore local variables: unspill registers from the stack and - // re-calculate R8-R13. - MOVQ 24(SP), DI - MOVQ 32(SP), SI - MOVQ 40(SP), CX - MOVQ dst_base+0(FP), R8 - MOVQ dst_len+8(FP), R9 - MOVQ R8, R10 - ADDQ R9, R10 - MOVQ src_base+24(FP), R11 - MOVQ src_len+32(FP), R12 - MOVQ R11, R13 - ADDQ R12, R13 - - // d += length - // s += length - ADDQ CX, DI - ADDQ CX, SI - JMP loop - -tagLit60Plus: - // !!! This fragment does the - // - // s += x - 58; if uint(s) > uint(len(src)) { etc } - // - // checks. In the asm version, we code it once instead of once per switch case. - ADDQ CX, SI - SUBQ $58, SI - MOVQ SI, BX - SUBQ R11, BX - CMPQ BX, R12 - JA errCorrupt - - // case x == 60: - CMPL CX, $61 - JEQ tagLit61 - JA tagLit62Plus - - // x = uint32(src[s-1]) - MOVBLZX -1(SI), CX - JMP doLit - -tagLit61: - // case x == 61: - // x = uint32(src[s-2]) | uint32(src[s-1])<<8 - MOVWLZX -2(SI), CX - JMP doLit - -tagLit62Plus: - CMPL CX, $62 - JA tagLit63 - - // case x == 62: - // x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16 - MOVWLZX -3(SI), CX - MOVBLZX -1(SI), BX - SHLL $16, BX - ORL BX, CX - JMP doLit - -tagLit63: - // case x == 63: - // x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24 - MOVL -4(SI), CX - JMP doLit - -// The code above handles literal tags. -// ---------------------------------------- -// The code below handles copy tags. - -tagCopy4: - // case tagCopy4: - // s += 5 - ADDQ $5, SI - - // if uint(s) > uint(len(src)) { etc } - MOVQ SI, BX - SUBQ R11, BX - CMPQ BX, R12 - JA errCorrupt - - // length = 1 + int(src[s-5])>>2 - SHRQ $2, CX - INCQ CX - - // offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24) - MOVLQZX -4(SI), DX - JMP doCopy - -tagCopy2: - // case tagCopy2: - // s += 3 - ADDQ $3, SI - - // if uint(s) > uint(len(src)) { etc } - MOVQ SI, BX - SUBQ R11, BX - CMPQ BX, R12 - JA errCorrupt - - // length = 1 + int(src[s-3])>>2 - SHRQ $2, CX - INCQ CX - - // offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8) - MOVWQZX -2(SI), DX - JMP doCopy - -tagCopy: - // We have a copy tag. We assume that: - // - BX == src[s] & 0x03 - // - CX == src[s] - CMPQ BX, $2 - JEQ tagCopy2 - JA tagCopy4 - - // case tagCopy1: - // s += 2 - ADDQ $2, SI - - // if uint(s) > uint(len(src)) { etc } - MOVQ SI, BX - SUBQ R11, BX - CMPQ BX, R12 - JA errCorrupt - - // offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1])) - MOVQ CX, DX - ANDQ $0xe0, DX - SHLQ $3, DX - MOVBQZX -1(SI), BX - ORQ BX, DX - - // length = 4 + int(src[s-2])>>2&0x7 - SHRQ $2, CX - ANDQ $7, CX - ADDQ $4, CX - -doCopy: - // This is the end of the outer "switch", when we have a copy tag. - // - // We assume that: - // - CX == length && CX > 0 - // - DX == offset - - // if offset <= 0 { etc } - CMPQ DX, $0 - JLE errCorrupt - - // if d < offset { etc } - MOVQ DI, BX - SUBQ R8, BX - CMPQ BX, DX - JLT errCorrupt - - // if length > len(dst)-d { etc } - MOVQ R10, BX - SUBQ DI, BX - CMPQ CX, BX - JGT errCorrupt - - // forwardCopy(dst[d:d+length], dst[d-offset:]); d += length - // - // Set: - // - R14 = len(dst)-d - // - R15 = &dst[d-offset] - MOVQ R10, R14 - SUBQ DI, R14 - MOVQ DI, R15 - SUBQ DX, R15 - - // !!! Try a faster technique for short (16 or fewer bytes) forward copies. - // - // First, try using two 8-byte load/stores, similar to the doLit technique - // above. Even if dst[d:d+length] and dst[d-offset:] can overlap, this is - // still OK if offset >= 8. Note that this has to be two 8-byte load/stores - // and not one 16-byte load/store, and the first store has to be before the - // second load, due to the overlap if offset is in the range [8, 16). - // - // if length > 16 || offset < 8 || len(dst)-d < 16 { - // goto slowForwardCopy - // } - // copy 16 bytes - // d += length - CMPQ CX, $16 - JGT slowForwardCopy - CMPQ DX, $8 - JLT slowForwardCopy - CMPQ R14, $16 - JLT slowForwardCopy - MOVQ 0(R15), AX - MOVQ AX, 0(DI) - MOVQ 8(R15), BX - MOVQ BX, 8(DI) - ADDQ CX, DI - JMP loop - -slowForwardCopy: - // !!! If the forward copy is longer than 16 bytes, or if offset < 8, we - // can still try 8-byte load stores, provided we can overrun up to 10 extra - // bytes. As above, the overrun will be fixed up by subsequent iterations - // of the outermost loop. - // - // The C++ snappy code calls this technique IncrementalCopyFastPath. Its - // commentary says: - // - // ---- - // - // The main part of this loop is a simple copy of eight bytes at a time - // until we've copied (at least) the requested amount of bytes. However, - // if d and d-offset are less than eight bytes apart (indicating a - // repeating pattern of length < 8), we first need to expand the pattern in - // order to get the correct results. For instance, if the buffer looks like - // this, with the eight-byte and patterns marked as - // intervals: - // - // abxxxxxxxxxxxx - // [------] d-offset - // [------] d - // - // a single eight-byte copy from to will repeat the pattern - // once, after which we can move two bytes without moving : - // - // ababxxxxxxxxxx - // [------] d-offset - // [------] d - // - // and repeat the exercise until the two no longer overlap. - // - // This allows us to do very well in the special case of one single byte - // repeated many times, without taking a big hit for more general cases. - // - // The worst case of extra writing past the end of the match occurs when - // offset == 1 and length == 1; the last copy will read from byte positions - // [0..7] and write to [4..11], whereas it was only supposed to write to - // position 1. Thus, ten excess bytes. - // - // ---- - // - // That "10 byte overrun" worst case is confirmed by Go's - // TestSlowForwardCopyOverrun, which also tests the fixUpSlowForwardCopy - // and finishSlowForwardCopy algorithm. - // - // if length > len(dst)-d-10 { - // goto verySlowForwardCopy - // } - SUBQ $10, R14 - CMPQ CX, R14 - JGT verySlowForwardCopy - -makeOffsetAtLeast8: - // !!! As above, expand the pattern so that offset >= 8 and we can use - // 8-byte load/stores. - // - // for offset < 8 { - // copy 8 bytes from dst[d-offset:] to dst[d:] - // length -= offset - // d += offset - // offset += offset - // // The two previous lines together means that d-offset, and therefore - // // R15, is unchanged. - // } - CMPQ DX, $8 - JGE fixUpSlowForwardCopy - MOVQ (R15), BX - MOVQ BX, (DI) - SUBQ DX, CX - ADDQ DX, DI - ADDQ DX, DX - JMP makeOffsetAtLeast8 - -fixUpSlowForwardCopy: - // !!! Add length (which might be negative now) to d (implied by DI being - // &dst[d]) so that d ends up at the right place when we jump back to the - // top of the loop. Before we do that, though, we save DI to AX so that, if - // length is positive, copying the remaining length bytes will write to the - // right place. - MOVQ DI, AX - ADDQ CX, DI - -finishSlowForwardCopy: - // !!! Repeat 8-byte load/stores until length <= 0. Ending with a negative - // length means that we overrun, but as above, that will be fixed up by - // subsequent iterations of the outermost loop. - CMPQ CX, $0 - JLE loop - MOVQ (R15), BX - MOVQ BX, (AX) - ADDQ $8, R15 - ADDQ $8, AX - SUBQ $8, CX - JMP finishSlowForwardCopy - -verySlowForwardCopy: - // verySlowForwardCopy is a simple implementation of forward copy. In C - // parlance, this is a do/while loop instead of a while loop, since we know - // that length > 0. In Go syntax: - // - // for { - // dst[d] = dst[d - offset] - // d++ - // length-- - // if length == 0 { - // break - // } - // } - MOVB (R15), BX - MOVB BX, (DI) - INCQ R15 - INCQ DI - DECQ CX - JNZ verySlowForwardCopy - JMP loop - -// The code above handles copy tags. -// ---------------------------------------- - -end: - // This is the end of the "for s < len(src)". - // - // if d != len(dst) { etc } - CMPQ DI, R10 - JNE errCorrupt - - // return 0 - MOVQ $0, ret+48(FP) - RET - -errCorrupt: - // return decodeErrCodeCorrupt - MOVQ $1, ret+48(FP) - RET diff --git a/vender/github.com/golang/snappy/decode_other.go b/vender/github.com/golang/snappy/decode_other.go deleted file mode 100644 index 8c9f204..0000000 --- a/vender/github.com/golang/snappy/decode_other.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2016 The Snappy-Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !amd64 appengine !gc noasm - -package snappy - -// decode writes the decoding of src to dst. It assumes that the varint-encoded -// length of the decompressed bytes has already been read, and that len(dst) -// equals that length. -// -// It returns 0 on success or a decodeErrCodeXxx error code on failure. -func decode(dst, src []byte) int { - var d, s, offset, length int - for s < len(src) { - switch src[s] & 0x03 { - case tagLiteral: - x := uint32(src[s] >> 2) - switch { - case x < 60: - s++ - case x == 60: - s += 2 - if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. - return decodeErrCodeCorrupt - } - x = uint32(src[s-1]) - case x == 61: - s += 3 - if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. - return decodeErrCodeCorrupt - } - x = uint32(src[s-2]) | uint32(src[s-1])<<8 - case x == 62: - s += 4 - if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. - return decodeErrCodeCorrupt - } - x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16 - case x == 63: - s += 5 - if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. - return decodeErrCodeCorrupt - } - x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24 - } - length = int(x) + 1 - if length <= 0 { - return decodeErrCodeUnsupportedLiteralLength - } - if length > len(dst)-d || length > len(src)-s { - return decodeErrCodeCorrupt - } - copy(dst[d:], src[s:s+length]) - d += length - s += length - continue - - case tagCopy1: - s += 2 - if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. - return decodeErrCodeCorrupt - } - length = 4 + int(src[s-2])>>2&0x7 - offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1])) - - case tagCopy2: - s += 3 - if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. - return decodeErrCodeCorrupt - } - length = 1 + int(src[s-3])>>2 - offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8) - - case tagCopy4: - s += 5 - if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. - return decodeErrCodeCorrupt - } - length = 1 + int(src[s-5])>>2 - offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24) - } - - if offset <= 0 || d < offset || length > len(dst)-d { - return decodeErrCodeCorrupt - } - // Copy from an earlier sub-slice of dst to a later sub-slice. Unlike - // the built-in copy function, this byte-by-byte copy always runs - // forwards, even if the slices overlap. Conceptually, this is: - // - // d += forwardCopy(dst[d:d+length], dst[d-offset:]) - for end := d + length; d != end; d++ { - dst[d] = dst[d-offset] - } - } - if d != len(dst) { - return decodeErrCodeCorrupt - } - return 0 -} diff --git a/vender/github.com/golang/snappy/encode.go b/vender/github.com/golang/snappy/encode.go deleted file mode 100644 index 8d393e9..0000000 --- a/vender/github.com/golang/snappy/encode.go +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright 2011 The Snappy-Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package snappy - -import ( - "encoding/binary" - "errors" - "io" -) - -// Encode returns the encoded form of src. The returned slice may be a sub- -// slice of dst if dst was large enough to hold the entire encoded block. -// Otherwise, a newly allocated slice will be returned. -// -// The dst and src must not overlap. It is valid to pass a nil dst. -func Encode(dst, src []byte) []byte { - if n := MaxEncodedLen(len(src)); n < 0 { - panic(ErrTooLarge) - } else if len(dst) < n { - dst = make([]byte, n) - } - - // The block starts with the varint-encoded length of the decompressed bytes. - d := binary.PutUvarint(dst, uint64(len(src))) - - for len(src) > 0 { - p := src - src = nil - if len(p) > maxBlockSize { - p, src = p[:maxBlockSize], p[maxBlockSize:] - } - if len(p) < minNonLiteralBlockSize { - d += emitLiteral(dst[d:], p) - } else { - d += encodeBlock(dst[d:], p) - } - } - return dst[:d] -} - -// inputMargin is the minimum number of extra input bytes to keep, inside -// encodeBlock's inner loop. On some architectures, this margin lets us -// implement a fast path for emitLiteral, where the copy of short (<= 16 byte) -// literals can be implemented as a single load to and store from a 16-byte -// register. That literal's actual length can be as short as 1 byte, so this -// can copy up to 15 bytes too much, but that's OK as subsequent iterations of -// the encoding loop will fix up the copy overrun, and this inputMargin ensures -// that we don't overrun the dst and src buffers. -const inputMargin = 16 - 1 - -// minNonLiteralBlockSize is the minimum size of the input to encodeBlock that -// could be encoded with a copy tag. This is the minimum with respect to the -// algorithm used by encodeBlock, not a minimum enforced by the file format. -// -// The encoded output must start with at least a 1 byte literal, as there are -// no previous bytes to copy. A minimal (1 byte) copy after that, generated -// from an emitCopy call in encodeBlock's main loop, would require at least -// another inputMargin bytes, for the reason above: we want any emitLiteral -// calls inside encodeBlock's main loop to use the fast path if possible, which -// requires being able to overrun by inputMargin bytes. Thus, -// minNonLiteralBlockSize equals 1 + 1 + inputMargin. -// -// The C++ code doesn't use this exact threshold, but it could, as discussed at -// https://groups.google.com/d/topic/snappy-compression/oGbhsdIJSJ8/discussion -// The difference between Go (2+inputMargin) and C++ (inputMargin) is purely an -// optimization. It should not affect the encoded form. This is tested by -// TestSameEncodingAsCppShortCopies. -const minNonLiteralBlockSize = 1 + 1 + inputMargin - -// MaxEncodedLen returns the maximum length of a snappy block, given its -// uncompressed length. -// -// It will return a negative value if srcLen is too large to encode. -func MaxEncodedLen(srcLen int) int { - n := uint64(srcLen) - if n > 0xffffffff { - return -1 - } - // Compressed data can be defined as: - // compressed := item* literal* - // item := literal* copy - // - // The trailing literal sequence has a space blowup of at most 62/60 - // since a literal of length 60 needs one tag byte + one extra byte - // for length information. - // - // Item blowup is trickier to measure. Suppose the "copy" op copies - // 4 bytes of data. Because of a special check in the encoding code, - // we produce a 4-byte copy only if the offset is < 65536. Therefore - // the copy op takes 3 bytes to encode, and this type of item leads - // to at most the 62/60 blowup for representing literals. - // - // Suppose the "copy" op copies 5 bytes of data. If the offset is big - // enough, it will take 5 bytes to encode the copy op. Therefore the - // worst case here is a one-byte literal followed by a five-byte copy. - // That is, 6 bytes of input turn into 7 bytes of "compressed" data. - // - // This last factor dominates the blowup, so the final estimate is: - n = 32 + n + n/6 - if n > 0xffffffff { - return -1 - } - return int(n) -} - -var errClosed = errors.New("snappy: Writer is closed") - -// NewWriter returns a new Writer that compresses to w. -// -// The Writer returned does not buffer writes. There is no need to Flush or -// Close such a Writer. -// -// Deprecated: the Writer returned is not suitable for many small writes, only -// for few large writes. Use NewBufferedWriter instead, which is efficient -// regardless of the frequency and shape of the writes, and remember to Close -// that Writer when done. -func NewWriter(w io.Writer) *Writer { - return &Writer{ - w: w, - obuf: make([]byte, obufLen), - } -} - -// NewBufferedWriter returns a new Writer that compresses to w, using the -// framing format described at -// https://github.com/google/snappy/blob/master/framing_format.txt -// -// The Writer returned buffers writes. Users must call Close to guarantee all -// data has been forwarded to the underlying io.Writer. They may also call -// Flush zero or more times before calling Close. -func NewBufferedWriter(w io.Writer) *Writer { - return &Writer{ - w: w, - ibuf: make([]byte, 0, maxBlockSize), - obuf: make([]byte, obufLen), - } -} - -// Writer is an io.Writer that can write Snappy-compressed bytes. -type Writer struct { - w io.Writer - err error - - // ibuf is a buffer for the incoming (uncompressed) bytes. - // - // Its use is optional. For backwards compatibility, Writers created by the - // NewWriter function have ibuf == nil, do not buffer incoming bytes, and - // therefore do not need to be Flush'ed or Close'd. - ibuf []byte - - // obuf is a buffer for the outgoing (compressed) bytes. - obuf []byte - - // wroteStreamHeader is whether we have written the stream header. - wroteStreamHeader bool -} - -// Reset discards the writer's state and switches the Snappy writer to write to -// w. This permits reusing a Writer rather than allocating a new one. -func (w *Writer) Reset(writer io.Writer) { - w.w = writer - w.err = nil - if w.ibuf != nil { - w.ibuf = w.ibuf[:0] - } - w.wroteStreamHeader = false -} - -// Write satisfies the io.Writer interface. -func (w *Writer) Write(p []byte) (nRet int, errRet error) { - if w.ibuf == nil { - // Do not buffer incoming bytes. This does not perform or compress well - // if the caller of Writer.Write writes many small slices. This - // behavior is therefore deprecated, but still supported for backwards - // compatibility with code that doesn't explicitly Flush or Close. - return w.write(p) - } - - // The remainder of this method is based on bufio.Writer.Write from the - // standard library. - - for len(p) > (cap(w.ibuf)-len(w.ibuf)) && w.err == nil { - var n int - if len(w.ibuf) == 0 { - // Large write, empty buffer. - // Write directly from p to avoid copy. - n, _ = w.write(p) - } else { - n = copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p) - w.ibuf = w.ibuf[:len(w.ibuf)+n] - w.Flush() - } - nRet += n - p = p[n:] - } - if w.err != nil { - return nRet, w.err - } - n := copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p) - w.ibuf = w.ibuf[:len(w.ibuf)+n] - nRet += n - return nRet, nil -} - -func (w *Writer) write(p []byte) (nRet int, errRet error) { - if w.err != nil { - return 0, w.err - } - for len(p) > 0 { - obufStart := len(magicChunk) - if !w.wroteStreamHeader { - w.wroteStreamHeader = true - copy(w.obuf, magicChunk) - obufStart = 0 - } - - var uncompressed []byte - if len(p) > maxBlockSize { - uncompressed, p = p[:maxBlockSize], p[maxBlockSize:] - } else { - uncompressed, p = p, nil - } - checksum := crc(uncompressed) - - // Compress the buffer, discarding the result if the improvement - // isn't at least 12.5%. - compressed := Encode(w.obuf[obufHeaderLen:], uncompressed) - chunkType := uint8(chunkTypeCompressedData) - chunkLen := 4 + len(compressed) - obufEnd := obufHeaderLen + len(compressed) - if len(compressed) >= len(uncompressed)-len(uncompressed)/8 { - chunkType = chunkTypeUncompressedData - chunkLen = 4 + len(uncompressed) - obufEnd = obufHeaderLen - } - - // Fill in the per-chunk header that comes before the body. - w.obuf[len(magicChunk)+0] = chunkType - w.obuf[len(magicChunk)+1] = uint8(chunkLen >> 0) - w.obuf[len(magicChunk)+2] = uint8(chunkLen >> 8) - w.obuf[len(magicChunk)+3] = uint8(chunkLen >> 16) - w.obuf[len(magicChunk)+4] = uint8(checksum >> 0) - w.obuf[len(magicChunk)+5] = uint8(checksum >> 8) - w.obuf[len(magicChunk)+6] = uint8(checksum >> 16) - w.obuf[len(magicChunk)+7] = uint8(checksum >> 24) - - if _, err := w.w.Write(w.obuf[obufStart:obufEnd]); err != nil { - w.err = err - return nRet, err - } - if chunkType == chunkTypeUncompressedData { - if _, err := w.w.Write(uncompressed); err != nil { - w.err = err - return nRet, err - } - } - nRet += len(uncompressed) - } - return nRet, nil -} - -// Flush flushes the Writer to its underlying io.Writer. -func (w *Writer) Flush() error { - if w.err != nil { - return w.err - } - if len(w.ibuf) == 0 { - return nil - } - w.write(w.ibuf) - w.ibuf = w.ibuf[:0] - return w.err -} - -// Close calls Flush and then closes the Writer. -func (w *Writer) Close() error { - w.Flush() - ret := w.err - if w.err == nil { - w.err = errClosed - } - return ret -} diff --git a/vender/github.com/golang/snappy/encode_amd64.go b/vender/github.com/golang/snappy/encode_amd64.go deleted file mode 100644 index 150d91b..0000000 --- a/vender/github.com/golang/snappy/encode_amd64.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2016 The Snappy-Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !appengine -// +build gc -// +build !noasm - -package snappy - -// emitLiteral has the same semantics as in encode_other.go. -// -//go:noescape -func emitLiteral(dst, lit []byte) int - -// emitCopy has the same semantics as in encode_other.go. -// -//go:noescape -func emitCopy(dst []byte, offset, length int) int - -// extendMatch has the same semantics as in encode_other.go. -// -//go:noescape -func extendMatch(src []byte, i, j int) int - -// encodeBlock has the same semantics as in encode_other.go. -// -//go:noescape -func encodeBlock(dst, src []byte) (d int) diff --git a/vender/github.com/golang/snappy/encode_amd64.s b/vender/github.com/golang/snappy/encode_amd64.s deleted file mode 100644 index b3ec953..0000000 --- a/vender/github.com/golang/snappy/encode_amd64.s +++ /dev/null @@ -1,730 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !appengine -// +build gc -// +build !noasm - -#include "textflag.h" - -// The XXX lines assemble on Go 1.4, 1.5 and 1.7, but not 1.6, due to a -// Go toolchain regression. See https://github.com/golang/go/issues/15426 and -// https://github.com/golang/snappy/issues/29 -// -// As a workaround, the package was built with a known good assembler, and -// those instructions were disassembled by "objdump -d" to yield the -// 4e 0f b7 7c 5c 78 movzwq 0x78(%rsp,%r11,2),%r15 -// style comments, in AT&T asm syntax. Note that rsp here is a physical -// register, not Go/asm's SP pseudo-register (see https://golang.org/doc/asm). -// The instructions were then encoded as "BYTE $0x.." sequences, which assemble -// fine on Go 1.6. - -// The asm code generally follows the pure Go code in encode_other.go, except -// where marked with a "!!!". - -// ---------------------------------------------------------------------------- - -// func emitLiteral(dst, lit []byte) int -// -// All local variables fit into registers. The register allocation: -// - AX len(lit) -// - BX n -// - DX return value -// - DI &dst[i] -// - R10 &lit[0] -// -// The 24 bytes of stack space is to call runtime·memmove. -// -// The unusual register allocation of local variables, such as R10 for the -// source pointer, matches the allocation used at the call site in encodeBlock, -// which makes it easier to manually inline this function. -TEXT ·emitLiteral(SB), NOSPLIT, $24-56 - MOVQ dst_base+0(FP), DI - MOVQ lit_base+24(FP), R10 - MOVQ lit_len+32(FP), AX - MOVQ AX, DX - MOVL AX, BX - SUBL $1, BX - - CMPL BX, $60 - JLT oneByte - CMPL BX, $256 - JLT twoBytes - -threeBytes: - MOVB $0xf4, 0(DI) - MOVW BX, 1(DI) - ADDQ $3, DI - ADDQ $3, DX - JMP memmove - -twoBytes: - MOVB $0xf0, 0(DI) - MOVB BX, 1(DI) - ADDQ $2, DI - ADDQ $2, DX - JMP memmove - -oneByte: - SHLB $2, BX - MOVB BX, 0(DI) - ADDQ $1, DI - ADDQ $1, DX - -memmove: - MOVQ DX, ret+48(FP) - - // copy(dst[i:], lit) - // - // This means calling runtime·memmove(&dst[i], &lit[0], len(lit)), so we push - // DI, R10 and AX as arguments. - MOVQ DI, 0(SP) - MOVQ R10, 8(SP) - MOVQ AX, 16(SP) - CALL runtime·memmove(SB) - RET - -// ---------------------------------------------------------------------------- - -// func emitCopy(dst []byte, offset, length int) int -// -// All local variables fit into registers. The register allocation: -// - AX length -// - SI &dst[0] -// - DI &dst[i] -// - R11 offset -// -// The unusual register allocation of local variables, such as R11 for the -// offset, matches the allocation used at the call site in encodeBlock, which -// makes it easier to manually inline this function. -TEXT ·emitCopy(SB), NOSPLIT, $0-48 - MOVQ dst_base+0(FP), DI - MOVQ DI, SI - MOVQ offset+24(FP), R11 - MOVQ length+32(FP), AX - -loop0: - // for length >= 68 { etc } - CMPL AX, $68 - JLT step1 - - // Emit a length 64 copy, encoded as 3 bytes. - MOVB $0xfe, 0(DI) - MOVW R11, 1(DI) - ADDQ $3, DI - SUBL $64, AX - JMP loop0 - -step1: - // if length > 64 { etc } - CMPL AX, $64 - JLE step2 - - // Emit a length 60 copy, encoded as 3 bytes. - MOVB $0xee, 0(DI) - MOVW R11, 1(DI) - ADDQ $3, DI - SUBL $60, AX - -step2: - // if length >= 12 || offset >= 2048 { goto step3 } - CMPL AX, $12 - JGE step3 - CMPL R11, $2048 - JGE step3 - - // Emit the remaining copy, encoded as 2 bytes. - MOVB R11, 1(DI) - SHRL $8, R11 - SHLB $5, R11 - SUBB $4, AX - SHLB $2, AX - ORB AX, R11 - ORB $1, R11 - MOVB R11, 0(DI) - ADDQ $2, DI - - // Return the number of bytes written. - SUBQ SI, DI - MOVQ DI, ret+40(FP) - RET - -step3: - // Emit the remaining copy, encoded as 3 bytes. - SUBL $1, AX - SHLB $2, AX - ORB $2, AX - MOVB AX, 0(DI) - MOVW R11, 1(DI) - ADDQ $3, DI - - // Return the number of bytes written. - SUBQ SI, DI - MOVQ DI, ret+40(FP) - RET - -// ---------------------------------------------------------------------------- - -// func extendMatch(src []byte, i, j int) int -// -// All local variables fit into registers. The register allocation: -// - DX &src[0] -// - SI &src[j] -// - R13 &src[len(src) - 8] -// - R14 &src[len(src)] -// - R15 &src[i] -// -// The unusual register allocation of local variables, such as R15 for a source -// pointer, matches the allocation used at the call site in encodeBlock, which -// makes it easier to manually inline this function. -TEXT ·extendMatch(SB), NOSPLIT, $0-48 - MOVQ src_base+0(FP), DX - MOVQ src_len+8(FP), R14 - MOVQ i+24(FP), R15 - MOVQ j+32(FP), SI - ADDQ DX, R14 - ADDQ DX, R15 - ADDQ DX, SI - MOVQ R14, R13 - SUBQ $8, R13 - -cmp8: - // As long as we are 8 or more bytes before the end of src, we can load and - // compare 8 bytes at a time. If those 8 bytes are equal, repeat. - CMPQ SI, R13 - JA cmp1 - MOVQ (R15), AX - MOVQ (SI), BX - CMPQ AX, BX - JNE bsf - ADDQ $8, R15 - ADDQ $8, SI - JMP cmp8 - -bsf: - // If those 8 bytes were not equal, XOR the two 8 byte values, and return - // the index of the first byte that differs. The BSF instruction finds the - // least significant 1 bit, the amd64 architecture is little-endian, and - // the shift by 3 converts a bit index to a byte index. - XORQ AX, BX - BSFQ BX, BX - SHRQ $3, BX - ADDQ BX, SI - - // Convert from &src[ret] to ret. - SUBQ DX, SI - MOVQ SI, ret+40(FP) - RET - -cmp1: - // In src's tail, compare 1 byte at a time. - CMPQ SI, R14 - JAE extendMatchEnd - MOVB (R15), AX - MOVB (SI), BX - CMPB AX, BX - JNE extendMatchEnd - ADDQ $1, R15 - ADDQ $1, SI - JMP cmp1 - -extendMatchEnd: - // Convert from &src[ret] to ret. - SUBQ DX, SI - MOVQ SI, ret+40(FP) - RET - -// ---------------------------------------------------------------------------- - -// func encodeBlock(dst, src []byte) (d int) -// -// All local variables fit into registers, other than "var table". The register -// allocation: -// - AX . . -// - BX . . -// - CX 56 shift (note that amd64 shifts by non-immediates must use CX). -// - DX 64 &src[0], tableSize -// - SI 72 &src[s] -// - DI 80 &dst[d] -// - R9 88 sLimit -// - R10 . &src[nextEmit] -// - R11 96 prevHash, currHash, nextHash, offset -// - R12 104 &src[base], skip -// - R13 . &src[nextS], &src[len(src) - 8] -// - R14 . len(src), bytesBetweenHashLookups, &src[len(src)], x -// - R15 112 candidate -// -// The second column (56, 64, etc) is the stack offset to spill the registers -// when calling other functions. We could pack this slightly tighter, but it's -// simpler to have a dedicated spill map independent of the function called. -// -// "var table [maxTableSize]uint16" takes up 32768 bytes of stack space. An -// extra 56 bytes, to call other functions, and an extra 64 bytes, to spill -// local variables (registers) during calls gives 32768 + 56 + 64 = 32888. -TEXT ·encodeBlock(SB), 0, $32888-56 - MOVQ dst_base+0(FP), DI - MOVQ src_base+24(FP), SI - MOVQ src_len+32(FP), R14 - - // shift, tableSize := uint32(32-8), 1<<8 - MOVQ $24, CX - MOVQ $256, DX - -calcShift: - // for ; tableSize < maxTableSize && tableSize < len(src); tableSize *= 2 { - // shift-- - // } - CMPQ DX, $16384 - JGE varTable - CMPQ DX, R14 - JGE varTable - SUBQ $1, CX - SHLQ $1, DX - JMP calcShift - -varTable: - // var table [maxTableSize]uint16 - // - // In the asm code, unlike the Go code, we can zero-initialize only the - // first tableSize elements. Each uint16 element is 2 bytes and each MOVOU - // writes 16 bytes, so we can do only tableSize/8 writes instead of the - // 2048 writes that would zero-initialize all of table's 32768 bytes. - SHRQ $3, DX - LEAQ table-32768(SP), BX - PXOR X0, X0 - -memclr: - MOVOU X0, 0(BX) - ADDQ $16, BX - SUBQ $1, DX - JNZ memclr - - // !!! DX = &src[0] - MOVQ SI, DX - - // sLimit := len(src) - inputMargin - MOVQ R14, R9 - SUBQ $15, R9 - - // !!! Pre-emptively spill CX, DX and R9 to the stack. Their values don't - // change for the rest of the function. - MOVQ CX, 56(SP) - MOVQ DX, 64(SP) - MOVQ R9, 88(SP) - - // nextEmit := 0 - MOVQ DX, R10 - - // s := 1 - ADDQ $1, SI - - // nextHash := hash(load32(src, s), shift) - MOVL 0(SI), R11 - IMULL $0x1e35a7bd, R11 - SHRL CX, R11 - -outer: - // for { etc } - - // skip := 32 - MOVQ $32, R12 - - // nextS := s - MOVQ SI, R13 - - // candidate := 0 - MOVQ $0, R15 - -inner0: - // for { etc } - - // s := nextS - MOVQ R13, SI - - // bytesBetweenHashLookups := skip >> 5 - MOVQ R12, R14 - SHRQ $5, R14 - - // nextS = s + bytesBetweenHashLookups - ADDQ R14, R13 - - // skip += bytesBetweenHashLookups - ADDQ R14, R12 - - // if nextS > sLimit { goto emitRemainder } - MOVQ R13, AX - SUBQ DX, AX - CMPQ AX, R9 - JA emitRemainder - - // candidate = int(table[nextHash]) - // XXX: MOVWQZX table-32768(SP)(R11*2), R15 - // XXX: 4e 0f b7 7c 5c 78 movzwq 0x78(%rsp,%r11,2),%r15 - BYTE $0x4e - BYTE $0x0f - BYTE $0xb7 - BYTE $0x7c - BYTE $0x5c - BYTE $0x78 - - // table[nextHash] = uint16(s) - MOVQ SI, AX - SUBQ DX, AX - - // XXX: MOVW AX, table-32768(SP)(R11*2) - // XXX: 66 42 89 44 5c 78 mov %ax,0x78(%rsp,%r11,2) - BYTE $0x66 - BYTE $0x42 - BYTE $0x89 - BYTE $0x44 - BYTE $0x5c - BYTE $0x78 - - // nextHash = hash(load32(src, nextS), shift) - MOVL 0(R13), R11 - IMULL $0x1e35a7bd, R11 - SHRL CX, R11 - - // if load32(src, s) != load32(src, candidate) { continue } break - MOVL 0(SI), AX - MOVL (DX)(R15*1), BX - CMPL AX, BX - JNE inner0 - -fourByteMatch: - // As per the encode_other.go code: - // - // A 4-byte match has been found. We'll later see etc. - - // !!! Jump to a fast path for short (<= 16 byte) literals. See the comment - // on inputMargin in encode.go. - MOVQ SI, AX - SUBQ R10, AX - CMPQ AX, $16 - JLE emitLiteralFastPath - - // ---------------------------------------- - // Begin inline of the emitLiteral call. - // - // d += emitLiteral(dst[d:], src[nextEmit:s]) - - MOVL AX, BX - SUBL $1, BX - - CMPL BX, $60 - JLT inlineEmitLiteralOneByte - CMPL BX, $256 - JLT inlineEmitLiteralTwoBytes - -inlineEmitLiteralThreeBytes: - MOVB $0xf4, 0(DI) - MOVW BX, 1(DI) - ADDQ $3, DI - JMP inlineEmitLiteralMemmove - -inlineEmitLiteralTwoBytes: - MOVB $0xf0, 0(DI) - MOVB BX, 1(DI) - ADDQ $2, DI - JMP inlineEmitLiteralMemmove - -inlineEmitLiteralOneByte: - SHLB $2, BX - MOVB BX, 0(DI) - ADDQ $1, DI - -inlineEmitLiteralMemmove: - // Spill local variables (registers) onto the stack; call; unspill. - // - // copy(dst[i:], lit) - // - // This means calling runtime·memmove(&dst[i], &lit[0], len(lit)), so we push - // DI, R10 and AX as arguments. - MOVQ DI, 0(SP) - MOVQ R10, 8(SP) - MOVQ AX, 16(SP) - ADDQ AX, DI // Finish the "d +=" part of "d += emitLiteral(etc)". - MOVQ SI, 72(SP) - MOVQ DI, 80(SP) - MOVQ R15, 112(SP) - CALL runtime·memmove(SB) - MOVQ 56(SP), CX - MOVQ 64(SP), DX - MOVQ 72(SP), SI - MOVQ 80(SP), DI - MOVQ 88(SP), R9 - MOVQ 112(SP), R15 - JMP inner1 - -inlineEmitLiteralEnd: - // End inline of the emitLiteral call. - // ---------------------------------------- - -emitLiteralFastPath: - // !!! Emit the 1-byte encoding "uint8(len(lit)-1)<<2". - MOVB AX, BX - SUBB $1, BX - SHLB $2, BX - MOVB BX, (DI) - ADDQ $1, DI - - // !!! Implement the copy from lit to dst as a 16-byte load and store. - // (Encode's documentation says that dst and src must not overlap.) - // - // This always copies 16 bytes, instead of only len(lit) bytes, but that's - // OK. Subsequent iterations will fix up the overserver. - // - // Note that on amd64, it is legal and cheap to issue unaligned 8-byte or - // 16-byte loads and stores. This technique probably wouldn't be as - // effective on architectures that are fussier about alignment. - MOVOU 0(R10), X0 - MOVOU X0, 0(DI) - ADDQ AX, DI - -inner1: - // for { etc } - - // base := s - MOVQ SI, R12 - - // !!! offset := base - candidate - MOVQ R12, R11 - SUBQ R15, R11 - SUBQ DX, R11 - - // ---------------------------------------- - // Begin inline of the extendMatch call. - // - // s = extendMatch(src, candidate+4, s+4) - - // !!! R14 = &src[len(src)] - MOVQ src_len+32(FP), R14 - ADDQ DX, R14 - - // !!! R13 = &src[len(src) - 8] - MOVQ R14, R13 - SUBQ $8, R13 - - // !!! R15 = &src[candidate + 4] - ADDQ $4, R15 - ADDQ DX, R15 - - // !!! s += 4 - ADDQ $4, SI - -inlineExtendMatchCmp8: - // As long as we are 8 or more bytes before the end of src, we can load and - // compare 8 bytes at a time. If those 8 bytes are equal, repeat. - CMPQ SI, R13 - JA inlineExtendMatchCmp1 - MOVQ (R15), AX - MOVQ (SI), BX - CMPQ AX, BX - JNE inlineExtendMatchBSF - ADDQ $8, R15 - ADDQ $8, SI - JMP inlineExtendMatchCmp8 - -inlineExtendMatchBSF: - // If those 8 bytes were not equal, XOR the two 8 byte values, and return - // the index of the first byte that differs. The BSF instruction finds the - // least significant 1 bit, the amd64 architecture is little-endian, and - // the shift by 3 converts a bit index to a byte index. - XORQ AX, BX - BSFQ BX, BX - SHRQ $3, BX - ADDQ BX, SI - JMP inlineExtendMatchEnd - -inlineExtendMatchCmp1: - // In src's tail, compare 1 byte at a time. - CMPQ SI, R14 - JAE inlineExtendMatchEnd - MOVB (R15), AX - MOVB (SI), BX - CMPB AX, BX - JNE inlineExtendMatchEnd - ADDQ $1, R15 - ADDQ $1, SI - JMP inlineExtendMatchCmp1 - -inlineExtendMatchEnd: - // End inline of the extendMatch call. - // ---------------------------------------- - - // ---------------------------------------- - // Begin inline of the emitCopy call. - // - // d += emitCopy(dst[d:], base-candidate, s-base) - - // !!! length := s - base - MOVQ SI, AX - SUBQ R12, AX - -inlineEmitCopyLoop0: - // for length >= 68 { etc } - CMPL AX, $68 - JLT inlineEmitCopyStep1 - - // Emit a length 64 copy, encoded as 3 bytes. - MOVB $0xfe, 0(DI) - MOVW R11, 1(DI) - ADDQ $3, DI - SUBL $64, AX - JMP inlineEmitCopyLoop0 - -inlineEmitCopyStep1: - // if length > 64 { etc } - CMPL AX, $64 - JLE inlineEmitCopyStep2 - - // Emit a length 60 copy, encoded as 3 bytes. - MOVB $0xee, 0(DI) - MOVW R11, 1(DI) - ADDQ $3, DI - SUBL $60, AX - -inlineEmitCopyStep2: - // if length >= 12 || offset >= 2048 { goto inlineEmitCopyStep3 } - CMPL AX, $12 - JGE inlineEmitCopyStep3 - CMPL R11, $2048 - JGE inlineEmitCopyStep3 - - // Emit the remaining copy, encoded as 2 bytes. - MOVB R11, 1(DI) - SHRL $8, R11 - SHLB $5, R11 - SUBB $4, AX - SHLB $2, AX - ORB AX, R11 - ORB $1, R11 - MOVB R11, 0(DI) - ADDQ $2, DI - JMP inlineEmitCopyEnd - -inlineEmitCopyStep3: - // Emit the remaining copy, encoded as 3 bytes. - SUBL $1, AX - SHLB $2, AX - ORB $2, AX - MOVB AX, 0(DI) - MOVW R11, 1(DI) - ADDQ $3, DI - -inlineEmitCopyEnd: - // End inline of the emitCopy call. - // ---------------------------------------- - - // nextEmit = s - MOVQ SI, R10 - - // if s >= sLimit { goto emitRemainder } - MOVQ SI, AX - SUBQ DX, AX - CMPQ AX, R9 - JAE emitRemainder - - // As per the encode_other.go code: - // - // We could immediately etc. - - // x := load64(src, s-1) - MOVQ -1(SI), R14 - - // prevHash := hash(uint32(x>>0), shift) - MOVL R14, R11 - IMULL $0x1e35a7bd, R11 - SHRL CX, R11 - - // table[prevHash] = uint16(s-1) - MOVQ SI, AX - SUBQ DX, AX - SUBQ $1, AX - - // XXX: MOVW AX, table-32768(SP)(R11*2) - // XXX: 66 42 89 44 5c 78 mov %ax,0x78(%rsp,%r11,2) - BYTE $0x66 - BYTE $0x42 - BYTE $0x89 - BYTE $0x44 - BYTE $0x5c - BYTE $0x78 - - // currHash := hash(uint32(x>>8), shift) - SHRQ $8, R14 - MOVL R14, R11 - IMULL $0x1e35a7bd, R11 - SHRL CX, R11 - - // candidate = int(table[currHash]) - // XXX: MOVWQZX table-32768(SP)(R11*2), R15 - // XXX: 4e 0f b7 7c 5c 78 movzwq 0x78(%rsp,%r11,2),%r15 - BYTE $0x4e - BYTE $0x0f - BYTE $0xb7 - BYTE $0x7c - BYTE $0x5c - BYTE $0x78 - - // table[currHash] = uint16(s) - ADDQ $1, AX - - // XXX: MOVW AX, table-32768(SP)(R11*2) - // XXX: 66 42 89 44 5c 78 mov %ax,0x78(%rsp,%r11,2) - BYTE $0x66 - BYTE $0x42 - BYTE $0x89 - BYTE $0x44 - BYTE $0x5c - BYTE $0x78 - - // if uint32(x>>8) == load32(src, candidate) { continue } - MOVL (DX)(R15*1), BX - CMPL R14, BX - JEQ inner1 - - // nextHash = hash(uint32(x>>16), shift) - SHRQ $8, R14 - MOVL R14, R11 - IMULL $0x1e35a7bd, R11 - SHRL CX, R11 - - // s++ - ADDQ $1, SI - - // break out of the inner1 for loop, i.e. continue the outer loop. - JMP outer - -emitRemainder: - // if nextEmit < len(src) { etc } - MOVQ src_len+32(FP), AX - ADDQ DX, AX - CMPQ R10, AX - JEQ encodeBlockEnd - - // d += emitLiteral(dst[d:], src[nextEmit:]) - // - // Push args. - MOVQ DI, 0(SP) - MOVQ $0, 8(SP) // Unnecessary, as the callee ignores it, but conservative. - MOVQ $0, 16(SP) // Unnecessary, as the callee ignores it, but conservative. - MOVQ R10, 24(SP) - SUBQ R10, AX - MOVQ AX, 32(SP) - MOVQ AX, 40(SP) // Unnecessary, as the callee ignores it, but conservative. - - // Spill local variables (registers) onto the stack; call; unspill. - MOVQ DI, 80(SP) - CALL ·emitLiteral(SB) - MOVQ 80(SP), DI - - // Finish the "d +=" part of "d += emitLiteral(etc)". - ADDQ 48(SP), DI - -encodeBlockEnd: - MOVQ dst_base+0(FP), AX - SUBQ AX, DI - MOVQ DI, d+48(FP) - RET diff --git a/vender/github.com/golang/snappy/encode_other.go b/vender/github.com/golang/snappy/encode_other.go deleted file mode 100644 index dbcae90..0000000 --- a/vender/github.com/golang/snappy/encode_other.go +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2016 The Snappy-Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !amd64 appengine !gc noasm - -package snappy - -func load32(b []byte, i int) uint32 { - b = b[i : i+4 : len(b)] // Help the compiler eliminate bounds checks on the next line. - return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 -} - -func load64(b []byte, i int) uint64 { - b = b[i : i+8 : len(b)] // Help the compiler eliminate bounds checks on the next line. - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | - uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 -} - -// emitLiteral writes a literal chunk and returns the number of bytes written. -// -// It assumes that: -// dst is long enough to hold the encoded bytes -// 1 <= len(lit) && len(lit) <= 65536 -func emitLiteral(dst, lit []byte) int { - i, n := 0, uint(len(lit)-1) - switch { - case n < 60: - dst[0] = uint8(n)<<2 | tagLiteral - i = 1 - case n < 1<<8: - dst[0] = 60<<2 | tagLiteral - dst[1] = uint8(n) - i = 2 - default: - dst[0] = 61<<2 | tagLiteral - dst[1] = uint8(n) - dst[2] = uint8(n >> 8) - i = 3 - } - return i + copy(dst[i:], lit) -} - -// emitCopy writes a copy chunk and returns the number of bytes written. -// -// It assumes that: -// dst is long enough to hold the encoded bytes -// 1 <= offset && offset <= 65535 -// 4 <= length && length <= 65535 -func emitCopy(dst []byte, offset, length int) int { - i := 0 - // The maximum length for a single tagCopy1 or tagCopy2 op is 64 bytes. The - // threshold for this loop is a little higher (at 68 = 64 + 4), and the - // length emitted down below is is a little lower (at 60 = 64 - 4), because - // it's shorter to encode a length 67 copy as a length 60 tagCopy2 followed - // by a length 7 tagCopy1 (which encodes as 3+2 bytes) than to encode it as - // a length 64 tagCopy2 followed by a length 3 tagCopy2 (which encodes as - // 3+3 bytes). The magic 4 in the 64±4 is because the minimum length for a - // tagCopy1 op is 4 bytes, which is why a length 3 copy has to be an - // encodes-as-3-bytes tagCopy2 instead of an encodes-as-2-bytes tagCopy1. - for length >= 68 { - // Emit a length 64 copy, encoded as 3 bytes. - dst[i+0] = 63<<2 | tagCopy2 - dst[i+1] = uint8(offset) - dst[i+2] = uint8(offset >> 8) - i += 3 - length -= 64 - } - if length > 64 { - // Emit a length 60 copy, encoded as 3 bytes. - dst[i+0] = 59<<2 | tagCopy2 - dst[i+1] = uint8(offset) - dst[i+2] = uint8(offset >> 8) - i += 3 - length -= 60 - } - if length >= 12 || offset >= 2048 { - // Emit the remaining copy, encoded as 3 bytes. - dst[i+0] = uint8(length-1)<<2 | tagCopy2 - dst[i+1] = uint8(offset) - dst[i+2] = uint8(offset >> 8) - return i + 3 - } - // Emit the remaining copy, encoded as 2 bytes. - dst[i+0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1 - dst[i+1] = uint8(offset) - return i + 2 -} - -// extendMatch returns the largest k such that k <= len(src) and that -// src[i:i+k-j] and src[j:k] have the same contents. -// -// It assumes that: -// 0 <= i && i < j && j <= len(src) -func extendMatch(src []byte, i, j int) int { - for ; j < len(src) && src[i] == src[j]; i, j = i+1, j+1 { - } - return j -} - -func hash(u, shift uint32) uint32 { - return (u * 0x1e35a7bd) >> shift -} - -// encodeBlock encodes a non-empty src to a guaranteed-large-enough dst. It -// assumes that the varint-encoded length of the decompressed bytes has already -// been written. -// -// It also assumes that: -// len(dst) >= MaxEncodedLen(len(src)) && -// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize -func encodeBlock(dst, src []byte) (d int) { - // Initialize the hash table. Its size ranges from 1<<8 to 1<<14 inclusive. - // The table element type is uint16, as s < sLimit and sLimit < len(src) - // and len(src) <= maxBlockSize and maxBlockSize == 65536. - const ( - maxTableSize = 1 << 14 - // tableMask is redundant, but helps the compiler eliminate bounds - // checks. - tableMask = maxTableSize - 1 - ) - shift := uint32(32 - 8) - for tableSize := 1 << 8; tableSize < maxTableSize && tableSize < len(src); tableSize *= 2 { - shift-- - } - // In Go, all array elements are zero-initialized, so there is no advantage - // to a smaller tableSize per se. However, it matches the C++ algorithm, - // and in the asm versions of this code, we can get away with zeroing only - // the first tableSize elements. - var table [maxTableSize]uint16 - - // sLimit is when to stop looking for offset/length copies. The inputMargin - // lets us use a fast path for emitLiteral in the main loop, while we are - // looking for copies. - sLimit := len(src) - inputMargin - - // nextEmit is where in src the next emitLiteral should start from. - nextEmit := 0 - - // The encoded form must start with a literal, as there are no previous - // bytes to copy, so we start looking for hash matches at s == 1. - s := 1 - nextHash := hash(load32(src, s), shift) - - for { - // Copied from the C++ snappy implementation: - // - // Heuristic match skipping: If 32 bytes are scanned with no matches - // found, start looking only at every other byte. If 32 more bytes are - // scanned (or skipped), look at every third byte, etc.. When a match - // is found, immediately go back to looking at every byte. This is a - // small loss (~5% performance, ~0.1% density) for compressible data - // due to more bookkeeping, but for non-compressible data (such as - // JPEG) it's a huge win since the compressor quickly "realizes" the - // data is incompressible and doesn't bother looking for matches - // everywhere. - // - // The "skip" variable keeps track of how many bytes there are since - // the last match; dividing it by 32 (ie. right-shifting by five) gives - // the number of bytes to move ahead for each iteration. - skip := 32 - - nextS := s - candidate := 0 - for { - s = nextS - bytesBetweenHashLookups := skip >> 5 - nextS = s + bytesBetweenHashLookups - skip += bytesBetweenHashLookups - if nextS > sLimit { - goto emitRemainder - } - candidate = int(table[nextHash&tableMask]) - table[nextHash&tableMask] = uint16(s) - nextHash = hash(load32(src, nextS), shift) - if load32(src, s) == load32(src, candidate) { - break - } - } - - // A 4-byte match has been found. We'll later see if more than 4 bytes - // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit - // them as literal bytes. - d += emitLiteral(dst[d:], src[nextEmit:s]) - - // Call emitCopy, and then see if another emitCopy could be our next - // move. Repeat until we find no match for the input immediately after - // what was consumed by the last emitCopy call. - // - // If we exit this loop normally then we need to call emitLiteral next, - // though we don't yet know how big the literal will be. We handle that - // by proceeding to the next iteration of the main loop. We also can - // exit this loop via goto if we get close to exhausting the input. - for { - // Invariant: we have a 4-byte match at s, and no need to emit any - // literal bytes prior to s. - base := s - - // Extend the 4-byte match as long as possible. - // - // This is an inlined version of: - // s = extendMatch(src, candidate+4, s+4) - s += 4 - for i := candidate + 4; s < len(src) && src[i] == src[s]; i, s = i+1, s+1 { - } - - d += emitCopy(dst[d:], base-candidate, s-base) - nextEmit = s - if s >= sLimit { - goto emitRemainder - } - - // We could immediately start working at s now, but to improve - // compression we first update the hash table at s-1 and at s. If - // another emitCopy is not our next move, also calculate nextHash - // at s+1. At least on GOARCH=amd64, these three hash calculations - // are faster as one load64 call (with some shifts) instead of - // three load32 calls. - x := load64(src, s-1) - prevHash := hash(uint32(x>>0), shift) - table[prevHash&tableMask] = uint16(s - 1) - currHash := hash(uint32(x>>8), shift) - candidate = int(table[currHash&tableMask]) - table[currHash&tableMask] = uint16(s) - if uint32(x>>8) != load32(src, candidate) { - nextHash = hash(uint32(x>>16), shift) - s++ - break - } - } - } - -emitRemainder: - if nextEmit < len(src) { - d += emitLiteral(dst[d:], src[nextEmit:]) - } - return d -} diff --git a/vender/github.com/golang/snappy/golden_test.go b/vender/github.com/golang/snappy/golden_test.go deleted file mode 100644 index e4496f9..0000000 --- a/vender/github.com/golang/snappy/golden_test.go +++ /dev/null @@ -1,1965 +0,0 @@ -// Copyright 2016 The Snappy-Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package snappy - -// extendMatchGoldenTestCases is the i and j arguments, and the returned value, -// for every extendMatch call issued when encoding the -// testdata/Mark.Twain-Tom.Sawyer.txt file. It is used to benchmark the -// extendMatch implementation. -// -// It was generated manually by adding some print statements to the (pure Go) -// extendMatch implementation: -// -// func extendMatch(src []byte, i, j int) int { -// i0, j0 := i, j -// for ; j < len(src) && src[i] == src[j]; i, j = i+1, j+1 { -// } -// println("{", i0, ",", j0, ",", j, "},") -// return j -// } -// -// and running "go test -test.run=EncodeGoldenInput -tags=noasm". -var extendMatchGoldenTestCases = []struct { - i, j, want int -}{ - {11, 61, 62}, - {80, 81, 82}, - {86, 87, 101}, - {85, 133, 149}, - {152, 153, 162}, - {133, 168, 193}, - {168, 207, 225}, - {81, 255, 275}, - {278, 279, 283}, - {306, 417, 417}, - {373, 428, 430}, - {389, 444, 447}, - {474, 510, 512}, - {465, 533, 533}, - {47, 547, 547}, - {307, 551, 554}, - {420, 582, 587}, - {309, 604, 604}, - {604, 625, 625}, - {538, 629, 629}, - {328, 640, 640}, - {573, 645, 645}, - {319, 657, 657}, - {30, 664, 664}, - {45, 679, 680}, - {621, 684, 684}, - {376, 700, 700}, - {33, 707, 708}, - {601, 733, 733}, - {334, 744, 745}, - {625, 758, 759}, - {382, 763, 763}, - {550, 769, 771}, - {533, 789, 789}, - {804, 813, 813}, - {342, 841, 842}, - {742, 847, 847}, - {74, 852, 852}, - {810, 864, 864}, - {758, 868, 869}, - {714, 883, 883}, - {582, 889, 891}, - {61, 934, 935}, - {894, 942, 942}, - {939, 949, 949}, - {785, 956, 957}, - {886, 978, 978}, - {792, 998, 998}, - {998, 1005, 1005}, - {572, 1032, 1032}, - {698, 1051, 1053}, - {599, 1067, 1069}, - {1056, 1079, 1079}, - {942, 1089, 1090}, - {831, 1094, 1096}, - {1088, 1100, 1103}, - {732, 1113, 1114}, - {1037, 1118, 1118}, - {872, 1128, 1130}, - {1079, 1140, 1142}, - {332, 1162, 1162}, - {207, 1168, 1186}, - {1189, 1190, 1225}, - {105, 1229, 1230}, - {79, 1256, 1257}, - {1190, 1261, 1283}, - {255, 1306, 1306}, - {1319, 1339, 1358}, - {364, 1370, 1370}, - {955, 1378, 1380}, - {122, 1403, 1403}, - {1325, 1407, 1419}, - {664, 1423, 1424}, - {941, 1461, 1463}, - {867, 1477, 1478}, - {757, 1488, 1489}, - {1140, 1499, 1499}, - {31, 1506, 1506}, - {1487, 1510, 1512}, - {1089, 1520, 1521}, - {1467, 1525, 1529}, - {1394, 1537, 1537}, - {1499, 1541, 1541}, - {367, 1558, 1558}, - {1475, 1564, 1564}, - {1525, 1568, 1571}, - {1541, 1582, 1583}, - {864, 1587, 1588}, - {704, 1597, 1597}, - {336, 1602, 1602}, - {1383, 1613, 1613}, - {1498, 1617, 1618}, - {1051, 1623, 1625}, - {401, 1643, 1645}, - {1072, 1654, 1655}, - {1067, 1667, 1669}, - {699, 1673, 1674}, - {1587, 1683, 1684}, - {920, 1696, 1696}, - {1505, 1710, 1710}, - {1550, 1723, 1723}, - {996, 1727, 1727}, - {833, 1733, 1734}, - {1638, 1739, 1740}, - {1654, 1744, 1744}, - {753, 1761, 1761}, - {1548, 1773, 1773}, - {1568, 1777, 1780}, - {1683, 1793, 1794}, - {948, 1801, 1801}, - {1666, 1805, 1808}, - {1502, 1814, 1814}, - {1696, 1822, 1822}, - {502, 1836, 1837}, - {917, 1843, 1843}, - {1733, 1854, 1855}, - {970, 1859, 1859}, - {310, 1863, 1863}, - {657, 1872, 1872}, - {1005, 1876, 1876}, - {1662, 1880, 1880}, - {904, 1892, 1892}, - {1427, 1910, 1910}, - {1772, 1929, 1930}, - {1822, 1937, 1940}, - {1858, 1949, 1950}, - {1602, 1956, 1956}, - {1150, 1962, 1962}, - {1504, 1966, 1967}, - {51, 1971, 1971}, - {1605, 1979, 1979}, - {1458, 1983, 1988}, - {1536, 2001, 2006}, - {1373, 2014, 2018}, - {1494, 2025, 2025}, - {1667, 2029, 2031}, - {1592, 2035, 2035}, - {330, 2045, 2045}, - {1376, 2053, 2053}, - {1991, 2058, 2059}, - {1635, 2065, 2065}, - {1992, 2073, 2074}, - {2014, 2080, 2081}, - {1546, 2085, 2087}, - {59, 2099, 2099}, - {1996, 2106, 2106}, - {1836, 2110, 2110}, - {2068, 2114, 2114}, - {1338, 2122, 2122}, - {1562, 2128, 2130}, - {1934, 2134, 2134}, - {2114, 2141, 2142}, - {977, 2149, 2150}, - {956, 2154, 2155}, - {1407, 2162, 2162}, - {1773, 2166, 2166}, - {883, 2171, 2171}, - {623, 2175, 2178}, - {1520, 2191, 2192}, - {1162, 2200, 2200}, - {912, 2204, 2204}, - {733, 2208, 2208}, - {1777, 2212, 2215}, - {1532, 2219, 2219}, - {718, 2223, 2225}, - {2069, 2229, 2229}, - {2207, 2245, 2246}, - {1139, 2264, 2264}, - {677, 2274, 2274}, - {2099, 2279, 2279}, - {1863, 2283, 2283}, - {1966, 2305, 2306}, - {2279, 2313, 2313}, - {1628, 2319, 2319}, - {755, 2329, 2329}, - {1461, 2334, 2334}, - {2117, 2340, 2340}, - {2313, 2349, 2349}, - {1859, 2353, 2353}, - {1048, 2362, 2362}, - {895, 2366, 2366}, - {2278, 2373, 2373}, - {1884, 2377, 2377}, - {1402, 2387, 2392}, - {700, 2398, 2398}, - {1971, 2402, 2402}, - {2009, 2419, 2419}, - {1441, 2426, 2428}, - {2208, 2432, 2432}, - {2038, 2436, 2436}, - {932, 2443, 2443}, - {1759, 2447, 2448}, - {744, 2452, 2452}, - {1875, 2458, 2458}, - {2405, 2468, 2468}, - {1596, 2472, 2473}, - {1953, 2480, 2482}, - {736, 2487, 2487}, - {1913, 2493, 2493}, - {774, 2497, 2497}, - {1484, 2506, 2508}, - {2432, 2512, 2512}, - {752, 2519, 2519}, - {2497, 2523, 2523}, - {2409, 2528, 2529}, - {2122, 2533, 2533}, - {2396, 2537, 2538}, - {2410, 2547, 2548}, - {1093, 2555, 2560}, - {551, 2564, 2565}, - {2268, 2569, 2569}, - {1362, 2580, 2580}, - {1916, 2584, 2585}, - {994, 2589, 2590}, - {1979, 2596, 2596}, - {1041, 2602, 2602}, - {2104, 2614, 2616}, - {2609, 2621, 2628}, - {2329, 2638, 2638}, - {2211, 2657, 2658}, - {2638, 2662, 2667}, - {2578, 2676, 2679}, - {2153, 2685, 2686}, - {2608, 2696, 2697}, - {598, 2712, 2712}, - {2620, 2719, 2720}, - {1888, 2724, 2728}, - {2709, 2732, 2732}, - {1365, 2739, 2739}, - {784, 2747, 2748}, - {424, 2753, 2753}, - {2204, 2759, 2759}, - {812, 2768, 2769}, - {2455, 2773, 2773}, - {1722, 2781, 2781}, - {1917, 2792, 2792}, - {2705, 2799, 2799}, - {2685, 2806, 2807}, - {2742, 2811, 2811}, - {1370, 2818, 2818}, - {2641, 2830, 2830}, - {2512, 2837, 2837}, - {2457, 2841, 2841}, - {2756, 2845, 2845}, - {2719, 2855, 2855}, - {1423, 2859, 2859}, - {2849, 2863, 2865}, - {1474, 2871, 2871}, - {1161, 2875, 2876}, - {2282, 2880, 2881}, - {2746, 2888, 2888}, - {1783, 2893, 2893}, - {2401, 2899, 2900}, - {2632, 2920, 2923}, - {2422, 2928, 2930}, - {2715, 2939, 2939}, - {2162, 2943, 2943}, - {2859, 2947, 2947}, - {1910, 2951, 2951}, - {1431, 2955, 2956}, - {1439, 2964, 2964}, - {2501, 2968, 2969}, - {2029, 2973, 2976}, - {689, 2983, 2984}, - {1658, 2988, 2988}, - {1031, 2996, 2996}, - {2149, 3001, 3002}, - {25, 3009, 3013}, - {2964, 3023, 3023}, - {953, 3027, 3028}, - {2359, 3036, 3036}, - {3023, 3049, 3049}, - {2880, 3055, 3056}, - {2973, 3076, 3077}, - {2874, 3090, 3090}, - {2871, 3094, 3094}, - {2532, 3100, 3100}, - {2938, 3107, 3108}, - {350, 3115, 3115}, - {2196, 3119, 3121}, - {1133, 3127, 3129}, - {1797, 3134, 3150}, - {3032, 3158, 3158}, - {3016, 3172, 3172}, - {2533, 3179, 3179}, - {3055, 3187, 3188}, - {1384, 3192, 3193}, - {2799, 3199, 3199}, - {2126, 3203, 3207}, - {2334, 3215, 3215}, - {2105, 3220, 3221}, - {3199, 3229, 3229}, - {2891, 3233, 3233}, - {855, 3240, 3240}, - {1852, 3253, 3256}, - {2140, 3263, 3263}, - {1682, 3268, 3270}, - {3243, 3274, 3274}, - {924, 3279, 3279}, - {2212, 3283, 3283}, - {2596, 3287, 3287}, - {2999, 3291, 3291}, - {2353, 3295, 3295}, - {2480, 3302, 3304}, - {1959, 3308, 3311}, - {3000, 3318, 3318}, - {845, 3330, 3330}, - {2283, 3334, 3334}, - {2519, 3342, 3342}, - {3325, 3346, 3348}, - {2397, 3353, 3354}, - {2763, 3358, 3358}, - {3198, 3363, 3364}, - {3211, 3368, 3372}, - {2950, 3376, 3377}, - {3245, 3388, 3391}, - {2264, 3398, 3398}, - {795, 3403, 3403}, - {3287, 3407, 3407}, - {3358, 3411, 3411}, - {3317, 3415, 3415}, - {3232, 3431, 3431}, - {2128, 3435, 3437}, - {3236, 3441, 3441}, - {3398, 3445, 3446}, - {2814, 3450, 3450}, - {3394, 3466, 3466}, - {2425, 3470, 3470}, - {3330, 3476, 3476}, - {1612, 3480, 3480}, - {1004, 3485, 3486}, - {2732, 3490, 3490}, - {1117, 3494, 3495}, - {629, 3501, 3501}, - {3087, 3514, 3514}, - {684, 3518, 3518}, - {3489, 3522, 3524}, - {1760, 3529, 3529}, - {617, 3537, 3537}, - {3431, 3541, 3541}, - {997, 3547, 3547}, - {882, 3552, 3553}, - {2419, 3558, 3558}, - {610, 3562, 3563}, - {1903, 3567, 3569}, - {3005, 3575, 3575}, - {3076, 3585, 3586}, - {3541, 3590, 3590}, - {3490, 3594, 3594}, - {1899, 3599, 3599}, - {3545, 3606, 3606}, - {3290, 3614, 3615}, - {2056, 3619, 3620}, - {3556, 3625, 3625}, - {3294, 3632, 3633}, - {637, 3643, 3644}, - {3609, 3648, 3650}, - {3175, 3658, 3658}, - {3498, 3665, 3665}, - {1597, 3669, 3669}, - {1983, 3673, 3673}, - {3215, 3682, 3682}, - {3544, 3689, 3689}, - {3694, 3698, 3698}, - {3228, 3715, 3716}, - {2594, 3720, 3722}, - {3573, 3726, 3726}, - {2479, 3732, 3735}, - {3191, 3741, 3742}, - {1113, 3746, 3747}, - {2844, 3751, 3751}, - {3445, 3756, 3757}, - {3755, 3766, 3766}, - {3421, 3775, 3780}, - {3593, 3784, 3786}, - {3263, 3796, 3796}, - {3469, 3806, 3806}, - {2602, 3815, 3815}, - {723, 3819, 3821}, - {1608, 3826, 3826}, - {3334, 3830, 3830}, - {2198, 3835, 3835}, - {2635, 3840, 3840}, - {3702, 3852, 3853}, - {3406, 3858, 3859}, - {3681, 3867, 3870}, - {3407, 3880, 3880}, - {340, 3889, 3889}, - {3772, 3893, 3893}, - {593, 3897, 3897}, - {2563, 3914, 3916}, - {2981, 3929, 3929}, - {1835, 3933, 3934}, - {3906, 3951, 3951}, - {1459, 3958, 3958}, - {3889, 3974, 3974}, - {2188, 3982, 3982}, - {3220, 3986, 3987}, - {3585, 3991, 3993}, - {3712, 3997, 4001}, - {2805, 4007, 4007}, - {1879, 4012, 4013}, - {3618, 4018, 4018}, - {1145, 4031, 4032}, - {3901, 4037, 4037}, - {2772, 4046, 4047}, - {2802, 4053, 4054}, - {3299, 4058, 4058}, - {3725, 4066, 4066}, - {2271, 4070, 4070}, - {385, 4075, 4076}, - {3624, 4089, 4090}, - {3745, 4096, 4098}, - {1563, 4102, 4102}, - {4045, 4106, 4111}, - {3696, 4115, 4119}, - {3376, 4125, 4126}, - {1880, 4130, 4130}, - {2048, 4140, 4141}, - {2724, 4149, 4149}, - {1767, 4156, 4156}, - {2601, 4164, 4164}, - {2757, 4168, 4168}, - {3974, 4172, 4172}, - {3914, 4178, 4178}, - {516, 4185, 4185}, - {1032, 4189, 4190}, - {3462, 4197, 4198}, - {3805, 4202, 4203}, - {3910, 4207, 4212}, - {3075, 4221, 4221}, - {3756, 4225, 4226}, - {1872, 4236, 4237}, - {3844, 4241, 4241}, - {3991, 4245, 4249}, - {2203, 4258, 4258}, - {3903, 4267, 4268}, - {705, 4272, 4272}, - {1896, 4276, 4276}, - {1955, 4285, 4288}, - {3746, 4302, 4303}, - {2672, 4311, 4311}, - {3969, 4317, 4317}, - {3883, 4322, 4322}, - {1920, 4339, 4340}, - {3527, 4344, 4346}, - {1160, 4358, 4358}, - {3648, 4364, 4366}, - {2711, 4387, 4387}, - {3619, 4391, 4392}, - {1944, 4396, 4396}, - {4369, 4400, 4400}, - {2736, 4404, 4407}, - {2546, 4411, 4412}, - {4390, 4422, 4422}, - {3610, 4426, 4427}, - {4058, 4431, 4431}, - {4374, 4435, 4435}, - {3463, 4445, 4446}, - {1813, 4452, 4452}, - {3669, 4456, 4456}, - {3830, 4460, 4460}, - {421, 4464, 4465}, - {1719, 4471, 4471}, - {3880, 4475, 4475}, - {1834, 4485, 4487}, - {3590, 4491, 4491}, - {442, 4496, 4497}, - {4435, 4501, 4501}, - {3814, 4509, 4509}, - {987, 4513, 4513}, - {4494, 4518, 4521}, - {3218, 4526, 4529}, - {4221, 4537, 4537}, - {2778, 4543, 4545}, - {4422, 4552, 4552}, - {4031, 4558, 4559}, - {4178, 4563, 4563}, - {3726, 4567, 4574}, - {4027, 4578, 4578}, - {4339, 4585, 4587}, - {3796, 4592, 4595}, - {543, 4600, 4613}, - {2855, 4620, 4621}, - {2795, 4627, 4627}, - {3440, 4631, 4632}, - {4279, 4636, 4639}, - {4245, 4643, 4645}, - {4516, 4649, 4650}, - {3133, 4654, 4654}, - {4042, 4658, 4659}, - {3422, 4663, 4663}, - {4046, 4667, 4668}, - {4267, 4672, 4672}, - {4004, 4676, 4677}, - {2490, 4682, 4682}, - {2451, 4697, 4697}, - {3027, 4705, 4705}, - {4028, 4717, 4717}, - {4460, 4721, 4721}, - {2471, 4725, 4727}, - {3090, 4735, 4735}, - {3192, 4739, 4740}, - {3835, 4760, 4760}, - {4540, 4764, 4764}, - {4007, 4772, 4774}, - {619, 4784, 4784}, - {3561, 4789, 4791}, - {3367, 4805, 4805}, - {4490, 4810, 4811}, - {2402, 4815, 4815}, - {3352, 4819, 4822}, - {2773, 4828, 4828}, - {4552, 4832, 4832}, - {2522, 4840, 4841}, - {316, 4847, 4852}, - {4715, 4858, 4858}, - {2959, 4862, 4862}, - {4858, 4868, 4869}, - {2134, 4873, 4873}, - {578, 4878, 4878}, - {4189, 4889, 4890}, - {2229, 4894, 4894}, - {4501, 4898, 4898}, - {2297, 4903, 4903}, - {2933, 4909, 4909}, - {3008, 4913, 4913}, - {3153, 4917, 4917}, - {4819, 4921, 4921}, - {4921, 4932, 4933}, - {4920, 4944, 4945}, - {4814, 4954, 4955}, - {576, 4966, 4966}, - {1854, 4970, 4971}, - {1374, 4975, 4976}, - {3307, 4980, 4980}, - {974, 4984, 4988}, - {4721, 4992, 4992}, - {4898, 4996, 4996}, - {4475, 5006, 5006}, - {3819, 5012, 5012}, - {1948, 5019, 5021}, - {4954, 5027, 5029}, - {3740, 5038, 5040}, - {4763, 5044, 5045}, - {1936, 5051, 5051}, - {4844, 5055, 5060}, - {4215, 5069, 5072}, - {1146, 5076, 5076}, - {3845, 5082, 5082}, - {4865, 5090, 5090}, - {4624, 5094, 5094}, - {4815, 5098, 5098}, - {5006, 5105, 5105}, - {4980, 5109, 5109}, - {4795, 5113, 5115}, - {5043, 5119, 5121}, - {4782, 5129, 5129}, - {3826, 5139, 5139}, - {3876, 5156, 5156}, - {3111, 5167, 5171}, - {1470, 5177, 5177}, - {4431, 5181, 5181}, - {546, 5189, 5189}, - {4225, 5193, 5193}, - {1672, 5199, 5201}, - {4207, 5205, 5209}, - {4220, 5216, 5217}, - {4658, 5224, 5225}, - {3295, 5235, 5235}, - {2436, 5239, 5239}, - {2349, 5246, 5246}, - {2175, 5250, 5250}, - {5180, 5257, 5258}, - {3161, 5263, 5263}, - {5105, 5272, 5272}, - {3552, 5282, 5282}, - {4944, 5299, 5300}, - {4130, 5312, 5313}, - {902, 5323, 5323}, - {913, 5327, 5327}, - {2987, 5333, 5334}, - {5150, 5344, 5344}, - {5249, 5348, 5348}, - {1965, 5358, 5359}, - {5330, 5364, 5364}, - {2012, 5373, 5377}, - {712, 5384, 5386}, - {5235, 5390, 5390}, - {5044, 5398, 5399}, - {564, 5406, 5406}, - {39, 5410, 5410}, - {4642, 5422, 5425}, - {4421, 5437, 5438}, - {2347, 5449, 5449}, - {5333, 5453, 5454}, - {4136, 5458, 5459}, - {3793, 5468, 5468}, - {2243, 5480, 5480}, - {4889, 5492, 5493}, - {4295, 5504, 5504}, - {2785, 5511, 5511}, - {2377, 5518, 5518}, - {3662, 5525, 5525}, - {5097, 5529, 5530}, - {4781, 5537, 5538}, - {4697, 5547, 5548}, - {436, 5552, 5553}, - {5542, 5558, 5558}, - {3692, 5562, 5562}, - {2696, 5568, 5569}, - {4620, 5578, 5578}, - {2898, 5590, 5590}, - {5557, 5596, 5618}, - {2797, 5623, 5625}, - {2792, 5629, 5629}, - {5243, 5633, 5633}, - {5348, 5637, 5637}, - {5547, 5643, 5643}, - {4296, 5654, 5655}, - {5568, 5662, 5662}, - {3001, 5670, 5671}, - {3794, 5679, 5679}, - {4006, 5685, 5686}, - {4969, 5690, 5692}, - {687, 5704, 5704}, - {4563, 5708, 5708}, - {1723, 5738, 5738}, - {649, 5742, 5742}, - {5163, 5748, 5755}, - {3907, 5759, 5759}, - {3074, 5764, 5764}, - {5326, 5771, 5771}, - {2951, 5776, 5776}, - {5181, 5780, 5780}, - {2614, 5785, 5788}, - {4709, 5794, 5794}, - {2784, 5799, 5799}, - {5518, 5803, 5803}, - {4155, 5812, 5815}, - {921, 5819, 5819}, - {5224, 5823, 5824}, - {2853, 5830, 5836}, - {5776, 5840, 5840}, - {2955, 5844, 5845}, - {5745, 5853, 5853}, - {3291, 5857, 5857}, - {2988, 5861, 5861}, - {2647, 5865, 5865}, - {5398, 5869, 5870}, - {1085, 5874, 5875}, - {4906, 5881, 5881}, - {802, 5886, 5886}, - {5119, 5890, 5893}, - {5802, 5899, 5900}, - {3415, 5904, 5904}, - {5629, 5908, 5908}, - {3714, 5912, 5914}, - {5558, 5921, 5921}, - {2710, 5927, 5928}, - {1094, 5932, 5934}, - {2653, 5940, 5941}, - {4735, 5954, 5954}, - {5861, 5958, 5958}, - {1040, 5971, 5971}, - {5514, 5977, 5977}, - {5048, 5981, 5982}, - {5953, 5992, 5993}, - {3751, 5997, 5997}, - {4991, 6001, 6002}, - {5885, 6006, 6007}, - {5529, 6011, 6012}, - {4974, 6019, 6020}, - {5857, 6024, 6024}, - {3483, 6032, 6032}, - {3594, 6036, 6036}, - {1997, 6040, 6040}, - {5997, 6044, 6047}, - {5197, 6051, 6051}, - {1764, 6055, 6055}, - {6050, 6059, 6059}, - {5239, 6063, 6063}, - {5049, 6067, 6067}, - {5957, 6073, 6074}, - {1022, 6078, 6078}, - {3414, 6083, 6084}, - {3809, 6090, 6090}, - {4562, 6095, 6096}, - {5878, 6104, 6104}, - {594, 6108, 6109}, - {3353, 6115, 6116}, - {4992, 6120, 6121}, - {2424, 6125, 6125}, - {4484, 6130, 6130}, - {3900, 6134, 6135}, - {5793, 6139, 6141}, - {3562, 6145, 6145}, - {1438, 6152, 6153}, - {6058, 6157, 6158}, - {4411, 6162, 6163}, - {4590, 6167, 6171}, - {4748, 6175, 6175}, - {5517, 6183, 6184}, - {6095, 6191, 6192}, - {1471, 6203, 6203}, - {2643, 6209, 6210}, - {450, 6220, 6220}, - {5266, 6226, 6226}, - {2576, 6233, 6233}, - {2607, 6239, 6240}, - {5164, 6244, 6251}, - {6054, 6255, 6255}, - {1789, 6260, 6261}, - {5250, 6265, 6265}, - {6062, 6273, 6278}, - {5990, 6282, 6282}, - {3283, 6286, 6286}, - {5436, 6290, 6290}, - {6059, 6294, 6294}, - {5668, 6298, 6300}, - {3072, 6324, 6329}, - {3132, 6338, 6339}, - {3246, 6343, 6344}, - {28, 6348, 6349}, - {1503, 6353, 6355}, - {6067, 6359, 6359}, - {3384, 6364, 6364}, - {545, 6375, 6376}, - {5803, 6380, 6380}, - {5522, 6384, 6385}, - {5908, 6389, 6389}, - {2796, 6393, 6396}, - {4831, 6403, 6404}, - {6388, 6412, 6412}, - {6005, 6417, 6420}, - {4450, 6430, 6430}, - {4050, 6435, 6435}, - {5372, 6441, 6441}, - {4378, 6447, 6447}, - {6199, 6452, 6452}, - {3026, 6456, 6456}, - {2642, 6460, 6462}, - {6392, 6470, 6470}, - {6459, 6474, 6474}, - {2829, 6487, 6488}, - {2942, 6499, 6504}, - {5069, 6508, 6511}, - {5341, 6515, 6516}, - {5853, 6521, 6525}, - {6104, 6531, 6531}, - {5759, 6535, 6538}, - {4672, 6542, 6543}, - {2443, 6550, 6550}, - {5109, 6554, 6554}, - {6494, 6558, 6560}, - {6006, 6570, 6572}, - {6424, 6576, 6580}, - {4693, 6591, 6592}, - {6439, 6596, 6597}, - {3179, 6601, 6601}, - {5299, 6606, 6607}, - {4148, 6612, 6613}, - {3774, 6617, 6617}, - {3537, 6623, 6624}, - {4975, 6628, 6629}, - {3848, 6636, 6636}, - {856, 6640, 6640}, - {5724, 6645, 6645}, - {6632, 6651, 6651}, - {4630, 6656, 6658}, - {1440, 6662, 6662}, - {4281, 6666, 6667}, - {4302, 6671, 6672}, - {2589, 6676, 6677}, - {5647, 6681, 6687}, - {6082, 6691, 6693}, - {6144, 6698, 6698}, - {6103, 6709, 6710}, - {3710, 6714, 6714}, - {4253, 6718, 6721}, - {2467, 6730, 6730}, - {4778, 6734, 6734}, - {6528, 6738, 6738}, - {4358, 6747, 6747}, - {5889, 6753, 6753}, - {5193, 6757, 6757}, - {5797, 6761, 6761}, - {3858, 6765, 6766}, - {5951, 6776, 6776}, - {6487, 6781, 6782}, - {3282, 6786, 6787}, - {4667, 6797, 6799}, - {1927, 6803, 6806}, - {6583, 6810, 6810}, - {4937, 6814, 6814}, - {6099, 6824, 6824}, - {4415, 6835, 6836}, - {6332, 6840, 6841}, - {5160, 6850, 6850}, - {4764, 6854, 6854}, - {6814, 6858, 6859}, - {3018, 6864, 6864}, - {6293, 6868, 6869}, - {6359, 6877, 6877}, - {3047, 6884, 6886}, - {5262, 6890, 6891}, - {5471, 6900, 6900}, - {3268, 6910, 6912}, - {1047, 6916, 6916}, - {5904, 6923, 6923}, - {5798, 6933, 6938}, - {4149, 6942, 6942}, - {1821, 6946, 6946}, - {3599, 6952, 6952}, - {6470, 6957, 6957}, - {5562, 6961, 6961}, - {6268, 6965, 6967}, - {6389, 6971, 6971}, - {6596, 6975, 6976}, - {6553, 6980, 6981}, - {6576, 6985, 6989}, - {1375, 6993, 6993}, - {652, 6998, 6998}, - {4876, 7002, 7003}, - {5768, 7011, 7013}, - {3973, 7017, 7017}, - {6802, 7025, 7025}, - {6955, 7034, 7036}, - {6974, 7040, 7040}, - {5944, 7044, 7044}, - {6992, 7048, 7054}, - {6872, 7059, 7059}, - {2943, 7063, 7063}, - {6923, 7067, 7067}, - {5094, 7071, 7071}, - {4873, 7075, 7075}, - {5819, 7079, 7079}, - {5945, 7085, 7085}, - {1540, 7090, 7091}, - {2090, 7095, 7095}, - {5024, 7104, 7105}, - {6900, 7109, 7109}, - {6024, 7113, 7114}, - {6000, 7118, 7120}, - {2187, 7124, 7125}, - {6760, 7129, 7130}, - {5898, 7134, 7136}, - {7032, 7144, 7144}, - {4271, 7148, 7148}, - {3706, 7152, 7152}, - {6970, 7156, 7157}, - {7088, 7161, 7163}, - {2718, 7168, 7169}, - {5674, 7175, 7175}, - {4631, 7182, 7182}, - {7070, 7188, 7189}, - {6220, 7196, 7196}, - {3458, 7201, 7202}, - {2041, 7211, 7212}, - {1454, 7216, 7216}, - {5199, 7225, 7227}, - {3529, 7234, 7234}, - {6890, 7238, 7238}, - {3815, 7242, 7243}, - {5490, 7250, 7253}, - {6554, 7257, 7263}, - {5890, 7267, 7269}, - {6877, 7273, 7273}, - {4877, 7277, 7277}, - {2502, 7285, 7285}, - {1483, 7289, 7295}, - {7210, 7304, 7308}, - {6845, 7313, 7316}, - {7219, 7320, 7320}, - {7001, 7325, 7329}, - {6853, 7333, 7334}, - {6120, 7338, 7338}, - {6606, 7342, 7343}, - {7020, 7348, 7350}, - {3509, 7354, 7354}, - {7133, 7359, 7363}, - {3434, 7371, 7374}, - {2787, 7384, 7384}, - {7044, 7388, 7388}, - {6960, 7394, 7395}, - {6676, 7399, 7400}, - {7161, 7404, 7404}, - {7285, 7417, 7418}, - {4558, 7425, 7426}, - {4828, 7430, 7430}, - {6063, 7436, 7436}, - {3597, 7442, 7442}, - {914, 7446, 7446}, - {7320, 7452, 7454}, - {7267, 7458, 7460}, - {5076, 7464, 7464}, - {7430, 7468, 7469}, - {6273, 7473, 7474}, - {7440, 7478, 7487}, - {7348, 7491, 7494}, - {1021, 7510, 7510}, - {7473, 7515, 7515}, - {2823, 7519, 7519}, - {6264, 7527, 7527}, - {7302, 7531, 7531}, - {7089, 7535, 7535}, - {7342, 7540, 7541}, - {3688, 7547, 7551}, - {3054, 7558, 7560}, - {4177, 7566, 7567}, - {6691, 7574, 7575}, - {7156, 7585, 7586}, - {7147, 7590, 7592}, - {7407, 7598, 7598}, - {7403, 7602, 7603}, - {6868, 7607, 7607}, - {6636, 7611, 7611}, - {4805, 7617, 7617}, - {5779, 7623, 7623}, - {7063, 7627, 7627}, - {5079, 7632, 7632}, - {7377, 7637, 7637}, - {7337, 7641, 7642}, - {6738, 7655, 7655}, - {7338, 7659, 7659}, - {6541, 7669, 7671}, - {595, 7675, 7675}, - {7658, 7679, 7680}, - {7647, 7685, 7686}, - {2477, 7690, 7690}, - {5823, 7694, 7694}, - {4156, 7699, 7699}, - {5931, 7703, 7706}, - {6854, 7712, 7712}, - {4931, 7718, 7718}, - {6979, 7722, 7722}, - {5085, 7727, 7727}, - {6965, 7732, 7732}, - {7201, 7736, 7737}, - {3639, 7741, 7743}, - {7534, 7749, 7749}, - {4292, 7753, 7753}, - {3427, 7759, 7763}, - {7273, 7767, 7767}, - {940, 7778, 7778}, - {4838, 7782, 7785}, - {4216, 7790, 7792}, - {922, 7800, 7801}, - {7256, 7810, 7811}, - {7789, 7815, 7819}, - {7225, 7823, 7825}, - {7531, 7829, 7829}, - {6997, 7833, 7833}, - {7757, 7837, 7838}, - {4129, 7842, 7842}, - {7333, 7848, 7849}, - {6776, 7855, 7855}, - {7527, 7859, 7859}, - {4370, 7863, 7863}, - {4512, 7868, 7868}, - {5679, 7880, 7880}, - {3162, 7884, 7885}, - {3933, 7892, 7894}, - {7804, 7899, 7902}, - {6363, 7906, 7907}, - {7848, 7911, 7912}, - {5584, 7917, 7921}, - {874, 7926, 7926}, - {3342, 7930, 7930}, - {4507, 7935, 7937}, - {3672, 7943, 7944}, - {7911, 7948, 7949}, - {6402, 7956, 7956}, - {7940, 7960, 7960}, - {7113, 7964, 7964}, - {1073, 7968, 7968}, - {7740, 7974, 7974}, - {7601, 7978, 7982}, - {6797, 7987, 7988}, - {3528, 7994, 7995}, - {5483, 7999, 7999}, - {5717, 8011, 8011}, - {5480, 8017, 8017}, - {7770, 8023, 8030}, - {2452, 8034, 8034}, - {5282, 8047, 8047}, - {7967, 8051, 8051}, - {1128, 8058, 8066}, - {6348, 8070, 8070}, - {8055, 8077, 8077}, - {7925, 8081, 8086}, - {6810, 8090, 8090}, - {5051, 8101, 8101}, - {4696, 8109, 8110}, - {5129, 8119, 8119}, - {4449, 8123, 8123}, - {7222, 8127, 8127}, - {4649, 8131, 8134}, - {7994, 8138, 8138}, - {5954, 8148, 8148}, - {475, 8152, 8153}, - {7906, 8157, 8157}, - {7458, 8164, 8166}, - {7632, 8171, 8173}, - {3874, 8177, 8183}, - {4391, 8187, 8187}, - {561, 8191, 8191}, - {2417, 8195, 8195}, - {2357, 8204, 8204}, - {2269, 8216, 8218}, - {3968, 8222, 8222}, - {2200, 8226, 8227}, - {3453, 8247, 8247}, - {2439, 8251, 8252}, - {7175, 8257, 8257}, - {976, 8262, 8264}, - {4953, 8273, 8273}, - {4219, 8278, 8278}, - {6, 8285, 8291}, - {5703, 8295, 8296}, - {5272, 8300, 8300}, - {8037, 8304, 8304}, - {8186, 8314, 8314}, - {8304, 8318, 8318}, - {8051, 8326, 8326}, - {8318, 8330, 8330}, - {2671, 8334, 8335}, - {2662, 8339, 8339}, - {8081, 8349, 8350}, - {3328, 8356, 8356}, - {2879, 8360, 8362}, - {8050, 8370, 8371}, - {8330, 8375, 8376}, - {8375, 8386, 8386}, - {4961, 8390, 8390}, - {1017, 8403, 8405}, - {3533, 8416, 8416}, - {4555, 8422, 8422}, - {6445, 8426, 8426}, - {8169, 8432, 8432}, - {990, 8436, 8436}, - {4102, 8440, 8440}, - {7398, 8444, 8446}, - {3480, 8450, 8450}, - {6324, 8462, 8462}, - {7948, 8466, 8467}, - {5950, 8471, 8471}, - {5189, 8476, 8476}, - {4026, 8490, 8490}, - {8374, 8494, 8495}, - {4682, 8501, 8501}, - {7387, 8506, 8506}, - {8164, 8510, 8515}, - {4079, 8524, 8524}, - {8360, 8529, 8531}, - {7446, 8540, 8543}, - {7971, 8547, 8548}, - {4311, 8552, 8552}, - {5204, 8556, 8557}, - {7968, 8562, 8562}, - {7847, 8571, 8573}, - {8547, 8577, 8577}, - {5320, 8581, 8581}, - {8556, 8585, 8586}, - {8504, 8590, 8590}, - {7669, 8602, 8604}, - {5874, 8608, 8609}, - {5828, 8613, 8613}, - {7998, 8617, 8617}, - {8519, 8625, 8625}, - {7250, 8637, 8637}, - {426, 8641, 8641}, - {8436, 8645, 8645}, - {5986, 8649, 8656}, - {8157, 8660, 8660}, - {7182, 8665, 8665}, - {8421, 8675, 8675}, - {8509, 8681, 8681}, - {5137, 8688, 8689}, - {8625, 8694, 8695}, - {5228, 8701, 8702}, - {6661, 8714, 8714}, - {1010, 8719, 8719}, - {6648, 8723, 8723}, - {3500, 8728, 8728}, - {2442, 8735, 8735}, - {8494, 8740, 8741}, - {8171, 8753, 8755}, - {7242, 8763, 8764}, - {4739, 8768, 8769}, - {7079, 8773, 8773}, - {8386, 8777, 8777}, - {8624, 8781, 8787}, - {661, 8791, 8794}, - {8631, 8801, 8801}, - {7753, 8805, 8805}, - {4783, 8809, 8810}, - {1673, 8814, 8815}, - {6623, 8819, 8819}, - {4404, 8823, 8823}, - {8089, 8827, 8828}, - {8773, 8832, 8832}, - {5394, 8836, 8836}, - {6231, 8841, 8843}, - {1015, 8852, 8853}, - {6873, 8857, 8857}, - {6289, 8865, 8865}, - {8577, 8869, 8869}, - {8114, 8873, 8875}, - {8534, 8883, 8883}, - {3007, 8887, 8888}, - {8827, 8892, 8893}, - {4788, 8897, 8900}, - {5698, 8906, 8907}, - {7690, 8911, 8911}, - {6643, 8919, 8919}, - {7206, 8923, 8924}, - {7866, 8929, 8931}, - {8880, 8942, 8942}, - {8630, 8951, 8952}, - {6027, 8958, 8958}, - {7749, 8966, 8967}, - {4932, 8972, 8973}, - {8892, 8980, 8981}, - {634, 9003, 9003}, - {8109, 9007, 9008}, - {8777, 9012, 9012}, - {3981, 9016, 9017}, - {5723, 9025, 9025}, - {7662, 9034, 9038}, - {8955, 9042, 9042}, - {8070, 9060, 9062}, - {8910, 9066, 9066}, - {5363, 9070, 9071}, - {7699, 9075, 9076}, - {8991, 9081, 9081}, - {6850, 9085, 9085}, - {5811, 9092, 9094}, - {9079, 9098, 9102}, - {6456, 9106, 9106}, - {2259, 9111, 9111}, - {4752, 9116, 9116}, - {9060, 9120, 9123}, - {8090, 9127, 9127}, - {5305, 9131, 9132}, - {8623, 9137, 9137}, - {7417, 9141, 9141}, - {6564, 9148, 9149}, - {9126, 9157, 9158}, - {4285, 9169, 9170}, - {8698, 9174, 9174}, - {8869, 9178, 9178}, - {2572, 9182, 9183}, - {6482, 9188, 9190}, - {9181, 9201, 9201}, - {2968, 9208, 9209}, - {2506, 9213, 9215}, - {9127, 9219, 9219}, - {7910, 9225, 9227}, - {5422, 9235, 9239}, - {8813, 9244, 9246}, - {9178, 9250, 9250}, - {8748, 9255, 9255}, - {7354, 9265, 9265}, - {7767, 9269, 9269}, - {7710, 9281, 9283}, - {8826, 9288, 9290}, - {861, 9295, 9295}, - {4482, 9301, 9301}, - {9264, 9305, 9306}, - {8805, 9310, 9310}, - {4995, 9314, 9314}, - {6730, 9318, 9318}, - {7457, 9328, 9328}, - {2547, 9335, 9336}, - {6298, 9340, 9343}, - {9305, 9353, 9354}, - {9269, 9358, 9358}, - {6338, 9370, 9370}, - {7289, 9376, 9379}, - {5780, 9383, 9383}, - {7607, 9387, 9387}, - {2065, 9392, 9392}, - {7238, 9396, 9396}, - {8856, 9400, 9400}, - {8069, 9412, 9413}, - {611, 9420, 9420}, - {7071, 9424, 9424}, - {3089, 9430, 9431}, - {7117, 9435, 9438}, - {1976, 9445, 9445}, - {6640, 9449, 9449}, - {5488, 9453, 9453}, - {8739, 9457, 9459}, - {5958, 9466, 9466}, - {7985, 9470, 9470}, - {8735, 9475, 9475}, - {5009, 9479, 9479}, - {8073, 9483, 9484}, - {2328, 9490, 9491}, - {9250, 9495, 9495}, - {4043, 9502, 9502}, - {7712, 9506, 9506}, - {9012, 9510, 9510}, - {9028, 9514, 9515}, - {2190, 9521, 9524}, - {9029, 9528, 9528}, - {9519, 9532, 9532}, - {9495, 9536, 9536}, - {8527, 9540, 9540}, - {2137, 9550, 9550}, - {8419, 9557, 9557}, - {9383, 9561, 9562}, - {8970, 9575, 9578}, - {8911, 9582, 9582}, - {7828, 9595, 9596}, - {6180, 9600, 9600}, - {8738, 9604, 9607}, - {7540, 9611, 9612}, - {9599, 9616, 9618}, - {9187, 9623, 9623}, - {9294, 9628, 9629}, - {4536, 9639, 9639}, - {3867, 9643, 9643}, - {6305, 9648, 9648}, - {1617, 9654, 9657}, - {5762, 9666, 9666}, - {8314, 9670, 9670}, - {9666, 9674, 9675}, - {9506, 9679, 9679}, - {9669, 9685, 9686}, - {9683, 9690, 9690}, - {8763, 9697, 9698}, - {7468, 9702, 9702}, - {460, 9707, 9707}, - {3115, 9712, 9712}, - {9424, 9716, 9717}, - {7359, 9721, 9724}, - {7547, 9728, 9729}, - {7151, 9733, 9738}, - {7627, 9742, 9742}, - {2822, 9747, 9747}, - {8247, 9751, 9753}, - {9550, 9758, 9758}, - {7585, 9762, 9763}, - {1002, 9767, 9767}, - {7168, 9772, 9773}, - {6941, 9777, 9780}, - {9728, 9784, 9786}, - {9770, 9792, 9796}, - {6411, 9801, 9802}, - {3689, 9806, 9808}, - {9575, 9814, 9816}, - {7025, 9820, 9821}, - {2776, 9826, 9826}, - {9806, 9830, 9830}, - {9820, 9834, 9835}, - {9800, 9839, 9847}, - {9834, 9851, 9852}, - {9829, 9856, 9862}, - {1400, 9866, 9866}, - {3197, 9870, 9871}, - {9851, 9875, 9876}, - {9742, 9883, 9884}, - {3362, 9888, 9889}, - {9883, 9893, 9893}, - {5711, 9899, 9910}, - {7806, 9915, 9915}, - {9120, 9919, 9919}, - {9715, 9925, 9934}, - {2580, 9938, 9938}, - {4907, 9942, 9944}, - {6239, 9953, 9954}, - {6961, 9963, 9963}, - {5295, 9967, 9968}, - {1915, 9972, 9973}, - {3426, 9983, 9985}, - {9875, 9994, 9995}, - {6942, 9999, 9999}, - {6621, 10005, 10005}, - {7589, 10010, 10012}, - {9286, 10020, 10020}, - {838, 10024, 10024}, - {9980, 10028, 10031}, - {9994, 10035, 10041}, - {2702, 10048, 10051}, - {2621, 10059, 10059}, - {10054, 10065, 10065}, - {8612, 10073, 10074}, - {7033, 10078, 10078}, - {916, 10082, 10082}, - {10035, 10086, 10087}, - {8613, 10097, 10097}, - {9919, 10107, 10108}, - {6133, 10114, 10115}, - {10059, 10119, 10119}, - {10065, 10126, 10127}, - {7732, 10131, 10131}, - {7155, 10135, 10136}, - {6728, 10140, 10140}, - {6162, 10144, 10145}, - {4724, 10150, 10150}, - {1665, 10154, 10154}, - {10126, 10163, 10163}, - {9783, 10168, 10168}, - {1715, 10172, 10173}, - {7152, 10177, 10182}, - {8760, 10187, 10187}, - {7829, 10191, 10191}, - {9679, 10196, 10196}, - {9369, 10201, 10201}, - {2928, 10206, 10208}, - {6951, 10214, 10217}, - {5633, 10221, 10221}, - {7199, 10225, 10225}, - {10118, 10230, 10231}, - {9999, 10235, 10236}, - {10045, 10240, 10249}, - {5565, 10256, 10256}, - {9866, 10261, 10261}, - {10163, 10268, 10268}, - {9869, 10272, 10272}, - {9789, 10276, 10283}, - {10235, 10287, 10288}, - {10214, 10298, 10299}, - {6971, 10303, 10303}, - {3346, 10307, 10307}, - {10185, 10311, 10312}, - {9993, 10318, 10320}, - {2779, 10332, 10334}, - {1726, 10338, 10338}, - {741, 10354, 10360}, - {10230, 10372, 10373}, - {10260, 10384, 10385}, - {10131, 10389, 10398}, - {6946, 10406, 10409}, - {10158, 10413, 10420}, - {10123, 10424, 10424}, - {6157, 10428, 10429}, - {4518, 10434, 10434}, - {9893, 10438, 10438}, - {9865, 10442, 10446}, - {7558, 10454, 10454}, - {10434, 10460, 10460}, - {10064, 10466, 10468}, - {2703, 10472, 10474}, - {9751, 10478, 10479}, - {6714, 10485, 10485}, - {8020, 10490, 10490}, - {10303, 10494, 10494}, - {3521, 10499, 10500}, - {9281, 10513, 10515}, - {6028, 10519, 10523}, - {9387, 10527, 10527}, - {7614, 10531, 10531}, - {3611, 10536, 10536}, - {9162, 10540, 10540}, - {10081, 10546, 10547}, - {10034, 10560, 10562}, - {6726, 10567, 10571}, - {8237, 10575, 10575}, - {10438, 10579, 10583}, - {10140, 10587, 10587}, - {5784, 10592, 10592}, - {9819, 10597, 10600}, - {10567, 10604, 10608}, - {9335, 10613, 10613}, - {8300, 10617, 10617}, - {10575, 10621, 10621}, - {9678, 10625, 10626}, - {9962, 10632, 10633}, - {10535, 10637, 10638}, - {8199, 10642, 10642}, - {10372, 10647, 10648}, - {10637, 10656, 10657}, - {10579, 10667, 10668}, - {10465, 10677, 10680}, - {6702, 10684, 10685}, - {10073, 10691, 10692}, - {4505, 10696, 10697}, - {9042, 10701, 10701}, - {6460, 10705, 10706}, - {10010, 10714, 10716}, - {10656, 10720, 10722}, - {7282, 10727, 10729}, - {2327, 10733, 10733}, - {2491, 10740, 10741}, - {10704, 10748, 10750}, - {6465, 10754, 10754}, - {10647, 10758, 10759}, - {10424, 10763, 10763}, - {10748, 10776, 10776}, - {10546, 10780, 10781}, - {10758, 10785, 10786}, - {10287, 10790, 10797}, - {10785, 10801, 10807}, - {10240, 10811, 10826}, - {9509, 10830, 10830}, - {2579, 10836, 10838}, - {9801, 10843, 10845}, - {7555, 10849, 10850}, - {10776, 10860, 10865}, - {8023, 10869, 10869}, - {10046, 10876, 10884}, - {10253, 10888, 10892}, - {9941, 10897, 10897}, - {7898, 10901, 10905}, - {6725, 10909, 10913}, - {10757, 10921, 10923}, - {10160, 10931, 10931}, - {10916, 10935, 10942}, - {10261, 10946, 10946}, - {10318, 10952, 10954}, - {5911, 10959, 10961}, - {10801, 10965, 10966}, - {10946, 10970, 10977}, - {10592, 10982, 10984}, - {9913, 10988, 10990}, - {8510, 10994, 10996}, - {9419, 11000, 11001}, - {6765, 11006, 11007}, - {10725, 11011, 11011}, - {5537, 11017, 11019}, - {9208, 11024, 11025}, - {5850, 11030, 11030}, - {9610, 11034, 11036}, - {8846, 11041, 11047}, - {9697, 11051, 11051}, - {1622, 11055, 11058}, - {2370, 11062, 11062}, - {8393, 11067, 11067}, - {9756, 11071, 11071}, - {10172, 11076, 11076}, - {27, 11081, 11081}, - {7357, 11087, 11092}, - {8151, 11104, 11106}, - {6115, 11110, 11110}, - {10667, 11114, 11115}, - {11099, 11121, 11123}, - {10705, 11127, 11127}, - {8938, 11131, 11131}, - {11114, 11135, 11136}, - {1390, 11140, 11141}, - {10964, 11146, 11148}, - {11140, 11152, 11155}, - {9813, 11159, 11166}, - {624, 11171, 11172}, - {3118, 11177, 11179}, - {11029, 11184, 11186}, - {10186, 11190, 11190}, - {10306, 11196, 11196}, - {8665, 11201, 11201}, - {7382, 11205, 11205}, - {1100, 11210, 11210}, - {2337, 11216, 11217}, - {1609, 11221, 11223}, - {5763, 11228, 11229}, - {5220, 11233, 11233}, - {11061, 11241, 11241}, - {10617, 11246, 11246}, - {11190, 11250, 11251}, - {10144, 11255, 11256}, - {11232, 11260, 11260}, - {857, 11264, 11265}, - {10994, 11269, 11271}, - {3879, 11280, 11281}, - {11184, 11287, 11289}, - {9611, 11293, 11295}, - {11250, 11299, 11299}, - {4495, 11304, 11304}, - {7574, 11308, 11309}, - {9814, 11315, 11317}, - {1713, 11321, 11324}, - {1905, 11328, 11328}, - {8745, 11335, 11340}, - {8883, 11351, 11351}, - {8119, 11358, 11358}, - {1842, 11363, 11364}, - {11237, 11368, 11368}, - {8814, 11373, 11374}, - {5684, 11378, 11378}, - {11011, 11382, 11382}, - {6520, 11389, 11389}, - {11183, 11393, 11396}, - {1790, 11404, 11404}, - {9536, 11408, 11408}, - {11298, 11418, 11419}, - {3929, 11425, 11425}, - {5588, 11429, 11429}, - {8476, 11436, 11436}, - {4096, 11440, 11442}, - {11084, 11446, 11454}, - {10603, 11458, 11463}, - {7332, 11472, 11474}, - {7611, 11483, 11486}, - {4836, 11490, 11491}, - {10024, 11495, 11495}, - {4917, 11501, 11506}, - {6486, 11510, 11512}, - {11269, 11516, 11518}, - {3603, 11522, 11525}, - {11126, 11535, 11535}, - {11418, 11539, 11541}, - {11408, 11545, 11545}, - {9021, 11549, 11552}, - {6745, 11557, 11557}, - {5118, 11561, 11564}, - {7590, 11568, 11569}, - {4426, 11573, 11578}, - {9790, 11582, 11583}, - {6447, 11587, 11587}, - {10229, 11591, 11594}, - {10457, 11598, 11598}, - {10168, 11604, 11604}, - {10543, 11608, 11608}, - {7404, 11612, 11612}, - {11127, 11616, 11616}, - {3337, 11620, 11620}, - {11501, 11624, 11628}, - {4543, 11633, 11635}, - {8449, 11642, 11642}, - {4943, 11646, 11648}, - {10526, 11652, 11654}, - {11620, 11659, 11659}, - {8927, 11664, 11669}, - {532, 11673, 11673}, - {10513, 11677, 11679}, - {10428, 11683, 11683}, - {10999, 11689, 11690}, - {9469, 11695, 11695}, - {3606, 11699, 11699}, - {9560, 11708, 11709}, - {1564, 11714, 11714}, - {10527, 11718, 11718}, - {3071, 11723, 11726}, - {11590, 11731, 11732}, - {6605, 11737, 11737}, - {11624, 11741, 11745}, - {7822, 11749, 11752}, - {5269, 11757, 11758}, - {1339, 11767, 11767}, - {1363, 11771, 11773}, - {3704, 11777, 11777}, - {10952, 11781, 11783}, - {6764, 11793, 11795}, - {8675, 11800, 11800}, - {9963, 11804, 11804}, - {11573, 11808, 11809}, - {9548, 11813, 11813}, - {11591, 11817, 11818}, - {11446, 11822, 11822}, - {9224, 11828, 11828}, - {3158, 11836, 11836}, - {10830, 11840, 11840}, - {7234, 11846, 11846}, - {11299, 11850, 11850}, - {11544, 11854, 11855}, - {11498, 11859, 11859}, - {10993, 11865, 11868}, - {9720, 11872, 11878}, - {10489, 11882, 11890}, - {11712, 11898, 11904}, - {11516, 11908, 11910}, - {11568, 11914, 11915}, - {10177, 11919, 11924}, - {11363, 11928, 11929}, - {10494, 11933, 11933}, - {9870, 11937, 11938}, - {9427, 11942, 11942}, - {11481, 11949, 11949}, - {6030, 11955, 11957}, - {11718, 11961, 11961}, - {10531, 11965, 11983}, - {5126, 11987, 11987}, - {7515, 11991, 11991}, - {10646, 11996, 11997}, - {2947, 12001, 12001}, - {9582, 12009, 12010}, - {6202, 12017, 12018}, - {11714, 12022, 12022}, - {9235, 12033, 12037}, - {9721, 12041, 12044}, - {11932, 12051, 12052}, - {12040, 12056, 12056}, - {12051, 12060, 12060}, - {11601, 12066, 12066}, - {8426, 12070, 12070}, - {4053, 12077, 12077}, - {4262, 12081, 12081}, - {9761, 12086, 12088}, - {11582, 12092, 12093}, - {10965, 12097, 12098}, - {11803, 12103, 12104}, - {11933, 12108, 12109}, - {10688, 12117, 12117}, - {12107, 12125, 12126}, - {6774, 12130, 12132}, - {6286, 12137, 12137}, - {9543, 12141, 12141}, - {12097, 12145, 12146}, - {10790, 12150, 12150}, - {10125, 12154, 12156}, - {12125, 12164, 12164}, - {12064, 12168, 12172}, - {10811, 12178, 12188}, - {12092, 12192, 12193}, - {10058, 12197, 12198}, - {11611, 12211, 12212}, - {3459, 12216, 12216}, - {10291, 12225, 12228}, - {12191, 12232, 12234}, - {12145, 12238, 12238}, - {12001, 12242, 12250}, - {3840, 12255, 12255}, - {12216, 12259, 12259}, - {674, 12272, 12272}, - {12141, 12276, 12276}, - {10766, 12280, 12280}, - {11545, 12284, 12284}, - {6496, 12290, 12290}, - {11381, 12294, 12295}, - {603, 12302, 12303}, - {12276, 12308, 12308}, - {11850, 12313, 12314}, - {565, 12319, 12319}, - {9351, 12324, 12324}, - {11822, 12328, 12328}, - {2691, 12333, 12334}, - {11840, 12338, 12338}, - {11070, 12343, 12343}, - {9510, 12347, 12347}, - {11024, 12352, 12353}, - {7173, 12359, 12359}, - {517, 12363, 12363}, - {6311, 12367, 12368}, - {11367, 12372, 12373}, - {12008, 12377, 12377}, - {11372, 12382, 12384}, - {11358, 12391, 12392}, - {11382, 12396, 12396}, - {6882, 12400, 12401}, - {11246, 12405, 12405}, - {8359, 12409, 12412}, - {10154, 12418, 12418}, - {12016, 12425, 12426}, - {8972, 12434, 12435}, - {10478, 12439, 12440}, - {12395, 12449, 12449}, - {11612, 12454, 12454}, - {12347, 12458, 12458}, - {10700, 12466, 12467}, - {3637, 12471, 12476}, - {1042, 12480, 12481}, - {6747, 12488, 12488}, - {12396, 12492, 12493}, - {9420, 12497, 12497}, - {11285, 12501, 12510}, - {4470, 12515, 12515}, - {9374, 12519, 12519}, - {11293, 12528, 12528}, - {2058, 12534, 12535}, - {6521, 12539, 12539}, - {12492, 12543, 12543}, - {3043, 12547, 12547}, - {2982, 12551, 12553}, - {11030, 12557, 12563}, - {7636, 12568, 12568}, - {9639, 12572, 12572}, - {12543, 12576, 12576}, - {5989, 12580, 12583}, - {11051, 12587, 12587}, - {1061, 12592, 12594}, - {12313, 12599, 12601}, - {11846, 12605, 12605}, - {12576, 12609, 12609}, - {11040, 12618, 12625}, - {12479, 12629, 12629}, - {6903, 12633, 12633}, - {12322, 12639, 12639}, - {12253, 12643, 12645}, - {5594, 12651, 12651}, - {12522, 12655, 12655}, - {11703, 12659, 12659}, - {1377, 12665, 12665}, - {8022, 12669, 12669}, - {12280, 12674, 12674}, - {9023, 12680, 12681}, - {12328, 12685, 12685}, - {3085, 12689, 12693}, - {4700, 12698, 12698}, - {10224, 12702, 12702}, - {8781, 12706, 12706}, - {1651, 12710, 12710}, - {12458, 12714, 12714}, - {12005, 12718, 12721}, - {11908, 12725, 12726}, - {8202, 12733, 12733}, - {11708, 12739, 12740}, - {12599, 12744, 12745}, - {12284, 12749, 12749}, - {5285, 12756, 12756}, - {12055, 12775, 12777}, - {6919, 12782, 12782}, - {12242, 12786, 12786}, - {12009, 12790, 12790}, - {9628, 12794, 12796}, - {11354, 12801, 12802}, - {10225, 12806, 12807}, - {579, 12813, 12813}, - {8935, 12817, 12822}, - {8753, 12827, 12829}, - {11006, 12835, 12835}, - {858, 12841, 12845}, - {476, 12849, 12849}, - {7667, 12854, 12854}, - {12760, 12860, 12871}, - {11677, 12875, 12877}, - {12714, 12881, 12881}, - {12731, 12885, 12890}, - {7108, 12894, 12896}, - {1165, 12900, 12900}, - {4021, 12906, 12906}, - {10829, 12910, 12911}, - {12331, 12915, 12915}, - {8887, 12919, 12921}, - {11639, 12925, 12925}, - {7964, 12929, 12929}, - {12528, 12937, 12937}, - {8148, 12941, 12941}, - {12770, 12948, 12950}, - {12609, 12954, 12954}, - {12685, 12958, 12958}, - {2803, 12962, 12962}, - {9561, 12966, 12966}, - {6671, 12972, 12973}, - {12056, 12977, 12977}, - {6380, 12981, 12981}, - {12048, 12985, 12985}, - {11961, 12989, 12993}, - {3368, 12997, 12999}, - {6634, 13004, 13004}, - {6775, 13009, 13010}, - {12136, 13014, 13019}, - {10341, 13023, 13023}, - {13002, 13027, 13027}, - {10587, 13031, 13031}, - {10307, 13035, 13035}, - {12736, 13039, 13039}, - {12744, 13043, 13044}, - {6175, 13048, 13048}, - {9702, 13053, 13054}, - {662, 13059, 13061}, - {12718, 13065, 13068}, - {12893, 13072, 13075}, - {8299, 13086, 13091}, - {12604, 13095, 13096}, - {12848, 13100, 13101}, - {12749, 13105, 13105}, - {12526, 13109, 13114}, - {9173, 13122, 13122}, - {12769, 13128, 13128}, - {13038, 13132, 13132}, - {12725, 13136, 13137}, - {12639, 13146, 13146}, - {9711, 13150, 13151}, - {12137, 13155, 13155}, - {13039, 13159, 13159}, - {4681, 13163, 13164}, - {12954, 13168, 13168}, - {13158, 13175, 13176}, - {13105, 13180, 13180}, - {10754, 13184, 13184}, - {13167, 13188, 13188}, - {12658, 13192, 13192}, - {4294, 13199, 13200}, - {11682, 13204, 13205}, - {11695, 13209, 13209}, - {11076, 13214, 13214}, - {12232, 13218, 13218}, - {9399, 13223, 13224}, - {12880, 13228, 13229}, - {13048, 13234, 13234}, - {9701, 13238, 13239}, - {13209, 13243, 13243}, - {3658, 13248, 13248}, - {3698, 13252, 13254}, - {12237, 13260, 13260}, - {8872, 13266, 13266}, - {12957, 13272, 13273}, - {1393, 13281, 13281}, - {2013, 13285, 13288}, - {4244, 13296, 13299}, - {9428, 13303, 13303}, - {12702, 13307, 13307}, - {13078, 13311, 13311}, - {6071, 13315, 13315}, - {3061, 13319, 13319}, - {2051, 13324, 13324}, - {11560, 13328, 13331}, - {6584, 13336, 13336}, - {8482, 13340, 13340}, - {5331, 13344, 13344}, - {4171, 13348, 13348}, - {8501, 13352, 13352}, - {9219, 13356, 13356}, - {9473, 13360, 13363}, - {12881, 13367, 13367}, - {13065, 13371, 13375}, - {2979, 13379, 13384}, - {1518, 13388, 13388}, - {11177, 13392, 13392}, - {9457, 13398, 13398}, - {12293, 13407, 13410}, - {3697, 13414, 13417}, - {10338, 13425, 13425}, - {13367, 13429, 13429}, - {11074, 13433, 13437}, - {4201, 13441, 13443}, - {1812, 13447, 13448}, - {13360, 13452, 13456}, - {13188, 13463, 13463}, - {9732, 13470, 13470}, - {11332, 13477, 13477}, - {9918, 13487, 13487}, - {6337, 13497, 13497}, - {13429, 13501, 13501}, - {11413, 13505, 13505}, - {4685, 13512, 13513}, - {13136, 13517, 13519}, - {7416, 13528, 13530}, - {12929, 13534, 13534}, - {11110, 13539, 13539}, - {11521, 13543, 13543}, - {12825, 13553, 13553}, - {13447, 13557, 13558}, - {12299, 13562, 13563}, - {9003, 13570, 13570}, - {12500, 13577, 13577}, - {13501, 13581, 13581}, - {9392, 13586, 13586}, - {12454, 13590, 13590}, - {6189, 13595, 13595}, - {13053, 13599, 13599}, - {11881, 13604, 13604}, - {13159, 13608, 13608}, - {4894, 13612, 13612}, - {13221, 13621, 13621}, - {8950, 13625, 13625}, - {13533, 13629, 13629}, - {9633, 13633, 13633}, - {7892, 13637, 13639}, - {13581, 13643, 13643}, - {13616, 13647, 13649}, - {12794, 13653, 13654}, - {8919, 13659, 13659}, - {9674, 13663, 13663}, - {13577, 13668, 13668}, - {12966, 13672, 13672}, - {12659, 13676, 13683}, - {6124, 13688, 13688}, - {9225, 13693, 13695}, - {11833, 13702, 13702}, - {12904, 13709, 13717}, - {13647, 13721, 13722}, - {11687, 13726, 13727}, - {12434, 13731, 13732}, - {12689, 13736, 13742}, - {13168, 13746, 13746}, - {6151, 13751, 13752}, - {11821, 13756, 13757}, - {6467, 13764, 13764}, - {5730, 13769, 13769}, - {5136, 13780, 13780}, - {724, 13784, 13785}, - {13517, 13789, 13791}, - {640, 13795, 13796}, - {7721, 13800, 13802}, - {11121, 13806, 13807}, - {5791, 13811, 13815}, - {12894, 13819, 13819}, - {11100, 13824, 13824}, - {7011, 13830, 13830}, - {7129, 13834, 13837}, - {13833, 13841, 13841}, - {11276, 13847, 13847}, - {13621, 13853, 13853}, - {13589, 13862, 13863}, - {12989, 13867, 13867}, - {12789, 13871, 13871}, - {1239, 13875, 13875}, - {4675, 13879, 13881}, - {4686, 13885, 13885}, - {707, 13889, 13889}, - {5449, 13897, 13898}, - {13867, 13902, 13903}, - {10613, 13908, 13908}, - {13789, 13912, 13914}, - {4451, 13918, 13919}, - {9200, 13924, 13924}, - {2011, 13930, 13930}, - {11433, 13934, 13936}, - {4695, 13942, 13943}, - {9435, 13948, 13951}, - {13688, 13955, 13957}, - {11694, 13961, 13962}, - {5712, 13966, 13966}, - {5991, 13970, 13972}, - {13477, 13976, 13976}, - {10213, 13987, 13987}, - {11839, 13991, 13993}, - {12272, 13997, 13997}, - {6206, 14001, 14001}, - {13179, 14006, 14007}, - {2939, 14011, 14011}, - {12972, 14016, 14017}, - {13918, 14021, 14022}, - {7436, 14026, 14027}, - {7678, 14032, 14034}, - {13586, 14040, 14040}, - {13347, 14044, 14044}, - {13109, 14048, 14051}, - {9244, 14055, 14057}, - {13315, 14061, 14061}, - {13276, 14067, 14067}, - {11435, 14073, 14074}, - {13853, 14078, 14078}, - {13452, 14082, 14082}, - {14044, 14087, 14087}, - {4440, 14091, 14095}, - {4479, 14100, 14103}, - {9395, 14107, 14109}, - {6834, 14119, 14119}, - {10458, 14123, 14124}, - {1429, 14129, 14129}, - {8443, 14135, 14135}, - {10365, 14140, 14140}, - {5267, 14145, 14145}, - {11834, 14151, 14153}, -} diff --git a/vender/github.com/golang/snappy/snappy.go b/vender/github.com/golang/snappy/snappy.go deleted file mode 100644 index 74a3668..0000000 --- a/vender/github.com/golang/snappy/snappy.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2011 The Snappy-Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package snappy implements the Snappy compression format. It aims for very -// high speeds and reasonable compression. -// -// There are actually two Snappy formats: block and stream. They are related, -// but different: trying to decompress block-compressed data as a Snappy stream -// will fail, and vice versa. The block format is the Decode and Encode -// functions and the stream format is the Reader and Writer types. -// -// The block format, the more common case, is used when the complete size (the -// number of bytes) of the original data is known upfront, at the time -// compression starts. The stream format, also known as the framing format, is -// for when that isn't always true. -// -// The canonical, C++ implementation is at https://github.com/google/snappy and -// it only implements the block format. -package snappy - -import ( - "hash/crc32" -) - -/* -Each encoded block begins with the varint-encoded length of the decoded data, -followed by a sequence of chunks. Chunks begin and end on byte boundaries. The -first byte of each chunk is broken into its 2 least and 6 most significant bits -called l and m: l ranges in [0, 4) and m ranges in [0, 64). l is the chunk tag. -Zero means a literal tag. All other values mean a copy tag. - -For literal tags: - - If m < 60, the next 1 + m bytes are literal bytes. - - Otherwise, let n be the little-endian unsigned integer denoted by the next - m - 59 bytes. The next 1 + n bytes after that are literal bytes. - -For copy tags, length bytes are copied from offset bytes ago, in the style of -Lempel-Ziv compression algorithms. In particular: - - For l == 1, the offset ranges in [0, 1<<11) and the length in [4, 12). - The length is 4 + the low 3 bits of m. The high 3 bits of m form bits 8-10 - of the offset. The next byte is bits 0-7 of the offset. - - For l == 2, the offset ranges in [0, 1<<16) and the length in [1, 65). - The length is 1 + m. The offset is the little-endian unsigned integer - denoted by the next 2 bytes. - - For l == 3, this tag is a legacy format that is no longer issued by most - encoders. Nonetheless, the offset ranges in [0, 1<<32) and the length in - [1, 65). The length is 1 + m. The offset is the little-endian unsigned - integer denoted by the next 4 bytes. -*/ -const ( - tagLiteral = 0x00 - tagCopy1 = 0x01 - tagCopy2 = 0x02 - tagCopy4 = 0x03 -) - -const ( - checksumSize = 4 - chunkHeaderSize = 4 - magicChunk = "\xff\x06\x00\x00" + magicBody - magicBody = "sNaPpY" - - // maxBlockSize is the maximum size of the input to encodeBlock. It is not - // part of the wire format per se, but some parts of the encoder assume - // that an offset fits into a uint16. - // - // Also, for the framing format (Writer type instead of Encode function), - // https://github.com/google/snappy/blob/master/framing_format.txt says - // that "the uncompressed data in a chunk must be no longer than 65536 - // bytes". - maxBlockSize = 65536 - - // maxEncodedLenOfMaxBlockSize equals MaxEncodedLen(maxBlockSize), but is - // hard coded to be a const instead of a variable, so that obufLen can also - // be a const. Their equivalence is confirmed by - // TestMaxEncodedLenOfMaxBlockSize. - maxEncodedLenOfMaxBlockSize = 76490 - - obufHeaderLen = len(magicChunk) + checksumSize + chunkHeaderSize - obufLen = obufHeaderLen + maxEncodedLenOfMaxBlockSize -) - -const ( - chunkTypeCompressedData = 0x00 - chunkTypeUncompressedData = 0x01 - chunkTypePadding = 0xfe - chunkTypeStreamIdentifier = 0xff -) - -var crcTable = crc32.MakeTable(crc32.Castagnoli) - -// crc implements the checksum specified in section 3 of -// https://github.com/google/snappy/blob/master/framing_format.txt -func crc(b []byte) uint32 { - c := crc32.Update(0, crcTable, b) - return uint32(c>>15|c<<17) + 0xa282ead8 -} diff --git a/vender/github.com/golang/snappy/snappy_test.go b/vender/github.com/golang/snappy/snappy_test.go deleted file mode 100644 index 2712710..0000000 --- a/vender/github.com/golang/snappy/snappy_test.go +++ /dev/null @@ -1,1353 +0,0 @@ -// Copyright 2011 The Snappy-Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package snappy - -import ( - "bytes" - "encoding/binary" - "flag" - "fmt" - "io" - "io/ioutil" - "math/rand" - "net/http" - "os" - "os/exec" - "path/filepath" - "runtime" - "strings" - "testing" -) - -var ( - download = flag.Bool("download", false, "If true, download any missing files before running benchmarks") - testdataDir = flag.String("testdataDir", "testdata", "Directory containing the test data") - benchdataDir = flag.String("benchdataDir", "testdata/bench", "Directory containing the benchmark data") -) - -// goEncoderShouldMatchCppEncoder is whether to test that the algorithm used by -// Go's encoder matches byte-for-byte what the C++ snappy encoder produces, on -// this GOARCH. There is more than one valid encoding of any given input, and -// there is more than one good algorithm along the frontier of trading off -// throughput for output size. Nonetheless, we presume that the C++ encoder's -// algorithm is a good one and has been tested on a wide range of inputs, so -// matching that exactly should mean that the Go encoder's algorithm is also -// good, without needing to gather our own corpus of test data. -// -// The exact algorithm used by the C++ code is potentially endian dependent, as -// it puns a byte pointer to a uint32 pointer to load, hash and compare 4 bytes -// at a time. The Go implementation is endian agnostic, in that its output is -// the same (as little-endian C++ code), regardless of the CPU's endianness. -// -// Thus, when comparing Go's output to C++ output generated beforehand, such as -// the "testdata/pi.txt.rawsnappy" file generated by C++ code on a little- -// endian system, we can run that test regardless of the runtime.GOARCH value. -// -// When comparing Go's output to dynamically generated C++ output, i.e. the -// result of fork/exec'ing a C++ program, we can run that test only on -// little-endian systems, because the C++ output might be different on -// big-endian systems. The runtime package doesn't export endianness per se, -// but we can restrict this match-C++ test to common little-endian systems. -const goEncoderShouldMatchCppEncoder = runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "arm" - -func TestMaxEncodedLenOfMaxBlockSize(t *testing.T) { - got := maxEncodedLenOfMaxBlockSize - want := MaxEncodedLen(maxBlockSize) - if got != want { - t.Fatalf("got %d, want %d", got, want) - } -} - -func cmp(a, b []byte) error { - if bytes.Equal(a, b) { - return nil - } - if len(a) != len(b) { - return fmt.Errorf("got %d bytes, want %d", len(a), len(b)) - } - for i := range a { - if a[i] != b[i] { - return fmt.Errorf("byte #%d: got 0x%02x, want 0x%02x", i, a[i], b[i]) - } - } - return nil -} - -func roundtrip(b, ebuf, dbuf []byte) error { - d, err := Decode(dbuf, Encode(ebuf, b)) - if err != nil { - return fmt.Errorf("decoding error: %v", err) - } - if err := cmp(d, b); err != nil { - return fmt.Errorf("roundtrip mismatch: %v", err) - } - return nil -} - -func TestEmpty(t *testing.T) { - if err := roundtrip(nil, nil, nil); err != nil { - t.Fatal(err) - } -} - -func TestSmallCopy(t *testing.T) { - for _, ebuf := range [][]byte{nil, make([]byte, 20), make([]byte, 64)} { - for _, dbuf := range [][]byte{nil, make([]byte, 20), make([]byte, 64)} { - for i := 0; i < 32; i++ { - s := "aaaa" + strings.Repeat("b", i) + "aaaabbbb" - if err := roundtrip([]byte(s), ebuf, dbuf); err != nil { - t.Errorf("len(ebuf)=%d, len(dbuf)=%d, i=%d: %v", len(ebuf), len(dbuf), i, err) - } - } - } - } -} - -func TestSmallRand(t *testing.T) { - rng := rand.New(rand.NewSource(1)) - for n := 1; n < 20000; n += 23 { - b := make([]byte, n) - for i := range b { - b[i] = uint8(rng.Intn(256)) - } - if err := roundtrip(b, nil, nil); err != nil { - t.Fatal(err) - } - } -} - -func TestSmallRegular(t *testing.T) { - for n := 1; n < 20000; n += 23 { - b := make([]byte, n) - for i := range b { - b[i] = uint8(i%10 + 'a') - } - if err := roundtrip(b, nil, nil); err != nil { - t.Fatal(err) - } - } -} - -func TestInvalidVarint(t *testing.T) { - testCases := []struct { - desc string - input string - }{{ - "invalid varint, final byte has continuation bit set", - "\xff", - }, { - "invalid varint, value overflows uint64", - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00", - }, { - // https://github.com/google/snappy/blob/master/format_description.txt - // says that "the stream starts with the uncompressed length [as a - // varint] (up to a maximum of 2^32 - 1)". - "valid varint (as uint64), but value overflows uint32", - "\x80\x80\x80\x80\x10", - }} - - for _, tc := range testCases { - input := []byte(tc.input) - if _, err := DecodedLen(input); err != ErrCorrupt { - t.Errorf("%s: DecodedLen: got %v, want ErrCorrupt", tc.desc, err) - } - if _, err := Decode(nil, input); err != ErrCorrupt { - t.Errorf("%s: Decode: got %v, want ErrCorrupt", tc.desc, err) - } - } -} - -func TestDecode(t *testing.T) { - lit40Bytes := make([]byte, 40) - for i := range lit40Bytes { - lit40Bytes[i] = byte(i) - } - lit40 := string(lit40Bytes) - - testCases := []struct { - desc string - input string - want string - wantErr error - }{{ - `decodedLen=0; valid input`, - "\x00", - "", - nil, - }, { - `decodedLen=3; tagLiteral, 0-byte length; length=3; valid input`, - "\x03" + "\x08\xff\xff\xff", - "\xff\xff\xff", - nil, - }, { - `decodedLen=2; tagLiteral, 0-byte length; length=3; not enough dst bytes`, - "\x02" + "\x08\xff\xff\xff", - "", - ErrCorrupt, - }, { - `decodedLen=3; tagLiteral, 0-byte length; length=3; not enough src bytes`, - "\x03" + "\x08\xff\xff", - "", - ErrCorrupt, - }, { - `decodedLen=40; tagLiteral, 0-byte length; length=40; valid input`, - "\x28" + "\x9c" + lit40, - lit40, - nil, - }, { - `decodedLen=1; tagLiteral, 1-byte length; not enough length bytes`, - "\x01" + "\xf0", - "", - ErrCorrupt, - }, { - `decodedLen=3; tagLiteral, 1-byte length; length=3; valid input`, - "\x03" + "\xf0\x02\xff\xff\xff", - "\xff\xff\xff", - nil, - }, { - `decodedLen=1; tagLiteral, 2-byte length; not enough length bytes`, - "\x01" + "\xf4\x00", - "", - ErrCorrupt, - }, { - `decodedLen=3; tagLiteral, 2-byte length; length=3; valid input`, - "\x03" + "\xf4\x02\x00\xff\xff\xff", - "\xff\xff\xff", - nil, - }, { - `decodedLen=1; tagLiteral, 3-byte length; not enough length bytes`, - "\x01" + "\xf8\x00\x00", - "", - ErrCorrupt, - }, { - `decodedLen=3; tagLiteral, 3-byte length; length=3; valid input`, - "\x03" + "\xf8\x02\x00\x00\xff\xff\xff", - "\xff\xff\xff", - nil, - }, { - `decodedLen=1; tagLiteral, 4-byte length; not enough length bytes`, - "\x01" + "\xfc\x00\x00\x00", - "", - ErrCorrupt, - }, { - `decodedLen=1; tagLiteral, 4-byte length; length=3; not enough dst bytes`, - "\x01" + "\xfc\x02\x00\x00\x00\xff\xff\xff", - "", - ErrCorrupt, - }, { - `decodedLen=4; tagLiteral, 4-byte length; length=3; not enough src bytes`, - "\x04" + "\xfc\x02\x00\x00\x00\xff", - "", - ErrCorrupt, - }, { - `decodedLen=3; tagLiteral, 4-byte length; length=3; valid input`, - "\x03" + "\xfc\x02\x00\x00\x00\xff\xff\xff", - "\xff\xff\xff", - nil, - }, { - `decodedLen=4; tagCopy1, 1 extra length|offset byte; not enough extra bytes`, - "\x04" + "\x01", - "", - ErrCorrupt, - }, { - `decodedLen=4; tagCopy2, 2 extra length|offset bytes; not enough extra bytes`, - "\x04" + "\x02\x00", - "", - ErrCorrupt, - }, { - `decodedLen=4; tagCopy4, 4 extra length|offset bytes; not enough extra bytes`, - "\x04" + "\x03\x00\x00\x00", - "", - ErrCorrupt, - }, { - `decodedLen=4; tagLiteral (4 bytes "abcd"); valid input`, - "\x04" + "\x0cabcd", - "abcd", - nil, - }, { - `decodedLen=13; tagLiteral (4 bytes "abcd"); tagCopy1; length=9 offset=4; valid input`, - "\x0d" + "\x0cabcd" + "\x15\x04", - "abcdabcdabcda", - nil, - }, { - `decodedLen=8; tagLiteral (4 bytes "abcd"); tagCopy1; length=4 offset=4; valid input`, - "\x08" + "\x0cabcd" + "\x01\x04", - "abcdabcd", - nil, - }, { - `decodedLen=8; tagLiteral (4 bytes "abcd"); tagCopy1; length=4 offset=2; valid input`, - "\x08" + "\x0cabcd" + "\x01\x02", - "abcdcdcd", - nil, - }, { - `decodedLen=8; tagLiteral (4 bytes "abcd"); tagCopy1; length=4 offset=1; valid input`, - "\x08" + "\x0cabcd" + "\x01\x01", - "abcddddd", - nil, - }, { - `decodedLen=8; tagLiteral (4 bytes "abcd"); tagCopy1; length=4 offset=0; zero offset`, - "\x08" + "\x0cabcd" + "\x01\x00", - "", - ErrCorrupt, - }, { - `decodedLen=9; tagLiteral (4 bytes "abcd"); tagCopy1; length=4 offset=4; inconsistent dLen`, - "\x09" + "\x0cabcd" + "\x01\x04", - "", - ErrCorrupt, - }, { - `decodedLen=8; tagLiteral (4 bytes "abcd"); tagCopy1; length=4 offset=5; offset too large`, - "\x08" + "\x0cabcd" + "\x01\x05", - "", - ErrCorrupt, - }, { - `decodedLen=7; tagLiteral (4 bytes "abcd"); tagCopy1; length=4 offset=4; length too large`, - "\x07" + "\x0cabcd" + "\x01\x04", - "", - ErrCorrupt, - }, { - `decodedLen=6; tagLiteral (4 bytes "abcd"); tagCopy2; length=2 offset=3; valid input`, - "\x06" + "\x0cabcd" + "\x06\x03\x00", - "abcdbc", - nil, - }, { - `decodedLen=6; tagLiteral (4 bytes "abcd"); tagCopy4; length=2 offset=3; valid input`, - "\x06" + "\x0cabcd" + "\x07\x03\x00\x00\x00", - "abcdbc", - nil, - }} - - const ( - // notPresentXxx defines a range of byte values [0xa0, 0xc5) that are - // not present in either the input or the output. It is written to dBuf - // to check that Decode does not write bytes past the end of - // dBuf[:dLen]. - // - // The magic number 37 was chosen because it is prime. A more 'natural' - // number like 32 might lead to a false negative if, for example, a - // byte was incorrectly copied 4*8 bytes later. - notPresentBase = 0xa0 - notPresentLen = 37 - ) - - var dBuf [100]byte -loop: - for i, tc := range testCases { - input := []byte(tc.input) - for _, x := range input { - if notPresentBase <= x && x < notPresentBase+notPresentLen { - t.Errorf("#%d (%s): input shouldn't contain %#02x\ninput: % x", i, tc.desc, x, input) - continue loop - } - } - - dLen, n := binary.Uvarint(input) - if n <= 0 { - t.Errorf("#%d (%s): invalid varint-encoded dLen", i, tc.desc) - continue - } - if dLen > uint64(len(dBuf)) { - t.Errorf("#%d (%s): dLen %d is too large", i, tc.desc, dLen) - continue - } - - for j := range dBuf { - dBuf[j] = byte(notPresentBase + j%notPresentLen) - } - g, gotErr := Decode(dBuf[:], input) - if got := string(g); got != tc.want || gotErr != tc.wantErr { - t.Errorf("#%d (%s):\ngot %q, %v\nwant %q, %v", - i, tc.desc, got, gotErr, tc.want, tc.wantErr) - continue - } - for j, x := range dBuf { - if uint64(j) < dLen { - continue - } - if w := byte(notPresentBase + j%notPresentLen); x != w { - t.Errorf("#%d (%s): Decode overrun: dBuf[%d] was modified: got %#02x, want %#02x\ndBuf: % x", - i, tc.desc, j, x, w, dBuf) - continue loop - } - } - } -} - -func TestDecodeCopy4(t *testing.T) { - dots := strings.Repeat(".", 65536) - - input := strings.Join([]string{ - "\x89\x80\x04", // decodedLen = 65545. - "\x0cpqrs", // 4-byte literal "pqrs". - "\xf4\xff\xff" + dots, // 65536-byte literal dots. - "\x13\x04\x00\x01\x00", // tagCopy4; length=5 offset=65540. - }, "") - - gotBytes, err := Decode(nil, []byte(input)) - if err != nil { - t.Fatal(err) - } - got := string(gotBytes) - want := "pqrs" + dots + "pqrs." - if len(got) != len(want) { - t.Fatalf("got %d bytes, want %d", len(got), len(want)) - } - if got != want { - for i := 0; i < len(got); i++ { - if g, w := got[i], want[i]; g != w { - t.Fatalf("byte #%d: got %#02x, want %#02x", i, g, w) - } - } - } -} - -// TestDecodeLengthOffset tests decoding an encoding of the form literal + -// copy-length-offset + literal. For example: "abcdefghijkl" + "efghij" + "AB". -func TestDecodeLengthOffset(t *testing.T) { - const ( - prefix = "abcdefghijklmnopqr" - suffix = "ABCDEFGHIJKLMNOPQR" - - // notPresentXxx defines a range of byte values [0xa0, 0xc5) that are - // not present in either the input or the output. It is written to - // gotBuf to check that Decode does not write bytes past the end of - // gotBuf[:totalLen]. - // - // The magic number 37 was chosen because it is prime. A more 'natural' - // number like 32 might lead to a false negative if, for example, a - // byte was incorrectly copied 4*8 bytes later. - notPresentBase = 0xa0 - notPresentLen = 37 - ) - var gotBuf, wantBuf, inputBuf [128]byte - for length := 1; length <= 18; length++ { - for offset := 1; offset <= 18; offset++ { - loop: - for suffixLen := 0; suffixLen <= 18; suffixLen++ { - totalLen := len(prefix) + length + suffixLen - - inputLen := binary.PutUvarint(inputBuf[:], uint64(totalLen)) - inputBuf[inputLen] = tagLiteral + 4*byte(len(prefix)-1) - inputLen++ - inputLen += copy(inputBuf[inputLen:], prefix) - inputBuf[inputLen+0] = tagCopy2 + 4*byte(length-1) - inputBuf[inputLen+1] = byte(offset) - inputBuf[inputLen+2] = 0x00 - inputLen += 3 - if suffixLen > 0 { - inputBuf[inputLen] = tagLiteral + 4*byte(suffixLen-1) - inputLen++ - inputLen += copy(inputBuf[inputLen:], suffix[:suffixLen]) - } - input := inputBuf[:inputLen] - - for i := range gotBuf { - gotBuf[i] = byte(notPresentBase + i%notPresentLen) - } - got, err := Decode(gotBuf[:], input) - if err != nil { - t.Errorf("length=%d, offset=%d; suffixLen=%d: %v", length, offset, suffixLen, err) - continue - } - - wantLen := 0 - wantLen += copy(wantBuf[wantLen:], prefix) - for i := 0; i < length; i++ { - wantBuf[wantLen] = wantBuf[wantLen-offset] - wantLen++ - } - wantLen += copy(wantBuf[wantLen:], suffix[:suffixLen]) - want := wantBuf[:wantLen] - - for _, x := range input { - if notPresentBase <= x && x < notPresentBase+notPresentLen { - t.Errorf("length=%d, offset=%d; suffixLen=%d: input shouldn't contain %#02x\ninput: % x", - length, offset, suffixLen, x, input) - continue loop - } - } - for i, x := range gotBuf { - if i < totalLen { - continue - } - if w := byte(notPresentBase + i%notPresentLen); x != w { - t.Errorf("length=%d, offset=%d; suffixLen=%d; totalLen=%d: "+ - "Decode overrun: gotBuf[%d] was modified: got %#02x, want %#02x\ngotBuf: % x", - length, offset, suffixLen, totalLen, i, x, w, gotBuf) - continue loop - } - } - for _, x := range want { - if notPresentBase <= x && x < notPresentBase+notPresentLen { - t.Errorf("length=%d, offset=%d; suffixLen=%d: want shouldn't contain %#02x\nwant: % x", - length, offset, suffixLen, x, want) - continue loop - } - } - - if !bytes.Equal(got, want) { - t.Errorf("length=%d, offset=%d; suffixLen=%d:\ninput % x\ngot % x\nwant % x", - length, offset, suffixLen, input, got, want) - continue - } - } - } - } -} - -const ( - goldenText = "Mark.Twain-Tom.Sawyer.txt" - goldenCompressed = goldenText + ".rawsnappy" -) - -func TestDecodeGoldenInput(t *testing.T) { - tDir := filepath.FromSlash(*testdataDir) - src, err := ioutil.ReadFile(filepath.Join(tDir, goldenCompressed)) - if err != nil { - t.Fatalf("ReadFile: %v", err) - } - got, err := Decode(nil, src) - if err != nil { - t.Fatalf("Decode: %v", err) - } - want, err := ioutil.ReadFile(filepath.Join(tDir, goldenText)) - if err != nil { - t.Fatalf("ReadFile: %v", err) - } - if err := cmp(got, want); err != nil { - t.Fatal(err) - } -} - -func TestEncodeGoldenInput(t *testing.T) { - tDir := filepath.FromSlash(*testdataDir) - src, err := ioutil.ReadFile(filepath.Join(tDir, goldenText)) - if err != nil { - t.Fatalf("ReadFile: %v", err) - } - got := Encode(nil, src) - want, err := ioutil.ReadFile(filepath.Join(tDir, goldenCompressed)) - if err != nil { - t.Fatalf("ReadFile: %v", err) - } - if err := cmp(got, want); err != nil { - t.Fatal(err) - } -} - -func TestExtendMatchGoldenInput(t *testing.T) { - tDir := filepath.FromSlash(*testdataDir) - src, err := ioutil.ReadFile(filepath.Join(tDir, goldenText)) - if err != nil { - t.Fatalf("ReadFile: %v", err) - } - for i, tc := range extendMatchGoldenTestCases { - got := extendMatch(src, tc.i, tc.j) - if got != tc.want { - t.Errorf("test #%d: i, j = %5d, %5d: got %5d (= j + %6d), want %5d (= j + %6d)", - i, tc.i, tc.j, got, got-tc.j, tc.want, tc.want-tc.j) - } - } -} - -func TestExtendMatch(t *testing.T) { - // ref is a simple, reference implementation of extendMatch. - ref := func(src []byte, i, j int) int { - for ; j < len(src) && src[i] == src[j]; i, j = i+1, j+1 { - } - return j - } - - nums := []int{0, 1, 2, 7, 8, 9, 29, 30, 31, 32, 33, 34, 38, 39, 40} - for yIndex := 40; yIndex > 30; yIndex-- { - xxx := bytes.Repeat([]byte("x"), 40) - if yIndex < len(xxx) { - xxx[yIndex] = 'y' - } - for _, i := range nums { - for _, j := range nums { - if i >= j { - continue - } - got := extendMatch(xxx, i, j) - want := ref(xxx, i, j) - if got != want { - t.Errorf("yIndex=%d, i=%d, j=%d: got %d, want %d", yIndex, i, j, got, want) - } - } - } - } -} - -const snappytoolCmdName = "cmd/snappytool/snappytool" - -func skipTestSameEncodingAsCpp() (msg string) { - if !goEncoderShouldMatchCppEncoder { - return fmt.Sprintf("skipping testing that the encoding is byte-for-byte identical to C++: GOARCH=%s", runtime.GOARCH) - } - if _, err := os.Stat(snappytoolCmdName); err != nil { - return fmt.Sprintf("could not find snappytool: %v", err) - } - return "" -} - -func runTestSameEncodingAsCpp(src []byte) error { - got := Encode(nil, src) - - cmd := exec.Command(snappytoolCmdName, "-e") - cmd.Stdin = bytes.NewReader(src) - want, err := cmd.Output() - if err != nil { - return fmt.Errorf("could not run snappytool: %v", err) - } - return cmp(got, want) -} - -func TestSameEncodingAsCppShortCopies(t *testing.T) { - if msg := skipTestSameEncodingAsCpp(); msg != "" { - t.Skip(msg) - } - src := bytes.Repeat([]byte{'a'}, 20) - for i := 0; i <= len(src); i++ { - if err := runTestSameEncodingAsCpp(src[:i]); err != nil { - t.Errorf("i=%d: %v", i, err) - } - } -} - -func TestSameEncodingAsCppLongFiles(t *testing.T) { - if msg := skipTestSameEncodingAsCpp(); msg != "" { - t.Skip(msg) - } - bDir := filepath.FromSlash(*benchdataDir) - failed := false - for i, tf := range testFiles { - if err := downloadBenchmarkFiles(t, tf.filename); err != nil { - t.Fatalf("failed to download testdata: %s", err) - } - data := readFile(t, filepath.Join(bDir, tf.filename)) - if n := tf.sizeLimit; 0 < n && n < len(data) { - data = data[:n] - } - if err := runTestSameEncodingAsCpp(data); err != nil { - t.Errorf("i=%d: %v", i, err) - failed = true - } - } - if failed { - t.Errorf("was the snappytool program built against the C++ snappy library version " + - "d53de187 or later, commited on 2016-04-05? See " + - "https://github.com/google/snappy/commit/d53de18799418e113e44444252a39b12a0e4e0cc") - } -} - -// TestSlowForwardCopyOverrun tests the "expand the pattern" algorithm -// described in decode_amd64.s and its claim of a 10 byte overrun worst case. -func TestSlowForwardCopyOverrun(t *testing.T) { - const base = 100 - - for length := 1; length < 18; length++ { - for offset := 1; offset < 18; offset++ { - highWaterMark := base - d := base - l := length - o := offset - - // makeOffsetAtLeast8 - for o < 8 { - if end := d + 8; highWaterMark < end { - highWaterMark = end - } - l -= o - d += o - o += o - } - - // fixUpSlowForwardCopy - a := d - d += l - - // finishSlowForwardCopy - for l > 0 { - if end := a + 8; highWaterMark < end { - highWaterMark = end - } - a += 8 - l -= 8 - } - - dWant := base + length - overrun := highWaterMark - dWant - if d != dWant || overrun < 0 || 10 < overrun { - t.Errorf("length=%d, offset=%d: d and overrun: got (%d, %d), want (%d, something in [0, 10])", - length, offset, d, overrun, dWant) - } - } - } -} - -// TestEncodeNoiseThenRepeats encodes input for which the first half is very -// incompressible and the second half is very compressible. The encoded form's -// length should be closer to 50% of the original length than 100%. -func TestEncodeNoiseThenRepeats(t *testing.T) { - for _, origLen := range []int{256 * 1024, 2048 * 1024} { - src := make([]byte, origLen) - rng := rand.New(rand.NewSource(1)) - firstHalf, secondHalf := src[:origLen/2], src[origLen/2:] - for i := range firstHalf { - firstHalf[i] = uint8(rng.Intn(256)) - } - for i := range secondHalf { - secondHalf[i] = uint8(i >> 8) - } - dst := Encode(nil, src) - if got, want := len(dst), origLen*3/4; got >= want { - t.Errorf("origLen=%d: got %d encoded bytes, want less than %d", origLen, got, want) - } - } -} - -func TestFramingFormat(t *testing.T) { - // src is comprised of alternating 1e5-sized sequences of random - // (incompressible) bytes and repeated (compressible) bytes. 1e5 was chosen - // because it is larger than maxBlockSize (64k). - src := make([]byte, 1e6) - rng := rand.New(rand.NewSource(1)) - for i := 0; i < 10; i++ { - if i%2 == 0 { - for j := 0; j < 1e5; j++ { - src[1e5*i+j] = uint8(rng.Intn(256)) - } - } else { - for j := 0; j < 1e5; j++ { - src[1e5*i+j] = uint8(i) - } - } - } - - buf := new(bytes.Buffer) - if _, err := NewWriter(buf).Write(src); err != nil { - t.Fatalf("Write: encoding: %v", err) - } - dst, err := ioutil.ReadAll(NewReader(buf)) - if err != nil { - t.Fatalf("ReadAll: decoding: %v", err) - } - if err := cmp(dst, src); err != nil { - t.Fatal(err) - } -} - -func TestWriterGoldenOutput(t *testing.T) { - buf := new(bytes.Buffer) - w := NewBufferedWriter(buf) - defer w.Close() - w.Write([]byte("abcd")) // Not compressible. - w.Flush() - w.Write(bytes.Repeat([]byte{'A'}, 150)) // Compressible. - w.Flush() - // The next chunk is also compressible, but a naive, greedy encoding of the - // overall length 67 copy as a length 64 copy (the longest expressible as a - // tagCopy1 or tagCopy2) plus a length 3 remainder would be two 3-byte - // tagCopy2 tags (6 bytes), since the minimum length for a tagCopy1 is 4 - // bytes. Instead, we could do it shorter, in 5 bytes: a 3-byte tagCopy2 - // (of length 60) and a 2-byte tagCopy1 (of length 7). - w.Write(bytes.Repeat([]byte{'B'}, 68)) - w.Write([]byte("efC")) // Not compressible. - w.Write(bytes.Repeat([]byte{'C'}, 20)) // Compressible. - w.Write(bytes.Repeat([]byte{'B'}, 20)) // Compressible. - w.Write([]byte("g")) // Not compressible. - w.Flush() - - got := buf.String() - want := strings.Join([]string{ - magicChunk, - "\x01\x08\x00\x00", // Uncompressed chunk, 8 bytes long (including 4 byte checksum). - "\x68\x10\xe6\xb6", // Checksum. - "\x61\x62\x63\x64", // Uncompressed payload: "abcd". - "\x00\x11\x00\x00", // Compressed chunk, 17 bytes long (including 4 byte checksum). - "\x5f\xeb\xf2\x10", // Checksum. - "\x96\x01", // Compressed payload: Uncompressed length (varint encoded): 150. - "\x00\x41", // Compressed payload: tagLiteral, length=1, "A". - "\xfe\x01\x00", // Compressed payload: tagCopy2, length=64, offset=1. - "\xfe\x01\x00", // Compressed payload: tagCopy2, length=64, offset=1. - "\x52\x01\x00", // Compressed payload: tagCopy2, length=21, offset=1. - "\x00\x18\x00\x00", // Compressed chunk, 24 bytes long (including 4 byte checksum). - "\x30\x85\x69\xeb", // Checksum. - "\x70", // Compressed payload: Uncompressed length (varint encoded): 112. - "\x00\x42", // Compressed payload: tagLiteral, length=1, "B". - "\xee\x01\x00", // Compressed payload: tagCopy2, length=60, offset=1. - "\x0d\x01", // Compressed payload: tagCopy1, length=7, offset=1. - "\x08\x65\x66\x43", // Compressed payload: tagLiteral, length=3, "efC". - "\x4e\x01\x00", // Compressed payload: tagCopy2, length=20, offset=1. - "\x4e\x5a\x00", // Compressed payload: tagCopy2, length=20, offset=90. - "\x00\x67", // Compressed payload: tagLiteral, length=1, "g". - }, "") - if got != want { - t.Fatalf("\ngot: % x\nwant: % x", got, want) - } -} - -func TestEmitLiteral(t *testing.T) { - testCases := []struct { - length int - want string - }{ - {1, "\x00"}, - {2, "\x04"}, - {59, "\xe8"}, - {60, "\xec"}, - {61, "\xf0\x3c"}, - {62, "\xf0\x3d"}, - {254, "\xf0\xfd"}, - {255, "\xf0\xfe"}, - {256, "\xf0\xff"}, - {257, "\xf4\x00\x01"}, - {65534, "\xf4\xfd\xff"}, - {65535, "\xf4\xfe\xff"}, - {65536, "\xf4\xff\xff"}, - } - - dst := make([]byte, 70000) - nines := bytes.Repeat([]byte{0x99}, 65536) - for _, tc := range testCases { - lit := nines[:tc.length] - n := emitLiteral(dst, lit) - if !bytes.HasSuffix(dst[:n], lit) { - t.Errorf("length=%d: did not end with that many literal bytes", tc.length) - continue - } - got := string(dst[:n-tc.length]) - if got != tc.want { - t.Errorf("length=%d:\ngot % x\nwant % x", tc.length, got, tc.want) - continue - } - } -} - -func TestEmitCopy(t *testing.T) { - testCases := []struct { - offset int - length int - want string - }{ - {8, 04, "\x01\x08"}, - {8, 11, "\x1d\x08"}, - {8, 12, "\x2e\x08\x00"}, - {8, 13, "\x32\x08\x00"}, - {8, 59, "\xea\x08\x00"}, - {8, 60, "\xee\x08\x00"}, - {8, 61, "\xf2\x08\x00"}, - {8, 62, "\xf6\x08\x00"}, - {8, 63, "\xfa\x08\x00"}, - {8, 64, "\xfe\x08\x00"}, - {8, 65, "\xee\x08\x00\x05\x08"}, - {8, 66, "\xee\x08\x00\x09\x08"}, - {8, 67, "\xee\x08\x00\x0d\x08"}, - {8, 68, "\xfe\x08\x00\x01\x08"}, - {8, 69, "\xfe\x08\x00\x05\x08"}, - {8, 80, "\xfe\x08\x00\x3e\x08\x00"}, - - {256, 04, "\x21\x00"}, - {256, 11, "\x3d\x00"}, - {256, 12, "\x2e\x00\x01"}, - {256, 13, "\x32\x00\x01"}, - {256, 59, "\xea\x00\x01"}, - {256, 60, "\xee\x00\x01"}, - {256, 61, "\xf2\x00\x01"}, - {256, 62, "\xf6\x00\x01"}, - {256, 63, "\xfa\x00\x01"}, - {256, 64, "\xfe\x00\x01"}, - {256, 65, "\xee\x00\x01\x25\x00"}, - {256, 66, "\xee\x00\x01\x29\x00"}, - {256, 67, "\xee\x00\x01\x2d\x00"}, - {256, 68, "\xfe\x00\x01\x21\x00"}, - {256, 69, "\xfe\x00\x01\x25\x00"}, - {256, 80, "\xfe\x00\x01\x3e\x00\x01"}, - - {2048, 04, "\x0e\x00\x08"}, - {2048, 11, "\x2a\x00\x08"}, - {2048, 12, "\x2e\x00\x08"}, - {2048, 13, "\x32\x00\x08"}, - {2048, 59, "\xea\x00\x08"}, - {2048, 60, "\xee\x00\x08"}, - {2048, 61, "\xf2\x00\x08"}, - {2048, 62, "\xf6\x00\x08"}, - {2048, 63, "\xfa\x00\x08"}, - {2048, 64, "\xfe\x00\x08"}, - {2048, 65, "\xee\x00\x08\x12\x00\x08"}, - {2048, 66, "\xee\x00\x08\x16\x00\x08"}, - {2048, 67, "\xee\x00\x08\x1a\x00\x08"}, - {2048, 68, "\xfe\x00\x08\x0e\x00\x08"}, - {2048, 69, "\xfe\x00\x08\x12\x00\x08"}, - {2048, 80, "\xfe\x00\x08\x3e\x00\x08"}, - } - - dst := make([]byte, 1024) - for _, tc := range testCases { - n := emitCopy(dst, tc.offset, tc.length) - got := string(dst[:n]) - if got != tc.want { - t.Errorf("offset=%d, length=%d:\ngot % x\nwant % x", tc.offset, tc.length, got, tc.want) - } - } -} - -func TestNewBufferedWriter(t *testing.T) { - // Test all 32 possible sub-sequences of these 5 input slices. - // - // Their lengths sum to 400,000, which is over 6 times the Writer ibuf - // capacity: 6 * maxBlockSize is 393,216. - inputs := [][]byte{ - bytes.Repeat([]byte{'a'}, 40000), - bytes.Repeat([]byte{'b'}, 150000), - bytes.Repeat([]byte{'c'}, 60000), - bytes.Repeat([]byte{'d'}, 120000), - bytes.Repeat([]byte{'e'}, 30000), - } -loop: - for i := 0; i < 1< 0; { - i := copy(x, src) - x = x[i:] - } - return dst -} - -func benchWords(b *testing.B, n int, decode bool) { - // Note: the file is OS-language dependent so the resulting values are not - // directly comparable for non-US-English OS installations. - data := expand(readFile(b, "/usr/share/dict/words"), n) - if decode { - benchDecode(b, data) - } else { - benchEncode(b, data) - } -} - -func BenchmarkWordsDecode1e1(b *testing.B) { benchWords(b, 1e1, true) } -func BenchmarkWordsDecode1e2(b *testing.B) { benchWords(b, 1e2, true) } -func BenchmarkWordsDecode1e3(b *testing.B) { benchWords(b, 1e3, true) } -func BenchmarkWordsDecode1e4(b *testing.B) { benchWords(b, 1e4, true) } -func BenchmarkWordsDecode1e5(b *testing.B) { benchWords(b, 1e5, true) } -func BenchmarkWordsDecode1e6(b *testing.B) { benchWords(b, 1e6, true) } -func BenchmarkWordsEncode1e1(b *testing.B) { benchWords(b, 1e1, false) } -func BenchmarkWordsEncode1e2(b *testing.B) { benchWords(b, 1e2, false) } -func BenchmarkWordsEncode1e3(b *testing.B) { benchWords(b, 1e3, false) } -func BenchmarkWordsEncode1e4(b *testing.B) { benchWords(b, 1e4, false) } -func BenchmarkWordsEncode1e5(b *testing.B) { benchWords(b, 1e5, false) } -func BenchmarkWordsEncode1e6(b *testing.B) { benchWords(b, 1e6, false) } - -func BenchmarkRandomEncode(b *testing.B) { - rng := rand.New(rand.NewSource(1)) - data := make([]byte, 1<<20) - for i := range data { - data[i] = uint8(rng.Intn(256)) - } - benchEncode(b, data) -} - -// testFiles' values are copied directly from -// https://raw.githubusercontent.com/google/snappy/master/snappy_unittest.cc -// The label field is unused in snappy-go. -var testFiles = []struct { - label string - filename string - sizeLimit int -}{ - {"html", "html", 0}, - {"urls", "urls.10K", 0}, - {"jpg", "fireworks.jpeg", 0}, - {"jpg_200", "fireworks.jpeg", 200}, - {"pdf", "paper-100k.pdf", 0}, - {"html4", "html_x_4", 0}, - {"txt1", "alice29.txt", 0}, - {"txt2", "asyoulik.txt", 0}, - {"txt3", "lcet10.txt", 0}, - {"txt4", "plrabn12.txt", 0}, - {"pb", "geo.protodata", 0}, - {"gaviota", "kppkn.gtb", 0}, -} - -const ( - // The benchmark data files are at this canonical URL. - benchURL = "https://raw.githubusercontent.com/google/snappy/master/testdata/" -) - -func downloadBenchmarkFiles(b testing.TB, basename string) (errRet error) { - bDir := filepath.FromSlash(*benchdataDir) - filename := filepath.Join(bDir, basename) - if stat, err := os.Stat(filename); err == nil && stat.Size() != 0 { - return nil - } - - if !*download { - b.Skipf("test data not found; skipping %s without the -download flag", testOrBenchmark(b)) - } - // Download the official snappy C++ implementation reference test data - // files for benchmarking. - if err := os.MkdirAll(bDir, 0777); err != nil && !os.IsExist(err) { - return fmt.Errorf("failed to create %s: %s", bDir, err) - } - - f, err := os.Create(filename) - if err != nil { - return fmt.Errorf("failed to create %s: %s", filename, err) - } - defer f.Close() - defer func() { - if errRet != nil { - os.Remove(filename) - } - }() - url := benchURL + basename - resp, err := http.Get(url) - if err != nil { - return fmt.Errorf("failed to download %s: %s", url, err) - } - defer resp.Body.Close() - if s := resp.StatusCode; s != http.StatusOK { - return fmt.Errorf("downloading %s: HTTP status code %d (%s)", url, s, http.StatusText(s)) - } - _, err = io.Copy(f, resp.Body) - if err != nil { - return fmt.Errorf("failed to download %s to %s: %s", url, filename, err) - } - return nil -} - -func benchFile(b *testing.B, i int, decode bool) { - if err := downloadBenchmarkFiles(b, testFiles[i].filename); err != nil { - b.Fatalf("failed to download testdata: %s", err) - } - bDir := filepath.FromSlash(*benchdataDir) - data := readFile(b, filepath.Join(bDir, testFiles[i].filename)) - if n := testFiles[i].sizeLimit; 0 < n && n < len(data) { - data = data[:n] - } - if decode { - benchDecode(b, data) - } else { - benchEncode(b, data) - } -} - -// Naming convention is kept similar to what snappy's C++ implementation uses. -func Benchmark_UFlat0(b *testing.B) { benchFile(b, 0, true) } -func Benchmark_UFlat1(b *testing.B) { benchFile(b, 1, true) } -func Benchmark_UFlat2(b *testing.B) { benchFile(b, 2, true) } -func Benchmark_UFlat3(b *testing.B) { benchFile(b, 3, true) } -func Benchmark_UFlat4(b *testing.B) { benchFile(b, 4, true) } -func Benchmark_UFlat5(b *testing.B) { benchFile(b, 5, true) } -func Benchmark_UFlat6(b *testing.B) { benchFile(b, 6, true) } -func Benchmark_UFlat7(b *testing.B) { benchFile(b, 7, true) } -func Benchmark_UFlat8(b *testing.B) { benchFile(b, 8, true) } -func Benchmark_UFlat9(b *testing.B) { benchFile(b, 9, true) } -func Benchmark_UFlat10(b *testing.B) { benchFile(b, 10, true) } -func Benchmark_UFlat11(b *testing.B) { benchFile(b, 11, true) } -func Benchmark_ZFlat0(b *testing.B) { benchFile(b, 0, false) } -func Benchmark_ZFlat1(b *testing.B) { benchFile(b, 1, false) } -func Benchmark_ZFlat2(b *testing.B) { benchFile(b, 2, false) } -func Benchmark_ZFlat3(b *testing.B) { benchFile(b, 3, false) } -func Benchmark_ZFlat4(b *testing.B) { benchFile(b, 4, false) } -func Benchmark_ZFlat5(b *testing.B) { benchFile(b, 5, false) } -func Benchmark_ZFlat6(b *testing.B) { benchFile(b, 6, false) } -func Benchmark_ZFlat7(b *testing.B) { benchFile(b, 7, false) } -func Benchmark_ZFlat8(b *testing.B) { benchFile(b, 8, false) } -func Benchmark_ZFlat9(b *testing.B) { benchFile(b, 9, false) } -func Benchmark_ZFlat10(b *testing.B) { benchFile(b, 10, false) } -func Benchmark_ZFlat11(b *testing.B) { benchFile(b, 11, false) } - -func BenchmarkExtendMatch(b *testing.B) { - tDir := filepath.FromSlash(*testdataDir) - src, err := ioutil.ReadFile(filepath.Join(tDir, goldenText)) - if err != nil { - b.Fatalf("ReadFile: %v", err) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - for _, tc := range extendMatchGoldenTestCases { - extendMatch(src, tc.i, tc.j) - } - } -} diff --git a/vender/github.com/xtaci/kcp/crypt.go b/vender/github.com/xtaci/kcp/crypt.go deleted file mode 100644 index 958fdea..0000000 --- a/vender/github.com/xtaci/kcp/crypt.go +++ /dev/null @@ -1,785 +0,0 @@ -package kcp - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/des" - "crypto/sha1" - - "github.com/templexxx/xor" - "github.com/tjfoc/gmsm/sm4" - - "golang.org/x/crypto/blowfish" - "golang.org/x/crypto/cast5" - "golang.org/x/crypto/pbkdf2" - "golang.org/x/crypto/salsa20" - "golang.org/x/crypto/tea" - "golang.org/x/crypto/twofish" - "golang.org/x/crypto/xtea" -) - -var ( - initialVector = []byte{167, 115, 79, 156, 18, 172, 27, 1, 164, 21, 242, 193, 252, 120, 230, 107} - saltxor = `sH3CIVoF#rWLtJo6` -) - -// BlockCrypt defines encryption/decryption methods for a given byte slice. -// Notes on implementing: the data to be encrypted contains a builtin -// nonce at the first 16 bytes -type BlockCrypt interface { - // Encrypt encrypts the whole block in src into dst. - // Dst and src may point at the same memory. - Encrypt(dst, src []byte) - - // Decrypt decrypts the whole block in src into dst. - // Dst and src may point at the same memory. - Decrypt(dst, src []byte) -} - -type salsa20BlockCrypt struct { - key [32]byte -} - -// NewSalsa20BlockCrypt https://en.wikipedia.org/wiki/Salsa20 -func NewSalsa20BlockCrypt(key []byte) (BlockCrypt, error) { - c := new(salsa20BlockCrypt) - copy(c.key[:], key) - return c, nil -} - -func (c *salsa20BlockCrypt) Encrypt(dst, src []byte) { - salsa20.XORKeyStream(dst[8:], src[8:], src[:8], &c.key) - copy(dst[:8], src[:8]) -} -func (c *salsa20BlockCrypt) Decrypt(dst, src []byte) { - salsa20.XORKeyStream(dst[8:], src[8:], src[:8], &c.key) - copy(dst[:8], src[:8]) -} - -type sm4BlockCrypt struct { - encbuf [sm4.BlockSize]byte - decbuf [2 * sm4.BlockSize]byte - block cipher.Block -} - -// NewSM4BlockCrypt https://github.com/tjfoc/gmsm/tree/master/sm4 -func NewSM4BlockCrypt(key []byte) (BlockCrypt, error) { - c := new(sm4BlockCrypt) - block, err := sm4.NewCipher(key) - if err != nil { - return nil, err - } - c.block = block - return c, nil -} - -func (c *sm4BlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf[:]) } -func (c *sm4BlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf[:]) } - -type twofishBlockCrypt struct { - encbuf [twofish.BlockSize]byte - decbuf [2 * twofish.BlockSize]byte - block cipher.Block -} - -// NewTwofishBlockCrypt https://en.wikipedia.org/wiki/Twofish -func NewTwofishBlockCrypt(key []byte) (BlockCrypt, error) { - c := new(twofishBlockCrypt) - block, err := twofish.NewCipher(key) - if err != nil { - return nil, err - } - c.block = block - return c, nil -} - -func (c *twofishBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf[:]) } -func (c *twofishBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf[:]) } - -type tripleDESBlockCrypt struct { - encbuf [des.BlockSize]byte - decbuf [2 * des.BlockSize]byte - block cipher.Block -} - -// NewTripleDESBlockCrypt https://en.wikipedia.org/wiki/Triple_DES -func NewTripleDESBlockCrypt(key []byte) (BlockCrypt, error) { - c := new(tripleDESBlockCrypt) - block, err := des.NewTripleDESCipher(key) - if err != nil { - return nil, err - } - c.block = block - return c, nil -} - -func (c *tripleDESBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf[:]) } -func (c *tripleDESBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf[:]) } - -type cast5BlockCrypt struct { - encbuf [cast5.BlockSize]byte - decbuf [2 * cast5.BlockSize]byte - block cipher.Block -} - -// NewCast5BlockCrypt https://en.wikipedia.org/wiki/CAST-128 -func NewCast5BlockCrypt(key []byte) (BlockCrypt, error) { - c := new(cast5BlockCrypt) - block, err := cast5.NewCipher(key) - if err != nil { - return nil, err - } - c.block = block - return c, nil -} - -func (c *cast5BlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf[:]) } -func (c *cast5BlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf[:]) } - -type blowfishBlockCrypt struct { - encbuf [blowfish.BlockSize]byte - decbuf [2 * blowfish.BlockSize]byte - block cipher.Block -} - -// NewBlowfishBlockCrypt https://en.wikipedia.org/wiki/Blowfish_(cipher) -func NewBlowfishBlockCrypt(key []byte) (BlockCrypt, error) { - c := new(blowfishBlockCrypt) - block, err := blowfish.NewCipher(key) - if err != nil { - return nil, err - } - c.block = block - return c, nil -} - -func (c *blowfishBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf[:]) } -func (c *blowfishBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf[:]) } - -type aesBlockCrypt struct { - encbuf [aes.BlockSize]byte - decbuf [2 * aes.BlockSize]byte - block cipher.Block -} - -// NewAESBlockCrypt https://en.wikipedia.org/wiki/Advanced_Encryption_Standard -func NewAESBlockCrypt(key []byte) (BlockCrypt, error) { - c := new(aesBlockCrypt) - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - c.block = block - return c, nil -} - -func (c *aesBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf[:]) } -func (c *aesBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf[:]) } - -type teaBlockCrypt struct { - encbuf [tea.BlockSize]byte - decbuf [2 * tea.BlockSize]byte - block cipher.Block -} - -// NewTEABlockCrypt https://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm -func NewTEABlockCrypt(key []byte) (BlockCrypt, error) { - c := new(teaBlockCrypt) - block, err := tea.NewCipherWithRounds(key, 16) - if err != nil { - return nil, err - } - c.block = block - return c, nil -} - -func (c *teaBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf[:]) } -func (c *teaBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf[:]) } - -type xteaBlockCrypt struct { - encbuf [xtea.BlockSize]byte - decbuf [2 * xtea.BlockSize]byte - block cipher.Block -} - -// NewXTEABlockCrypt https://en.wikipedia.org/wiki/XTEA -func NewXTEABlockCrypt(key []byte) (BlockCrypt, error) { - c := new(xteaBlockCrypt) - block, err := xtea.NewCipher(key) - if err != nil { - return nil, err - } - c.block = block - return c, nil -} - -func (c *xteaBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf[:]) } -func (c *xteaBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf[:]) } - -type simpleXORBlockCrypt struct { - xortbl []byte -} - -// NewSimpleXORBlockCrypt simple xor with key expanding -func NewSimpleXORBlockCrypt(key []byte) (BlockCrypt, error) { - c := new(simpleXORBlockCrypt) - c.xortbl = pbkdf2.Key(key, []byte(saltxor), 32, mtuLimit, sha1.New) - return c, nil -} - -func (c *simpleXORBlockCrypt) Encrypt(dst, src []byte) { xor.Bytes(dst, src, c.xortbl) } -func (c *simpleXORBlockCrypt) Decrypt(dst, src []byte) { xor.Bytes(dst, src, c.xortbl) } - -type noneBlockCrypt struct{} - -// NewNoneBlockCrypt does nothing but copying -func NewNoneBlockCrypt(key []byte) (BlockCrypt, error) { - return new(noneBlockCrypt), nil -} - -func (c *noneBlockCrypt) Encrypt(dst, src []byte) { copy(dst, src) } -func (c *noneBlockCrypt) Decrypt(dst, src []byte) { copy(dst, src) } - -// packet encryption with local CFB mode -func encrypt(block cipher.Block, dst, src, buf []byte) { - switch block.BlockSize() { - case 8: - encrypt8(block, dst, src, buf) - case 16: - encrypt16(block, dst, src, buf) - default: - encryptVariant(block, dst, src, buf) - } -} - -// optimized encryption for the ciphers which works in 8-bytes -func encrypt8(block cipher.Block, dst, src, buf []byte) { - tbl := buf[:8] - block.Encrypt(tbl, initialVector) - n := len(src) / 8 - base := 0 - repeat := n / 8 - left := n % 8 - for i := 0; i < repeat; i++ { - s := src[base:][0:64] - d := dst[base:][0:64] - // 1 - xor.BytesSrc1(d[0:8], s[0:8], tbl) - block.Encrypt(tbl, d[0:8]) - // 2 - xor.BytesSrc1(d[8:16], s[8:16], tbl) - block.Encrypt(tbl, d[8:16]) - // 3 - xor.BytesSrc1(d[16:24], s[16:24], tbl) - block.Encrypt(tbl, d[16:24]) - // 4 - xor.BytesSrc1(d[24:32], s[24:32], tbl) - block.Encrypt(tbl, d[24:32]) - // 5 - xor.BytesSrc1(d[32:40], s[32:40], tbl) - block.Encrypt(tbl, d[32:40]) - // 6 - xor.BytesSrc1(d[40:48], s[40:48], tbl) - block.Encrypt(tbl, d[40:48]) - // 7 - xor.BytesSrc1(d[48:56], s[48:56], tbl) - block.Encrypt(tbl, d[48:56]) - // 8 - xor.BytesSrc1(d[56:64], s[56:64], tbl) - block.Encrypt(tbl, d[56:64]) - base += 64 - } - - switch left { - case 7: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += 8 - fallthrough - case 6: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += 8 - fallthrough - case 5: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += 8 - fallthrough - case 4: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += 8 - fallthrough - case 3: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += 8 - fallthrough - case 2: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += 8 - fallthrough - case 1: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += 8 - fallthrough - case 0: - xor.BytesSrc0(dst[base:], src[base:], tbl) - } -} - -// optimized encryption for the ciphers which works in 16-bytes -func encrypt16(block cipher.Block, dst, src, buf []byte) { - tbl := buf[:16] - block.Encrypt(tbl, initialVector) - n := len(src) / 16 - base := 0 - repeat := n / 8 - left := n % 8 - for i := 0; i < repeat; i++ { - s := src[base:][0:128] - d := dst[base:][0:128] - // 1 - xor.BytesSrc1(d[0:16], s[0:16], tbl) - block.Encrypt(tbl, d[0:16]) - // 2 - xor.BytesSrc1(d[16:32], s[16:32], tbl) - block.Encrypt(tbl, d[16:32]) - // 3 - xor.BytesSrc1(d[32:48], s[32:48], tbl) - block.Encrypt(tbl, d[32:48]) - // 4 - xor.BytesSrc1(d[48:64], s[48:64], tbl) - block.Encrypt(tbl, d[48:64]) - // 5 - xor.BytesSrc1(d[64:80], s[64:80], tbl) - block.Encrypt(tbl, d[64:80]) - // 6 - xor.BytesSrc1(d[80:96], s[80:96], tbl) - block.Encrypt(tbl, d[80:96]) - // 7 - xor.BytesSrc1(d[96:112], s[96:112], tbl) - block.Encrypt(tbl, d[96:112]) - // 8 - xor.BytesSrc1(d[112:128], s[112:128], tbl) - block.Encrypt(tbl, d[112:128]) - base += 128 - } - - switch left { - case 7: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += 16 - fallthrough - case 6: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += 16 - fallthrough - case 5: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += 16 - fallthrough - case 4: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += 16 - fallthrough - case 3: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += 16 - fallthrough - case 2: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += 16 - fallthrough - case 1: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += 16 - fallthrough - case 0: - xor.BytesSrc0(dst[base:], src[base:], tbl) - } -} - -func encryptVariant(block cipher.Block, dst, src, buf []byte) { - blocksize := block.BlockSize() - tbl := buf[:blocksize] - block.Encrypt(tbl, initialVector) - n := len(src) / blocksize - base := 0 - repeat := n / 8 - left := n % 8 - for i := 0; i < repeat; i++ { - // 1 - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += blocksize - - // 2 - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += blocksize - - // 3 - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += blocksize - - // 4 - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += blocksize - - // 5 - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += blocksize - - // 6 - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += blocksize - - // 7 - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += blocksize - - // 8 - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += blocksize - } - - switch left { - case 7: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += blocksize - fallthrough - case 6: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += blocksize - fallthrough - case 5: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += blocksize - fallthrough - case 4: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += blocksize - fallthrough - case 3: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += blocksize - fallthrough - case 2: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += blocksize - fallthrough - case 1: - xor.BytesSrc1(dst[base:], src[base:], tbl) - block.Encrypt(tbl, dst[base:]) - base += blocksize - fallthrough - case 0: - xor.BytesSrc0(dst[base:], src[base:], tbl) - } -} - -// decryption -func decrypt(block cipher.Block, dst, src, buf []byte) { - switch block.BlockSize() { - case 8: - decrypt8(block, dst, src, buf) - case 16: - decrypt16(block, dst, src, buf) - default: - decryptVariant(block, dst, src, buf) - } -} - -func decrypt8(block cipher.Block, dst, src, buf []byte) { - tbl := buf[0:8] - next := buf[8:16] - block.Encrypt(tbl, initialVector) - n := len(src) / 8 - base := 0 - repeat := n / 8 - left := n % 8 - for i := 0; i < repeat; i++ { - s := src[base:][0:64] - d := dst[base:][0:64] - // 1 - block.Encrypt(next, s[0:8]) - xor.BytesSrc1(d[0:8], s[0:8], tbl) - // 2 - block.Encrypt(tbl, s[8:16]) - xor.BytesSrc1(d[8:16], s[8:16], next) - // 3 - block.Encrypt(next, s[16:24]) - xor.BytesSrc1(d[16:24], s[16:24], tbl) - // 4 - block.Encrypt(tbl, s[24:32]) - xor.BytesSrc1(d[24:32], s[24:32], next) - // 5 - block.Encrypt(next, s[32:40]) - xor.BytesSrc1(d[32:40], s[32:40], tbl) - // 6 - block.Encrypt(tbl, s[40:48]) - xor.BytesSrc1(d[40:48], s[40:48], next) - // 7 - block.Encrypt(next, s[48:56]) - xor.BytesSrc1(d[48:56], s[48:56], tbl) - // 8 - block.Encrypt(tbl, s[56:64]) - xor.BytesSrc1(d[56:64], s[56:64], next) - base += 64 - } - - switch left { - case 7: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += 8 - fallthrough - case 6: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += 8 - fallthrough - case 5: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += 8 - fallthrough - case 4: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += 8 - fallthrough - case 3: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += 8 - fallthrough - case 2: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += 8 - fallthrough - case 1: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += 8 - fallthrough - case 0: - xor.BytesSrc0(dst[base:], src[base:], tbl) - } -} - -func decrypt16(block cipher.Block, dst, src, buf []byte) { - tbl := buf[0:16] - next := buf[16:32] - block.Encrypt(tbl, initialVector) - n := len(src) / 16 - base := 0 - repeat := n / 8 - left := n % 8 - for i := 0; i < repeat; i++ { - s := src[base:][0:128] - d := dst[base:][0:128] - // 1 - block.Encrypt(next, s[0:16]) - xor.BytesSrc1(d[0:16], s[0:16], tbl) - // 2 - block.Encrypt(tbl, s[16:32]) - xor.BytesSrc1(d[16:32], s[16:32], next) - // 3 - block.Encrypt(next, s[32:48]) - xor.BytesSrc1(d[32:48], s[32:48], tbl) - // 4 - block.Encrypt(tbl, s[48:64]) - xor.BytesSrc1(d[48:64], s[48:64], next) - // 5 - block.Encrypt(next, s[64:80]) - xor.BytesSrc1(d[64:80], s[64:80], tbl) - // 6 - block.Encrypt(tbl, s[80:96]) - xor.BytesSrc1(d[80:96], s[80:96], next) - // 7 - block.Encrypt(next, s[96:112]) - xor.BytesSrc1(d[96:112], s[96:112], tbl) - // 8 - block.Encrypt(tbl, s[112:128]) - xor.BytesSrc1(d[112:128], s[112:128], next) - base += 128 - } - - switch left { - case 7: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += 16 - fallthrough - case 6: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += 16 - fallthrough - case 5: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += 16 - fallthrough - case 4: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += 16 - fallthrough - case 3: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += 16 - fallthrough - case 2: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += 16 - fallthrough - case 1: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += 16 - fallthrough - case 0: - xor.BytesSrc0(dst[base:], src[base:], tbl) - } -} - -func decryptVariant(block cipher.Block, dst, src, buf []byte) { - blocksize := block.BlockSize() - tbl := buf[:blocksize] - next := buf[blocksize:] - block.Encrypt(tbl, initialVector) - n := len(src) / blocksize - base := 0 - repeat := n / 8 - left := n % 8 - for i := 0; i < repeat; i++ { - // 1 - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - base += blocksize - - // 2 - block.Encrypt(tbl, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], next) - base += blocksize - - // 3 - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - base += blocksize - - // 4 - block.Encrypt(tbl, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], next) - base += blocksize - - // 5 - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - base += blocksize - - // 6 - block.Encrypt(tbl, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], next) - base += blocksize - - // 7 - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - base += blocksize - - // 8 - block.Encrypt(tbl, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], next) - base += blocksize - } - - switch left { - case 7: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += blocksize - fallthrough - case 6: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += blocksize - fallthrough - case 5: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += blocksize - fallthrough - case 4: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += blocksize - fallthrough - case 3: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += blocksize - fallthrough - case 2: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += blocksize - fallthrough - case 1: - block.Encrypt(next, src[base:]) - xor.BytesSrc1(dst[base:], src[base:], tbl) - tbl, next = next, tbl - base += blocksize - fallthrough - case 0: - xor.BytesSrc0(dst[base:], src[base:], tbl) - } -} diff --git a/vender/github.com/xtaci/kcp/crypt_test.go b/vender/github.com/xtaci/kcp/crypt_test.go deleted file mode 100644 index 2ef4dc8..0000000 --- a/vender/github.com/xtaci/kcp/crypt_test.go +++ /dev/null @@ -1,289 +0,0 @@ -package kcp - -import ( - "bytes" - "crypto/aes" - "crypto/md5" - "crypto/rand" - "crypto/sha1" - "hash/crc32" - "io" - "testing" -) - -func TestSM4(t *testing.T) { - bc, err := NewSM4BlockCrypt(pass[:16]) - if err != nil { - t.Fatal(err) - } - cryptTest(t, bc) -} - -func TestAES(t *testing.T) { - bc, err := NewAESBlockCrypt(pass[:32]) - if err != nil { - t.Fatal(err) - } - cryptTest(t, bc) -} - -func TestTEA(t *testing.T) { - bc, err := NewTEABlockCrypt(pass[:16]) - if err != nil { - t.Fatal(err) - } - cryptTest(t, bc) -} - -func TestXOR(t *testing.T) { - bc, err := NewSimpleXORBlockCrypt(pass[:32]) - if err != nil { - t.Fatal(err) - } - cryptTest(t, bc) -} - -func TestBlowfish(t *testing.T) { - bc, err := NewBlowfishBlockCrypt(pass[:32]) - if err != nil { - t.Fatal(err) - } - cryptTest(t, bc) -} - -func TestNone(t *testing.T) { - bc, err := NewNoneBlockCrypt(pass[:32]) - if err != nil { - t.Fatal(err) - } - cryptTest(t, bc) -} - -func TestCast5(t *testing.T) { - bc, err := NewCast5BlockCrypt(pass[:16]) - if err != nil { - t.Fatal(err) - } - cryptTest(t, bc) -} - -func Test3DES(t *testing.T) { - bc, err := NewTripleDESBlockCrypt(pass[:24]) - if err != nil { - t.Fatal(err) - } - cryptTest(t, bc) -} - -func TestTwofish(t *testing.T) { - bc, err := NewTwofishBlockCrypt(pass[:32]) - if err != nil { - t.Fatal(err) - } - cryptTest(t, bc) -} - -func TestXTEA(t *testing.T) { - bc, err := NewXTEABlockCrypt(pass[:16]) - if err != nil { - t.Fatal(err) - } - cryptTest(t, bc) -} - -func TestSalsa20(t *testing.T) { - bc, err := NewSalsa20BlockCrypt(pass[:32]) - if err != nil { - t.Fatal(err) - } - cryptTest(t, bc) -} - -func cryptTest(t *testing.T, bc BlockCrypt) { - data := make([]byte, mtuLimit) - io.ReadFull(rand.Reader, data) - dec := make([]byte, mtuLimit) - enc := make([]byte, mtuLimit) - bc.Encrypt(enc, data) - bc.Decrypt(dec, enc) - if !bytes.Equal(data, dec) { - t.Fail() - } -} - -func BenchmarkSM4(b *testing.B) { - bc, err := NewSM4BlockCrypt(pass[:16]) - if err != nil { - b.Fatal(err) - } - benchCrypt(b, bc) -} - -func BenchmarkAES128(b *testing.B) { - bc, err := NewAESBlockCrypt(pass[:16]) - if err != nil { - b.Fatal(err) - } - - benchCrypt(b, bc) -} - -func BenchmarkAES192(b *testing.B) { - bc, err := NewAESBlockCrypt(pass[:24]) - if err != nil { - b.Fatal(err) - } - - benchCrypt(b, bc) -} - -func BenchmarkAES256(b *testing.B) { - bc, err := NewAESBlockCrypt(pass[:32]) - if err != nil { - b.Fatal(err) - } - - benchCrypt(b, bc) -} - -func BenchmarkTEA(b *testing.B) { - bc, err := NewTEABlockCrypt(pass[:16]) - if err != nil { - b.Fatal(err) - } - benchCrypt(b, bc) -} - -func BenchmarkXOR(b *testing.B) { - bc, err := NewSimpleXORBlockCrypt(pass[:32]) - if err != nil { - b.Fatal(err) - } - benchCrypt(b, bc) -} - -func BenchmarkBlowfish(b *testing.B) { - bc, err := NewBlowfishBlockCrypt(pass[:32]) - if err != nil { - b.Fatal(err) - } - benchCrypt(b, bc) -} - -func BenchmarkNone(b *testing.B) { - bc, err := NewNoneBlockCrypt(pass[:32]) - if err != nil { - b.Fatal(err) - } - benchCrypt(b, bc) -} - -func BenchmarkCast5(b *testing.B) { - bc, err := NewCast5BlockCrypt(pass[:16]) - if err != nil { - b.Fatal(err) - } - benchCrypt(b, bc) -} - -func Benchmark3DES(b *testing.B) { - bc, err := NewTripleDESBlockCrypt(pass[:24]) - if err != nil { - b.Fatal(err) - } - benchCrypt(b, bc) -} - -func BenchmarkTwofish(b *testing.B) { - bc, err := NewTwofishBlockCrypt(pass[:32]) - if err != nil { - b.Fatal(err) - } - benchCrypt(b, bc) -} - -func BenchmarkXTEA(b *testing.B) { - bc, err := NewXTEABlockCrypt(pass[:16]) - if err != nil { - b.Fatal(err) - } - benchCrypt(b, bc) -} - -func BenchmarkSalsa20(b *testing.B) { - bc, err := NewSalsa20BlockCrypt(pass[:32]) - if err != nil { - b.Fatal(err) - } - benchCrypt(b, bc) -} - -func benchCrypt(b *testing.B, bc BlockCrypt) { - data := make([]byte, mtuLimit) - io.ReadFull(rand.Reader, data) - dec := make([]byte, mtuLimit) - enc := make([]byte, mtuLimit) - - b.ReportAllocs() - b.SetBytes(int64(len(enc) * 2)) - b.ResetTimer() - for i := 0; i < b.N; i++ { - bc.Encrypt(enc, data) - bc.Decrypt(dec, enc) - } -} - -func BenchmarkCRC32(b *testing.B) { - content := make([]byte, 1024) - b.SetBytes(int64(len(content))) - for i := 0; i < b.N; i++ { - crc32.ChecksumIEEE(content) - } -} - -func BenchmarkCsprngSystem(b *testing.B) { - data := make([]byte, md5.Size) - b.SetBytes(int64(len(data))) - - for i := 0; i < b.N; i++ { - io.ReadFull(rand.Reader, data) - } -} - -func BenchmarkCsprngMD5(b *testing.B) { - var data [md5.Size]byte - b.SetBytes(md5.Size) - - for i := 0; i < b.N; i++ { - data = md5.Sum(data[:]) - } -} -func BenchmarkCsprngSHA1(b *testing.B) { - var data [sha1.Size]byte - b.SetBytes(sha1.Size) - - for i := 0; i < b.N; i++ { - data = sha1.Sum(data[:]) - } -} - -func BenchmarkCsprngNonceMD5(b *testing.B) { - var ng nonceMD5 - ng.Init() - b.SetBytes(md5.Size) - data := make([]byte, md5.Size) - for i := 0; i < b.N; i++ { - ng.Fill(data) - } -} - -func BenchmarkCsprngNonceAES128(b *testing.B) { - var ng nonceAES128 - ng.Init() - - b.SetBytes(aes.BlockSize) - data := make([]byte, aes.BlockSize) - for i := 0; i < b.N; i++ { - ng.Fill(data) - } -} diff --git a/vender/github.com/xtaci/kcp/entropy.go b/vender/github.com/xtaci/kcp/entropy.go deleted file mode 100644 index 156c1cd..0000000 --- a/vender/github.com/xtaci/kcp/entropy.go +++ /dev/null @@ -1,52 +0,0 @@ -package kcp - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/md5" - "crypto/rand" - "io" -) - -// Entropy defines a entropy source -type Entropy interface { - Init() - Fill(nonce []byte) -} - -// nonceMD5 nonce generator for packet header -type nonceMD5 struct { - seed [md5.Size]byte -} - -func (n *nonceMD5) Init() { /*nothing required*/ } - -func (n *nonceMD5) Fill(nonce []byte) { - if n.seed[0] == 0 { // entropy update - io.ReadFull(rand.Reader, n.seed[:]) - } - n.seed = md5.Sum(n.seed[:]) - copy(nonce, n.seed[:]) -} - -// nonceAES128 nonce generator for packet headers -type nonceAES128 struct { - seed [aes.BlockSize]byte - block cipher.Block -} - -func (n *nonceAES128) Init() { - var key [16]byte //aes-128 - io.ReadFull(rand.Reader, key[:]) - io.ReadFull(rand.Reader, n.seed[:]) - block, _ := aes.NewCipher(key[:]) - n.block = block -} - -func (n *nonceAES128) Fill(nonce []byte) { - if n.seed[0] == 0 { // entropy update - io.ReadFull(rand.Reader, n.seed[:]) - } - n.block.Encrypt(n.seed[:], n.seed[:]) - copy(nonce, n.seed[:]) -} diff --git a/vender/github.com/xtaci/kcp/fec.go b/vender/github.com/xtaci/kcp/fec.go deleted file mode 100644 index 366637b..0000000 --- a/vender/github.com/xtaci/kcp/fec.go +++ /dev/null @@ -1,311 +0,0 @@ -package kcp - -import ( - "encoding/binary" - "sync/atomic" - - "github.com/klauspost/reedsolomon" -) - -const ( - fecHeaderSize = 6 - fecHeaderSizePlus2 = fecHeaderSize + 2 // plus 2B data size - typeData = 0xf1 - typeFEC = 0xf2 -) - -type ( - // fecPacket is a decoded FEC packet - fecPacket struct { - seqid uint32 - flag uint16 - data []byte - } - - // fecDecoder for decoding incoming packets - fecDecoder struct { - rxlimit int // queue size limit - dataShards int - parityShards int - shardSize int - rx []fecPacket // ordered receive queue - - // caches - decodeCache [][]byte - flagCache []bool - - // zeros - zeros []byte - - // RS decoder - codec reedsolomon.Encoder - } -) - -func newFECDecoder(rxlimit, dataShards, parityShards int) *fecDecoder { - if dataShards <= 0 || parityShards <= 0 { - return nil - } - if rxlimit < dataShards+parityShards { - return nil - } - - dec := new(fecDecoder) - dec.rxlimit = rxlimit - dec.dataShards = dataShards - dec.parityShards = parityShards - dec.shardSize = dataShards + parityShards - codec, err := reedsolomon.New(dataShards, parityShards) - if err != nil { - return nil - } - dec.codec = codec - dec.decodeCache = make([][]byte, dec.shardSize) - dec.flagCache = make([]bool, dec.shardSize) - dec.zeros = make([]byte, mtuLimit) - return dec -} - -// decodeBytes a fec packet -func (dec *fecDecoder) decodeBytes(data []byte) fecPacket { - var pkt fecPacket - pkt.seqid = binary.LittleEndian.Uint32(data) - pkt.flag = binary.LittleEndian.Uint16(data[4:]) - // allocate memory & copy - buf := xmitBuf.Get().([]byte)[:len(data)-6] - copy(buf, data[6:]) - pkt.data = buf - return pkt -} - -// decode a fec packet -func (dec *fecDecoder) decode(pkt fecPacket) (recovered [][]byte) { - // insertion - n := len(dec.rx) - 1 - insertIdx := 0 - for i := n; i >= 0; i-- { - if pkt.seqid == dec.rx[i].seqid { // de-duplicate - xmitBuf.Put(pkt.data) - return nil - } else if _itimediff(pkt.seqid, dec.rx[i].seqid) > 0 { // insertion - insertIdx = i + 1 - break - } - } - - // insert into ordered rx queue - if insertIdx == n+1 { - dec.rx = append(dec.rx, pkt) - } else { - dec.rx = append(dec.rx, fecPacket{}) - copy(dec.rx[insertIdx+1:], dec.rx[insertIdx:]) // shift right - dec.rx[insertIdx] = pkt - } - - // shard range for current packet - shardBegin := pkt.seqid - pkt.seqid%uint32(dec.shardSize) - shardEnd := shardBegin + uint32(dec.shardSize) - 1 - - // max search range in ordered queue for current shard - searchBegin := insertIdx - int(pkt.seqid%uint32(dec.shardSize)) - if searchBegin < 0 { - searchBegin = 0 - } - searchEnd := searchBegin + dec.shardSize - 1 - if searchEnd >= len(dec.rx) { - searchEnd = len(dec.rx) - 1 - } - - // re-construct datashards - if searchEnd-searchBegin+1 >= dec.dataShards { - var numshard, numDataShard, first, maxlen int - - // zero caches - shards := dec.decodeCache - shardsflag := dec.flagCache - for k := range dec.decodeCache { - shards[k] = nil - shardsflag[k] = false - } - - // shard assembly - for i := searchBegin; i <= searchEnd; i++ { - seqid := dec.rx[i].seqid - if _itimediff(seqid, shardEnd) > 0 { - break - } else if _itimediff(seqid, shardBegin) >= 0 { - shards[seqid%uint32(dec.shardSize)] = dec.rx[i].data - shardsflag[seqid%uint32(dec.shardSize)] = true - numshard++ - if dec.rx[i].flag == typeData { - numDataShard++ - } - if numshard == 1 { - first = i - } - if len(dec.rx[i].data) > maxlen { - maxlen = len(dec.rx[i].data) - } - } - } - - if numDataShard == dec.dataShards { - // case 1: no loss on data shards - dec.rx = dec.freeRange(first, numshard, dec.rx) - } else if numshard >= dec.dataShards { - // case 2: loss on data shards, but it's recoverable from parity shards - for k := range shards { - if shards[k] != nil { - dlen := len(shards[k]) - shards[k] = shards[k][:maxlen] - copy(shards[k][dlen:], dec.zeros) - } - } - if err := dec.codec.ReconstructData(shards); err == nil { - for k := range shards[:dec.dataShards] { - if !shardsflag[k] { - recovered = append(recovered, shards[k]) - } - } - } - dec.rx = dec.freeRange(first, numshard, dec.rx) - } - } - - // keep rxlimit - if len(dec.rx) > dec.rxlimit { - if dec.rx[0].flag == typeData { // track the unrecoverable data - atomic.AddUint64(&DefaultSnmp.FECShortShards, 1) - } - dec.rx = dec.freeRange(0, 1, dec.rx) - } - return -} - -// free a range of fecPacket, and zero for GC recycling -func (dec *fecDecoder) freeRange(first, n int, q []fecPacket) []fecPacket { - for i := first; i < first+n; i++ { // recycle buffer - xmitBuf.Put(q[i].data) - } - copy(q[first:], q[first+n:]) - for i := 0; i < n; i++ { // dereference data - q[len(q)-1-i].data = nil - } - return q[:len(q)-n] -} - -type ( - // fecEncoder for encoding outgoing packets - fecEncoder struct { - dataShards int - parityShards int - shardSize int - paws uint32 // Protect Against Wrapped Sequence numbers - next uint32 // next seqid - - shardCount int // count the number of datashards collected - maxSize int // track maximum data length in datashard - - headerOffset int // FEC header offset - payloadOffset int // FEC payload offset - - // caches - shardCache [][]byte - encodeCache [][]byte - - // zeros - zeros []byte - - // RS encoder - codec reedsolomon.Encoder - } -) - -func newFECEncoder(dataShards, parityShards, offset int) *fecEncoder { - if dataShards <= 0 || parityShards <= 0 { - return nil - } - enc := new(fecEncoder) - enc.dataShards = dataShards - enc.parityShards = parityShards - enc.shardSize = dataShards + parityShards - enc.paws = (0xffffffff/uint32(enc.shardSize) - 1) * uint32(enc.shardSize) - enc.headerOffset = offset - enc.payloadOffset = enc.headerOffset + fecHeaderSize - - codec, err := reedsolomon.New(dataShards, parityShards) - if err != nil { - return nil - } - enc.codec = codec - - // caches - enc.encodeCache = make([][]byte, enc.shardSize) - enc.shardCache = make([][]byte, enc.shardSize) - for k := range enc.shardCache { - enc.shardCache[k] = make([]byte, mtuLimit) - } - enc.zeros = make([]byte, mtuLimit) - return enc -} - -// encodes the packet, outputs parity shards if we have collected quorum datashards -// notice: the contents of 'ps' will be re-written in successive calling -func (enc *fecEncoder) encode(b []byte) (ps [][]byte) { - enc.markData(b[enc.headerOffset:]) - binary.LittleEndian.PutUint16(b[enc.payloadOffset:], uint16(len(b[enc.payloadOffset:]))) - - // copy data to fec datashards - sz := len(b) - enc.shardCache[enc.shardCount] = enc.shardCache[enc.shardCount][:sz] - copy(enc.shardCache[enc.shardCount], b) - enc.shardCount++ - - // track max datashard length - if sz > enc.maxSize { - enc.maxSize = sz - } - - // Generation of Reed-Solomon Erasure Code - if enc.shardCount == enc.dataShards { - // fill '0' into the tail of each datashard - for i := 0; i < enc.dataShards; i++ { - shard := enc.shardCache[i] - slen := len(shard) - copy(shard[slen:enc.maxSize], enc.zeros) - } - - // construct equal-sized slice with stripped header - cache := enc.encodeCache - for k := range cache { - cache[k] = enc.shardCache[k][enc.payloadOffset:enc.maxSize] - } - - // encoding - if err := enc.codec.Encode(cache); err == nil { - ps = enc.shardCache[enc.dataShards:] - for k := range ps { - enc.markFEC(ps[k][enc.headerOffset:]) - ps[k] = ps[k][:enc.maxSize] - } - } - - // counters resetting - enc.shardCount = 0 - enc.maxSize = 0 - } - - return -} - -func (enc *fecEncoder) markData(data []byte) { - binary.LittleEndian.PutUint32(data, enc.next) - binary.LittleEndian.PutUint16(data[4:], typeData) - enc.next++ -} - -func (enc *fecEncoder) markFEC(data []byte) { - binary.LittleEndian.PutUint32(data, enc.next) - binary.LittleEndian.PutUint16(data[4:], typeFEC) - enc.next = (enc.next + 1) % enc.paws -} diff --git a/vender/github.com/xtaci/kcp/fec_test.go b/vender/github.com/xtaci/kcp/fec_test.go deleted file mode 100644 index 9279f00..0000000 --- a/vender/github.com/xtaci/kcp/fec_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package kcp - -import ( - "math/rand" - "testing" -) - -func BenchmarkFECDecode(b *testing.B) { - const dataSize = 10 - const paritySize = 3 - const payLoad = 1500 - decoder := newFECDecoder(1024, dataSize, paritySize) - b.ReportAllocs() - b.SetBytes(payLoad) - for i := 0; i < b.N; i++ { - if rand.Int()%(dataSize+paritySize) == 0 { // random loss - continue - } - var pkt fecPacket - pkt.seqid = uint32(i) - if i%(dataSize+paritySize) >= dataSize { - pkt.flag = typeFEC - } else { - pkt.flag = typeData - } - pkt.data = make([]byte, payLoad) - decoder.decode(pkt) - } -} - -func BenchmarkFECEncode(b *testing.B) { - const dataSize = 10 - const paritySize = 3 - const payLoad = 1500 - - b.ReportAllocs() - b.SetBytes(payLoad) - encoder := newFECEncoder(dataSize, paritySize, 0) - for i := 0; i < b.N; i++ { - data := make([]byte, payLoad) - encoder.encode(data) - } -} diff --git a/vender/github.com/xtaci/kcp/kcp.go b/vender/github.com/xtaci/kcp/kcp.go deleted file mode 100644 index 6bfb04e..0000000 --- a/vender/github.com/xtaci/kcp/kcp.go +++ /dev/null @@ -1,1012 +0,0 @@ -// Package kcp - A Fast and Reliable ARQ Protocol -package kcp - -import ( - "encoding/binary" - "sync/atomic" -) - -const ( - IKCP_RTO_NDL = 30 // no delay min rto - IKCP_RTO_MIN = 100 // normal min rto - IKCP_RTO_DEF = 200 - IKCP_RTO_MAX = 60000 - IKCP_CMD_PUSH = 81 // cmd: push data - IKCP_CMD_ACK = 82 // cmd: ack - IKCP_CMD_WASK = 83 // cmd: window probe (ask) - IKCP_CMD_WINS = 84 // cmd: window size (tell) - IKCP_ASK_SEND = 1 // need to send IKCP_CMD_WASK - IKCP_ASK_TELL = 2 // need to send IKCP_CMD_WINS - IKCP_WND_SND = 32 - IKCP_WND_RCV = 32 - IKCP_MTU_DEF = 1400 - IKCP_ACK_FAST = 3 - IKCP_INTERVAL = 100 - IKCP_OVERHEAD = 24 - IKCP_DEADLINK = 20 - IKCP_THRESH_INIT = 2 - IKCP_THRESH_MIN = 2 - IKCP_PROBE_INIT = 7000 // 7 secs to probe window size - IKCP_PROBE_LIMIT = 120000 // up to 120 secs to probe window -) - -// output_callback is a prototype which ought capture conn and call conn.Write -type output_callback func(buf []byte, size int) - -/* encode 8 bits unsigned int */ -func ikcp_encode8u(p []byte, c byte) []byte { - p[0] = c - return p[1:] -} - -/* decode 8 bits unsigned int */ -func ikcp_decode8u(p []byte, c *byte) []byte { - *c = p[0] - return p[1:] -} - -/* encode 16 bits unsigned int (lsb) */ -func ikcp_encode16u(p []byte, w uint16) []byte { - binary.LittleEndian.PutUint16(p, w) - return p[2:] -} - -/* decode 16 bits unsigned int (lsb) */ -func ikcp_decode16u(p []byte, w *uint16) []byte { - *w = binary.LittleEndian.Uint16(p) - return p[2:] -} - -/* encode 32 bits unsigned int (lsb) */ -func ikcp_encode32u(p []byte, l uint32) []byte { - binary.LittleEndian.PutUint32(p, l) - return p[4:] -} - -/* decode 32 bits unsigned int (lsb) */ -func ikcp_decode32u(p []byte, l *uint32) []byte { - *l = binary.LittleEndian.Uint32(p) - return p[4:] -} - -func _imin_(a, b uint32) uint32 { - if a <= b { - return a - } - return b -} - -func _imax_(a, b uint32) uint32 { - if a >= b { - return a - } - return b -} - -func _ibound_(lower, middle, upper uint32) uint32 { - return _imin_(_imax_(lower, middle), upper) -} - -func _itimediff(later, earlier uint32) int32 { - return (int32)(later - earlier) -} - -// segment defines a KCP segment -type segment struct { - conv uint32 - cmd uint8 - frg uint8 - wnd uint16 - ts uint32 - sn uint32 - una uint32 - rto uint32 - xmit uint32 - resendts uint32 - fastack uint32 - acked uint32 // mark if the seg has acked - data []byte -} - -// encode a segment into buffer -func (seg *segment) encode(ptr []byte) []byte { - ptr = ikcp_encode32u(ptr, seg.conv) - ptr = ikcp_encode8u(ptr, seg.cmd) - ptr = ikcp_encode8u(ptr, seg.frg) - ptr = ikcp_encode16u(ptr, seg.wnd) - ptr = ikcp_encode32u(ptr, seg.ts) - ptr = ikcp_encode32u(ptr, seg.sn) - ptr = ikcp_encode32u(ptr, seg.una) - ptr = ikcp_encode32u(ptr, uint32(len(seg.data))) - atomic.AddUint64(&DefaultSnmp.OutSegs, 1) - return ptr -} - -// KCP defines a single KCP connection -type KCP struct { - conv, mtu, mss, state uint32 - snd_una, snd_nxt, rcv_nxt uint32 - ssthresh uint32 - rx_rttvar, rx_srtt int32 - rx_rto, rx_minrto uint32 - snd_wnd, rcv_wnd, rmt_wnd, cwnd, probe uint32 - interval, ts_flush uint32 - nodelay, updated uint32 - ts_probe, probe_wait uint32 - dead_link, incr uint32 - - fastresend int32 - nocwnd, stream int32 - - snd_queue []segment - rcv_queue []segment - snd_buf []segment - rcv_buf []segment - - acklist []ackItem - - buffer []byte - output output_callback -} - -type ackItem struct { - sn uint32 - ts uint32 -} - -// NewKCP create a new kcp control object, 'conv' must equal in two endpoint -// from the same connection. -func NewKCP(conv uint32, output output_callback) *KCP { - kcp := new(KCP) - kcp.conv = conv - kcp.snd_wnd = IKCP_WND_SND - kcp.rcv_wnd = IKCP_WND_RCV - kcp.rmt_wnd = IKCP_WND_RCV - kcp.mtu = IKCP_MTU_DEF - kcp.mss = kcp.mtu - IKCP_OVERHEAD - kcp.buffer = make([]byte, (kcp.mtu+IKCP_OVERHEAD)*3) - kcp.rx_rto = IKCP_RTO_DEF - kcp.rx_minrto = IKCP_RTO_MIN - kcp.interval = IKCP_INTERVAL - kcp.ts_flush = IKCP_INTERVAL - kcp.ssthresh = IKCP_THRESH_INIT - kcp.dead_link = IKCP_DEADLINK - kcp.output = output - return kcp -} - -// newSegment creates a KCP segment -func (kcp *KCP) newSegment(size int) (seg segment) { - seg.data = xmitBuf.Get().([]byte)[:size] - return -} - -// delSegment recycles a KCP segment -func (kcp *KCP) delSegment(seg *segment) { - if seg.data != nil { - xmitBuf.Put(seg.data) - seg.data = nil - } -} - -// PeekSize checks the size of next message in the recv queue -func (kcp *KCP) PeekSize() (length int) { - if len(kcp.rcv_queue) == 0 { - return -1 - } - - seg := &kcp.rcv_queue[0] - if seg.frg == 0 { - return len(seg.data) - } - - if len(kcp.rcv_queue) < int(seg.frg+1) { - return -1 - } - - for k := range kcp.rcv_queue { - seg := &kcp.rcv_queue[k] - length += len(seg.data) - if seg.frg == 0 { - break - } - } - return -} - -// Recv is user/upper level recv: returns size, returns below zero for EAGAIN -func (kcp *KCP) Recv(buffer []byte) (n int) { - if len(kcp.rcv_queue) == 0 { - return -1 - } - - peeksize := kcp.PeekSize() - if peeksize < 0 { - return -2 - } - - if peeksize > len(buffer) { - return -3 - } - - var fast_recover bool - if len(kcp.rcv_queue) >= int(kcp.rcv_wnd) { - fast_recover = true - } - - // merge fragment - count := 0 - for k := range kcp.rcv_queue { - seg := &kcp.rcv_queue[k] - copy(buffer, seg.data) - buffer = buffer[len(seg.data):] - n += len(seg.data) - count++ - kcp.delSegment(seg) - if seg.frg == 0 { - break - } - } - if count > 0 { - kcp.rcv_queue = kcp.remove_front(kcp.rcv_queue, count) - } - - // move available data from rcv_buf -> rcv_queue - count = 0 - for k := range kcp.rcv_buf { - seg := &kcp.rcv_buf[k] - if seg.sn == kcp.rcv_nxt && len(kcp.rcv_queue) < int(kcp.rcv_wnd) { - kcp.rcv_nxt++ - count++ - } else { - break - } - } - - if count > 0 { - kcp.rcv_queue = append(kcp.rcv_queue, kcp.rcv_buf[:count]...) - kcp.rcv_buf = kcp.remove_front(kcp.rcv_buf, count) - } - - // fast recover - if len(kcp.rcv_queue) < int(kcp.rcv_wnd) && fast_recover { - // ready to send back IKCP_CMD_WINS in ikcp_flush - // tell remote my window size - kcp.probe |= IKCP_ASK_TELL - } - return -} - -// Send is user/upper level send, returns below zero for error -func (kcp *KCP) Send(buffer []byte) int { - var count int - if len(buffer) == 0 { - return -1 - } - - // append to previous segment in streaming mode (if possible) - if kcp.stream != 0 { - n := len(kcp.snd_queue) - if n > 0 { - seg := &kcp.snd_queue[n-1] - if len(seg.data) < int(kcp.mss) { - capacity := int(kcp.mss) - len(seg.data) - extend := capacity - if len(buffer) < capacity { - extend = len(buffer) - } - - // grow slice, the underlying cap is guaranteed to - // be larger than kcp.mss - oldlen := len(seg.data) - seg.data = seg.data[:oldlen+extend] - copy(seg.data[oldlen:], buffer) - buffer = buffer[extend:] - } - } - - if len(buffer) == 0 { - return 0 - } - } - - if len(buffer) <= int(kcp.mss) { - count = 1 - } else { - count = (len(buffer) + int(kcp.mss) - 1) / int(kcp.mss) - } - - if count > 255 { - return -2 - } - - if count == 0 { - count = 1 - } - - for i := 0; i < count; i++ { - var size int - if len(buffer) > int(kcp.mss) { - size = int(kcp.mss) - } else { - size = len(buffer) - } - seg := kcp.newSegment(size) - copy(seg.data, buffer[:size]) - if kcp.stream == 0 { // message mode - seg.frg = uint8(count - i - 1) - } else { // stream mode - seg.frg = 0 - } - kcp.snd_queue = append(kcp.snd_queue, seg) - buffer = buffer[size:] - } - return 0 -} - -func (kcp *KCP) update_ack(rtt int32) { - // https://tools.ietf.org/html/rfc6298 - var rto uint32 - if kcp.rx_srtt == 0 { - kcp.rx_srtt = rtt - kcp.rx_rttvar = rtt >> 1 - } else { - delta := rtt - kcp.rx_srtt - kcp.rx_srtt += delta >> 3 - if delta < 0 { - delta = -delta - } - if rtt < kcp.rx_srtt-kcp.rx_rttvar { - // if the new RTT sample is below the bottom of the range of - // what an RTT measurement is expected to be. - // give an 8x reduced weight versus its normal weighting - kcp.rx_rttvar += (delta - kcp.rx_rttvar) >> 5 - } else { - kcp.rx_rttvar += (delta - kcp.rx_rttvar) >> 2 - } - } - rto = uint32(kcp.rx_srtt) + _imax_(kcp.interval, uint32(kcp.rx_rttvar)<<2) - kcp.rx_rto = _ibound_(kcp.rx_minrto, rto, IKCP_RTO_MAX) -} - -func (kcp *KCP) shrink_buf() { - if len(kcp.snd_buf) > 0 { - seg := &kcp.snd_buf[0] - kcp.snd_una = seg.sn - } else { - kcp.snd_una = kcp.snd_nxt - } -} - -func (kcp *KCP) parse_ack(sn uint32) { - if _itimediff(sn, kcp.snd_una) < 0 || _itimediff(sn, kcp.snd_nxt) >= 0 { - return - } - - for k := range kcp.snd_buf { - seg := &kcp.snd_buf[k] - if sn == seg.sn { - seg.acked = 1 - kcp.delSegment(seg) - break - } - if _itimediff(sn, seg.sn) < 0 { - break - } - } -} - -func (kcp *KCP) parse_fastack(sn, ts uint32) { - if _itimediff(sn, kcp.snd_una) < 0 || _itimediff(sn, kcp.snd_nxt) >= 0 { - return - } - - for k := range kcp.snd_buf { - seg := &kcp.snd_buf[k] - if _itimediff(sn, seg.sn) < 0 { - break - } else if sn != seg.sn && _itimediff(seg.ts, ts) <= 0 { - seg.fastack++ - } - } -} - -func (kcp *KCP) parse_una(una uint32) { - count := 0 - for k := range kcp.snd_buf { - seg := &kcp.snd_buf[k] - if _itimediff(una, seg.sn) > 0 { - kcp.delSegment(seg) - count++ - } else { - break - } - } - if count > 0 { - kcp.snd_buf = kcp.remove_front(kcp.snd_buf, count) - } -} - -// ack append -func (kcp *KCP) ack_push(sn, ts uint32) { - kcp.acklist = append(kcp.acklist, ackItem{sn, ts}) -} - -// returns true if data has repeated -func (kcp *KCP) parse_data(newseg segment) bool { - sn := newseg.sn - if _itimediff(sn, kcp.rcv_nxt+kcp.rcv_wnd) >= 0 || - _itimediff(sn, kcp.rcv_nxt) < 0 { - return true - } - - n := len(kcp.rcv_buf) - 1 - insert_idx := 0 - repeat := false - for i := n; i >= 0; i-- { - seg := &kcp.rcv_buf[i] - if seg.sn == sn { - repeat = true - break - } - if _itimediff(sn, seg.sn) > 0 { - insert_idx = i + 1 - break - } - } - - if !repeat { - // replicate the content if it's new - dataCopy := xmitBuf.Get().([]byte)[:len(newseg.data)] - copy(dataCopy, newseg.data) - newseg.data = dataCopy - - if insert_idx == n+1 { - kcp.rcv_buf = append(kcp.rcv_buf, newseg) - } else { - kcp.rcv_buf = append(kcp.rcv_buf, segment{}) - copy(kcp.rcv_buf[insert_idx+1:], kcp.rcv_buf[insert_idx:]) - kcp.rcv_buf[insert_idx] = newseg - } - } - - // move available data from rcv_buf -> rcv_queue - count := 0 - for k := range kcp.rcv_buf { - seg := &kcp.rcv_buf[k] - if seg.sn == kcp.rcv_nxt && len(kcp.rcv_queue) < int(kcp.rcv_wnd) { - kcp.rcv_nxt++ - count++ - } else { - break - } - } - if count > 0 { - kcp.rcv_queue = append(kcp.rcv_queue, kcp.rcv_buf[:count]...) - kcp.rcv_buf = kcp.remove_front(kcp.rcv_buf, count) - } - - return repeat -} - -// Input when you received a low level packet (eg. UDP packet), call it -// regular indicates a regular packet has received(not from FEC) -func (kcp *KCP) Input(data []byte, regular, ackNoDelay bool) int { - snd_una := kcp.snd_una - if len(data) < IKCP_OVERHEAD { - return -1 - } - - var latest uint32 // the latest ack packet - var flag int - var inSegs uint64 - - for { - var ts, sn, length, una, conv uint32 - var wnd uint16 - var cmd, frg uint8 - - if len(data) < int(IKCP_OVERHEAD) { - break - } - - data = ikcp_decode32u(data, &conv) - if conv != kcp.conv { - return -1 - } - - data = ikcp_decode8u(data, &cmd) - data = ikcp_decode8u(data, &frg) - data = ikcp_decode16u(data, &wnd) - data = ikcp_decode32u(data, &ts) - data = ikcp_decode32u(data, &sn) - data = ikcp_decode32u(data, &una) - data = ikcp_decode32u(data, &length) - if len(data) < int(length) { - return -2 - } - - if cmd != IKCP_CMD_PUSH && cmd != IKCP_CMD_ACK && - cmd != IKCP_CMD_WASK && cmd != IKCP_CMD_WINS { - return -3 - } - - // only trust window updates from regular packets. i.e: latest update - if regular { - kcp.rmt_wnd = uint32(wnd) - } - kcp.parse_una(una) - kcp.shrink_buf() - - if cmd == IKCP_CMD_ACK { - kcp.parse_ack(sn) - kcp.parse_fastack(sn, ts) - flag |= 1 - latest = ts - } else if cmd == IKCP_CMD_PUSH { - repeat := true - if _itimediff(sn, kcp.rcv_nxt+kcp.rcv_wnd) < 0 { - kcp.ack_push(sn, ts) - if _itimediff(sn, kcp.rcv_nxt) >= 0 { - var seg segment - seg.conv = conv - seg.cmd = cmd - seg.frg = frg - seg.wnd = wnd - seg.ts = ts - seg.sn = sn - seg.una = una - seg.data = data[:length] // delayed data copying - repeat = kcp.parse_data(seg) - } - } - if regular && repeat { - atomic.AddUint64(&DefaultSnmp.RepeatSegs, 1) - } - } else if cmd == IKCP_CMD_WASK { - // ready to send back IKCP_CMD_WINS in Ikcp_flush - // tell remote my window size - kcp.probe |= IKCP_ASK_TELL - } else if cmd == IKCP_CMD_WINS { - // do nothing - } else { - return -3 - } - - inSegs++ - data = data[length:] - } - atomic.AddUint64(&DefaultSnmp.InSegs, inSegs) - - // update rtt with the latest ts - // ignore the FEC packet - if flag != 0 && regular { - current := currentMs() - if _itimediff(current, latest) >= 0 { - kcp.update_ack(_itimediff(current, latest)) - } - } - - // cwnd update when packet arrived - if kcp.nocwnd == 0 { - if _itimediff(kcp.snd_una, snd_una) > 0 { - if kcp.cwnd < kcp.rmt_wnd { - mss := kcp.mss - if kcp.cwnd < kcp.ssthresh { - kcp.cwnd++ - kcp.incr += mss - } else { - if kcp.incr < mss { - kcp.incr = mss - } - kcp.incr += (mss*mss)/kcp.incr + (mss / 16) - if (kcp.cwnd+1)*mss <= kcp.incr { - kcp.cwnd++ - } - } - if kcp.cwnd > kcp.rmt_wnd { - kcp.cwnd = kcp.rmt_wnd - kcp.incr = kcp.rmt_wnd * mss - } - } - } - } - - if ackNoDelay && len(kcp.acklist) > 0 { // ack immediately - kcp.flush(true) - } - return 0 -} - -func (kcp *KCP) wnd_unused() uint16 { - if len(kcp.rcv_queue) < int(kcp.rcv_wnd) { - return uint16(int(kcp.rcv_wnd) - len(kcp.rcv_queue)) - } - return 0 -} - -// flush pending data -func (kcp *KCP) flush(ackOnly bool) uint32 { - var seg segment - seg.conv = kcp.conv - seg.cmd = IKCP_CMD_ACK - seg.wnd = kcp.wnd_unused() - seg.una = kcp.rcv_nxt - - buffer := kcp.buffer - // flush acknowledges - ptr := buffer - for i, ack := range kcp.acklist { - size := len(buffer) - len(ptr) - if size+IKCP_OVERHEAD > int(kcp.mtu) { - kcp.output(buffer, size) - ptr = buffer - } - // filter jitters caused by bufferbloat - if ack.sn >= kcp.rcv_nxt || len(kcp.acklist)-1 == i { - seg.sn, seg.ts = ack.sn, ack.ts - ptr = seg.encode(ptr) - } - } - kcp.acklist = kcp.acklist[0:0] - - if ackOnly { // flash remain ack segments - size := len(buffer) - len(ptr) - if size > 0 { - kcp.output(buffer, size) - } - return kcp.interval - } - - // probe window size (if remote window size equals zero) - if kcp.rmt_wnd == 0 { - current := currentMs() - if kcp.probe_wait == 0 { - kcp.probe_wait = IKCP_PROBE_INIT - kcp.ts_probe = current + kcp.probe_wait - } else { - if _itimediff(current, kcp.ts_probe) >= 0 { - if kcp.probe_wait < IKCP_PROBE_INIT { - kcp.probe_wait = IKCP_PROBE_INIT - } - kcp.probe_wait += kcp.probe_wait / 2 - if kcp.probe_wait > IKCP_PROBE_LIMIT { - kcp.probe_wait = IKCP_PROBE_LIMIT - } - kcp.ts_probe = current + kcp.probe_wait - kcp.probe |= IKCP_ASK_SEND - } - } - } else { - kcp.ts_probe = 0 - kcp.probe_wait = 0 - } - - // flush window probing commands - if (kcp.probe & IKCP_ASK_SEND) != 0 { - seg.cmd = IKCP_CMD_WASK - size := len(buffer) - len(ptr) - if size+IKCP_OVERHEAD > int(kcp.mtu) { - kcp.output(buffer, size) - ptr = buffer - } - ptr = seg.encode(ptr) - } - - // flush window probing commands - if (kcp.probe & IKCP_ASK_TELL) != 0 { - seg.cmd = IKCP_CMD_WINS - size := len(buffer) - len(ptr) - if size+IKCP_OVERHEAD > int(kcp.mtu) { - kcp.output(buffer, size) - ptr = buffer - } - ptr = seg.encode(ptr) - } - - kcp.probe = 0 - - // calculate window size - cwnd := _imin_(kcp.snd_wnd, kcp.rmt_wnd) - if kcp.nocwnd == 0 { - cwnd = _imin_(kcp.cwnd, cwnd) - } - - // sliding window, controlled by snd_nxt && sna_una+cwnd - newSegsCount := 0 - for k := range kcp.snd_queue { - if _itimediff(kcp.snd_nxt, kcp.snd_una+cwnd) >= 0 { - break - } - newseg := kcp.snd_queue[k] - newseg.conv = kcp.conv - newseg.cmd = IKCP_CMD_PUSH - newseg.sn = kcp.snd_nxt - kcp.snd_buf = append(kcp.snd_buf, newseg) - kcp.snd_nxt++ - newSegsCount++ - } - if newSegsCount > 0 { - kcp.snd_queue = kcp.remove_front(kcp.snd_queue, newSegsCount) - } - - // calculate resent - resent := uint32(kcp.fastresend) - if kcp.fastresend <= 0 { - resent = 0xffffffff - } - - // check for retransmissions - current := currentMs() - var change, lost, lostSegs, fastRetransSegs, earlyRetransSegs uint64 - minrto := int32(kcp.interval) - - ref := kcp.snd_buf[:len(kcp.snd_buf)] // for bounds check elimination - for k := range ref { - segment := &ref[k] - needsend := false - if segment.acked == 1 { - continue - } - if segment.xmit == 0 { // initial transmit - needsend = true - segment.rto = kcp.rx_rto - segment.resendts = current + segment.rto - } else if _itimediff(current, segment.resendts) >= 0 { // RTO - needsend = true - if kcp.nodelay == 0 { - segment.rto += kcp.rx_rto - } else { - segment.rto += kcp.rx_rto / 2 - } - segment.resendts = current + segment.rto - lost++ - lostSegs++ - } else if segment.fastack >= resent { // fast retransmit - needsend = true - segment.fastack = 0 - segment.rto = kcp.rx_rto - segment.resendts = current + segment.rto - change++ - fastRetransSegs++ - } else if segment.fastack > 0 && newSegsCount == 0 { // early retransmit - needsend = true - segment.fastack = 0 - segment.rto = kcp.rx_rto - segment.resendts = current + segment.rto - change++ - earlyRetransSegs++ - } - - if needsend { - current = currentMs() // time update for a blocking call - segment.xmit++ - segment.ts = current - segment.wnd = seg.wnd - segment.una = seg.una - - size := len(buffer) - len(ptr) - need := IKCP_OVERHEAD + len(segment.data) - - if size+need > int(kcp.mtu) { - kcp.output(buffer, size) - ptr = buffer - } - - ptr = segment.encode(ptr) - copy(ptr, segment.data) - ptr = ptr[len(segment.data):] - - if segment.xmit >= kcp.dead_link { - kcp.state = 0xFFFFFFFF - } - } - - // get the nearest rto - if rto := _itimediff(segment.resendts, current); rto > 0 && rto < minrto { - minrto = rto - } - } - - // flash remain segments - size := len(buffer) - len(ptr) - if size > 0 { - kcp.output(buffer, size) - } - - // counter updates - sum := lostSegs - if lostSegs > 0 { - atomic.AddUint64(&DefaultSnmp.LostSegs, lostSegs) - } - if fastRetransSegs > 0 { - atomic.AddUint64(&DefaultSnmp.FastRetransSegs, fastRetransSegs) - sum += fastRetransSegs - } - if earlyRetransSegs > 0 { - atomic.AddUint64(&DefaultSnmp.EarlyRetransSegs, earlyRetransSegs) - sum += earlyRetransSegs - } - if sum > 0 { - atomic.AddUint64(&DefaultSnmp.RetransSegs, sum) - } - - // cwnd update - if kcp.nocwnd == 0 { - // update ssthresh - // rate halving, https://tools.ietf.org/html/rfc6937 - if change > 0 { - inflight := kcp.snd_nxt - kcp.snd_una - kcp.ssthresh = inflight / 2 - if kcp.ssthresh < IKCP_THRESH_MIN { - kcp.ssthresh = IKCP_THRESH_MIN - } - kcp.cwnd = kcp.ssthresh + resent - kcp.incr = kcp.cwnd * kcp.mss - } - - // congestion control, https://tools.ietf.org/html/rfc5681 - if lost > 0 { - kcp.ssthresh = cwnd / 2 - if kcp.ssthresh < IKCP_THRESH_MIN { - kcp.ssthresh = IKCP_THRESH_MIN - } - kcp.cwnd = 1 - kcp.incr = kcp.mss - } - - if kcp.cwnd < 1 { - kcp.cwnd = 1 - kcp.incr = kcp.mss - } - } - - return uint32(minrto) -} - -// Update updates state (call it repeatedly, every 10ms-100ms), or you can ask -// ikcp_check when to call it again (without ikcp_input/_send calling). -// 'current' - current timestamp in millisec. -func (kcp *KCP) Update() { - var slap int32 - - current := currentMs() - if kcp.updated == 0 { - kcp.updated = 1 - kcp.ts_flush = current - } - - slap = _itimediff(current, kcp.ts_flush) - - if slap >= 10000 || slap < -10000 { - kcp.ts_flush = current - slap = 0 - } - - if slap >= 0 { - kcp.ts_flush += kcp.interval - if _itimediff(current, kcp.ts_flush) >= 0 { - kcp.ts_flush = current + kcp.interval - } - kcp.flush(false) - } -} - -// Check determines when should you invoke ikcp_update: -// returns when you should invoke ikcp_update in millisec, if there -// is no ikcp_input/_send calling. you can call ikcp_update in that -// time, instead of call update repeatly. -// Important to reduce unnacessary ikcp_update invoking. use it to -// schedule ikcp_update (eg. implementing an epoll-like mechanism, -// or optimize ikcp_update when handling massive kcp connections) -func (kcp *KCP) Check() uint32 { - current := currentMs() - ts_flush := kcp.ts_flush - tm_flush := int32(0x7fffffff) - tm_packet := int32(0x7fffffff) - minimal := uint32(0) - if kcp.updated == 0 { - return current - } - - if _itimediff(current, ts_flush) >= 10000 || - _itimediff(current, ts_flush) < -10000 { - ts_flush = current - } - - if _itimediff(current, ts_flush) >= 0 { - return current - } - - tm_flush = _itimediff(ts_flush, current) - - for k := range kcp.snd_buf { - seg := &kcp.snd_buf[k] - diff := _itimediff(seg.resendts, current) - if diff <= 0 { - return current - } - if diff < tm_packet { - tm_packet = diff - } - } - - minimal = uint32(tm_packet) - if tm_packet >= tm_flush { - minimal = uint32(tm_flush) - } - if minimal >= kcp.interval { - minimal = kcp.interval - } - - return current + minimal -} - -// SetMtu changes MTU size, default is 1400 -func (kcp *KCP) SetMtu(mtu int) int { - if mtu < 50 || mtu < IKCP_OVERHEAD { - return -1 - } - buffer := make([]byte, (mtu+IKCP_OVERHEAD)*3) - if buffer == nil { - return -2 - } - kcp.mtu = uint32(mtu) - kcp.mss = kcp.mtu - IKCP_OVERHEAD - kcp.buffer = buffer - return 0 -} - -// NoDelay options -// fastest: ikcp_nodelay(kcp, 1, 20, 2, 1) -// nodelay: 0:disable(default), 1:enable -// interval: internal update timer interval in millisec, default is 100ms -// resend: 0:disable fast resend(default), 1:enable fast resend -// nc: 0:normal congestion control(default), 1:disable congestion control -func (kcp *KCP) NoDelay(nodelay, interval, resend, nc int) int { - if nodelay >= 0 { - kcp.nodelay = uint32(nodelay) - if nodelay != 0 { - kcp.rx_minrto = IKCP_RTO_NDL - } else { - kcp.rx_minrto = IKCP_RTO_MIN - } - } - if interval >= 0 { - if interval > 5000 { - interval = 5000 - } else if interval < 10 { - interval = 10 - } - kcp.interval = uint32(interval) - } - if resend >= 0 { - kcp.fastresend = int32(resend) - } - if nc >= 0 { - kcp.nocwnd = int32(nc) - } - return 0 -} - -// WndSize sets maximum window size: sndwnd=32, rcvwnd=32 by default -func (kcp *KCP) WndSize(sndwnd, rcvwnd int) int { - if sndwnd > 0 { - kcp.snd_wnd = uint32(sndwnd) - } - if rcvwnd > 0 { - kcp.rcv_wnd = uint32(rcvwnd) - } - return 0 -} - -// WaitSnd gets how many packet is waiting to be sent -func (kcp *KCP) WaitSnd() int { - return len(kcp.snd_buf) + len(kcp.snd_queue) -} - -// remove front n elements from queue -func (kcp *KCP) remove_front(q []segment, n int) []segment { - newn := copy(q, q[n:]) - return q[:newn] -} diff --git a/vender/github.com/xtaci/kcp/kcp_test.go b/vender/github.com/xtaci/kcp/kcp_test.go deleted file mode 100644 index d06b061..0000000 --- a/vender/github.com/xtaci/kcp/kcp_test.go +++ /dev/null @@ -1,302 +0,0 @@ -package kcp - -import ( - "bytes" - "container/list" - "encoding/binary" - "fmt" - "math/rand" - "sync" - "testing" - "time" -) - -func iclock() int32 { - return int32(currentMs()) -} - -type DelayPacket struct { - _ptr []byte - _size int - _ts int32 -} - -func (p *DelayPacket) Init(size int, src []byte) { - p._ptr = make([]byte, size) - p._size = size - copy(p._ptr, src[:size]) -} - -func (p *DelayPacket) ptr() []byte { return p._ptr } -func (p *DelayPacket) size() int { return p._size } -func (p *DelayPacket) ts() int32 { return p._ts } -func (p *DelayPacket) setts(ts int32) { p._ts = ts } - -type DelayTunnel struct{ *list.List } -type LatencySimulator struct { - current int32 - lostrate, rttmin, rttmax, nmax int - p12 DelayTunnel - p21 DelayTunnel - r12 *rand.Rand - r21 *rand.Rand -} - -// lostrate: 往返一周丢包率的百分比,默认 10% -// rttmin:rtt最小值,默认 60 -// rttmax:rtt最大值,默认 125 -//func (p *LatencySimulator)Init(int lostrate = 10, int rttmin = 60, int rttmax = 125, int nmax = 1000): -func (p *LatencySimulator) Init(lostrate, rttmin, rttmax, nmax int) { - p.r12 = rand.New(rand.NewSource(9)) - p.r21 = rand.New(rand.NewSource(99)) - p.p12 = DelayTunnel{list.New()} - p.p21 = DelayTunnel{list.New()} - p.current = iclock() - p.lostrate = lostrate / 2 // 上面数据是往返丢包率,单程除以2 - p.rttmin = rttmin / 2 - p.rttmax = rttmax / 2 - p.nmax = nmax -} - -// 发送数据 -// peer - 端点0/1,从0发送,从1接收;从1发送从0接收 -func (p *LatencySimulator) send(peer int, data []byte, size int) int { - rnd := 0 - if peer == 0 { - rnd = p.r12.Intn(100) - } else { - rnd = p.r21.Intn(100) - } - //println("!!!!!!!!!!!!!!!!!!!!", rnd, p.lostrate, peer) - if rnd < p.lostrate { - return 0 - } - pkt := &DelayPacket{} - pkt.Init(size, data) - p.current = iclock() - delay := p.rttmin - if p.rttmax > p.rttmin { - delay += rand.Int() % (p.rttmax - p.rttmin) - } - pkt.setts(p.current + int32(delay)) - if peer == 0 { - p.p12.PushBack(pkt) - } else { - p.p21.PushBack(pkt) - } - return 1 -} - -// 接收数据 -func (p *LatencySimulator) recv(peer int, data []byte, maxsize int) int32 { - var it *list.Element - if peer == 0 { - it = p.p21.Front() - if p.p21.Len() == 0 { - return -1 - } - } else { - it = p.p12.Front() - if p.p12.Len() == 0 { - return -1 - } - } - pkt := it.Value.(*DelayPacket) - p.current = iclock() - if p.current < pkt.ts() { - return -2 - } - if maxsize < pkt.size() { - return -3 - } - if peer == 0 { - p.p21.Remove(it) - } else { - p.p12.Remove(it) - } - maxsize = pkt.size() - copy(data, pkt.ptr()[:maxsize]) - return int32(maxsize) -} - -//===================================================================== -//===================================================================== - -// 模拟网络 -var vnet *LatencySimulator - -// 测试用例 -func test(mode int) { - // 创建模拟网络:丢包率10%,Rtt 60ms~125ms - vnet = &LatencySimulator{} - vnet.Init(10, 60, 125, 1000) - - // 创建两个端点的 kcp对象,第一个参数 conv是会话编号,同一个会话需要相同 - // 最后一个是 user参数,用来传递标识 - output1 := func(buf []byte, size int) { - if vnet.send(0, buf, size) != 1 { - } - } - output2 := func(buf []byte, size int) { - if vnet.send(1, buf, size) != 1 { - } - } - kcp1 := NewKCP(0x11223344, output1) - kcp2 := NewKCP(0x11223344, output2) - - current := uint32(iclock()) - slap := current + 20 - index := 0 - next := 0 - var sumrtt uint32 - count := 0 - maxrtt := 0 - - // 配置窗口大小:平均延迟200ms,每20ms发送一个包, - // 而考虑到丢包重发,设置最大收发窗口为128 - kcp1.WndSize(128, 128) - kcp2.WndSize(128, 128) - - // 判断测试用例的模式 - if mode == 0 { - // 默认模式 - kcp1.NoDelay(0, 10, 0, 0) - kcp2.NoDelay(0, 10, 0, 0) - } else if mode == 1 { - // 普通模式,关闭流控等 - kcp1.NoDelay(0, 10, 0, 1) - kcp2.NoDelay(0, 10, 0, 1) - } else { - // 启动快速模式 - // 第二个参数 nodelay-启用以后若干常规加速将启动 - // 第三个参数 interval为内部处理时钟,默认设置为 10ms - // 第四个参数 resend为快速重传指标,设置为2 - // 第五个参数 为是否禁用常规流控,这里禁止 - kcp1.NoDelay(1, 10, 2, 1) - kcp2.NoDelay(1, 10, 2, 1) - } - - buffer := make([]byte, 2000) - var hr int32 - - ts1 := iclock() - - for { - time.Sleep(1 * time.Millisecond) - current = uint32(iclock()) - kcp1.Update() - kcp2.Update() - - // 每隔 20ms,kcp1发送数据 - for ; current >= slap; slap += 20 { - buf := new(bytes.Buffer) - binary.Write(buf, binary.LittleEndian, uint32(index)) - index++ - binary.Write(buf, binary.LittleEndian, uint32(current)) - // 发送上层协议包 - kcp1.Send(buf.Bytes()) - //println("now", iclock()) - } - - // 处理虚拟网络:检测是否有udp包从p1->p2 - for { - hr = vnet.recv(1, buffer, 2000) - if hr < 0 { - break - } - // 如果 p2收到udp,则作为下层协议输入到kcp2 - kcp2.Input(buffer[:hr], true, false) - } - - // 处理虚拟网络:检测是否有udp包从p2->p1 - for { - hr = vnet.recv(0, buffer, 2000) - if hr < 0 { - break - } - // 如果 p1收到udp,则作为下层协议输入到kcp1 - kcp1.Input(buffer[:hr], true, false) - //println("@@@@", hr, r) - } - - // kcp2接收到任何包都返回回去 - for { - hr = int32(kcp2.Recv(buffer[:10])) - // 没有收到包就退出 - if hr < 0 { - break - } - // 如果收到包就回射 - buf := bytes.NewReader(buffer) - var sn uint32 - binary.Read(buf, binary.LittleEndian, &sn) - kcp2.Send(buffer[:hr]) - } - - // kcp1收到kcp2的回射数据 - for { - hr = int32(kcp1.Recv(buffer[:10])) - buf := bytes.NewReader(buffer) - // 没有收到包就退出 - if hr < 0 { - break - } - var sn uint32 - var ts, rtt uint32 - binary.Read(buf, binary.LittleEndian, &sn) - binary.Read(buf, binary.LittleEndian, &ts) - rtt = uint32(current) - ts - - if sn != uint32(next) { - // 如果收到的包不连续 - //for i:=0;i<8 ;i++ { - //println("---", i, buffer[i]) - //} - println("ERROR sn ", count, "<->", next, sn) - return - } - - next++ - sumrtt += rtt - count++ - if rtt > uint32(maxrtt) { - maxrtt = int(rtt) - } - - //println("[RECV] mode=", mode, " sn=", sn, " rtt=", rtt) - } - - if next > 100 { - break - } - } - - ts1 = iclock() - ts1 - - names := []string{"default", "normal", "fast"} - fmt.Printf("%s mode result (%dms):\n", names[mode], ts1) - fmt.Printf("avgrtt=%d maxrtt=%d\n", int(sumrtt/uint32(count)), maxrtt) -} - -func TestNetwork(t *testing.T) { - test(0) // 默认模式,类似 TCP:正常模式,无快速重传,常规流控 - test(1) // 普通模式,关闭流控等 - test(2) // 快速模式,所有开关都打开,且关闭流控 -} - -func BenchmarkFlush(b *testing.B) { - kcp := NewKCP(1, func(buf []byte, size int) {}) - kcp.snd_buf = make([]segment, 1024) - for k := range kcp.snd_buf { - kcp.snd_buf[k].xmit = 1 - kcp.snd_buf[k].resendts = currentMs() + 10000 - } - b.ResetTimer() - b.ReportAllocs() - var mu sync.Mutex - for i := 0; i < b.N; i++ { - mu.Lock() - kcp.flush(false) - mu.Unlock() - } -} diff --git a/vender/github.com/xtaci/kcp/sess.go b/vender/github.com/xtaci/kcp/sess.go deleted file mode 100644 index a60b7b8..0000000 --- a/vender/github.com/xtaci/kcp/sess.go +++ /dev/null @@ -1,963 +0,0 @@ -package kcp - -import ( - "crypto/rand" - "encoding/binary" - "hash/crc32" - "net" - "sync" - "sync/atomic" - "time" - - "github.com/pkg/errors" - "golang.org/x/net/ipv4" - "golang.org/x/net/ipv6" -) - -type errTimeout struct { - error -} - -func (errTimeout) Timeout() bool { return true } -func (errTimeout) Temporary() bool { return true } -func (errTimeout) Error() string { return "i/o timeout" } - -const ( - // 16-bytes nonce for each packet - nonceSize = 16 - - // 4-bytes packet checksum - crcSize = 4 - - // overall crypto header size - cryptHeaderSize = nonceSize + crcSize - - // maximum packet size - mtuLimit = 1500 - - // FEC keeps rxFECMulti* (dataShard+parityShard) ordered packets in memory - rxFECMulti = 3 - - // accept backlog - acceptBacklog = 128 -) - -const ( - errBrokenPipe = "broken pipe" - errInvalidOperation = "invalid operation" -) - -var ( - // a system-wide packet buffer shared among sending, receiving and FEC - // to mitigate high-frequency memory allocation for packets - xmitBuf sync.Pool -) - -func init() { - xmitBuf.New = func() interface{} { - return make([]byte, mtuLimit) - } -} - -type ( - // UDPSession defines a KCP session implemented by UDP - UDPSession struct { - updaterIdx int // record slice index in updater - conn net.PacketConn // the underlying packet connection - kcp *KCP // KCP ARQ protocol - l *Listener // pointing to the Listener object if it's been accepted by a Listener - block BlockCrypt // block encryption object - - // kcp receiving is based on packets - // recvbuf turns packets into stream - recvbuf []byte - bufptr []byte - // header extended output buffer, if has header - ext []byte - - // FEC codec - fecDecoder *fecDecoder - fecEncoder *fecEncoder - - // settings - remote net.Addr // remote peer address - rd time.Time // read deadline - wd time.Time // write deadline - headerSize int // the header size additional to a KCP frame - ackNoDelay bool // send ack immediately for each incoming packet(testing purpose) - writeDelay bool // delay kcp.flush() for Write() for bulk transfer - dup int // duplicate udp packets(testing purpose) - - // notifications - die chan struct{} // notify current session has Closed - chReadEvent chan struct{} // notify Read() can be called without blocking - chWriteEvent chan struct{} // notify Write() can be called without blocking - chReadError chan error // notify PacketConn.Read() have an error - chWriteError chan error // notify PacketConn.Write() have an error - - // nonce generator - nonce Entropy - - isClosed bool // flag the session has Closed - mu sync.Mutex - } - - setReadBuffer interface { - SetReadBuffer(bytes int) error - } - - setWriteBuffer interface { - SetWriteBuffer(bytes int) error - } -) - -// newUDPSession create a new udp session for client or server -func newUDPSession(conv uint32, dataShards, parityShards int, l *Listener, conn net.PacketConn, remote net.Addr, block BlockCrypt) *UDPSession { - sess := new(UDPSession) - sess.die = make(chan struct{}) - sess.nonce = new(nonceAES128) - sess.nonce.Init() - sess.chReadEvent = make(chan struct{}, 1) - sess.chWriteEvent = make(chan struct{}, 1) - sess.chReadError = make(chan error, 1) - sess.chWriteError = make(chan error, 1) - sess.remote = remote - sess.conn = conn - sess.l = l - sess.block = block - sess.recvbuf = make([]byte, mtuLimit) - - // FEC codec initialization - sess.fecDecoder = newFECDecoder(rxFECMulti*(dataShards+parityShards), dataShards, parityShards) - if sess.block != nil { - sess.fecEncoder = newFECEncoder(dataShards, parityShards, cryptHeaderSize) - } else { - sess.fecEncoder = newFECEncoder(dataShards, parityShards, 0) - } - - // calculate additional header size introduced by FEC and encryption - if sess.block != nil { - sess.headerSize += cryptHeaderSize - } - if sess.fecEncoder != nil { - sess.headerSize += fecHeaderSizePlus2 - } - - // we only need to allocate extended packet buffer if we have the additional header - if sess.headerSize > 0 { - sess.ext = make([]byte, mtuLimit) - } - - sess.kcp = NewKCP(conv, func(buf []byte, size int) { - if size >= IKCP_OVERHEAD { - sess.output(buf[:size]) - } - }) - sess.kcp.SetMtu(IKCP_MTU_DEF - sess.headerSize) - - // register current session to the global updater, - // which call sess.update() periodically. - updater.addSession(sess) - - if sess.l == nil { // it's a client connection - go sess.readLoop() - atomic.AddUint64(&DefaultSnmp.ActiveOpens, 1) - } else { - atomic.AddUint64(&DefaultSnmp.PassiveOpens, 1) - } - currestab := atomic.AddUint64(&DefaultSnmp.CurrEstab, 1) - maxconn := atomic.LoadUint64(&DefaultSnmp.MaxConn) - if currestab > maxconn { - atomic.CompareAndSwapUint64(&DefaultSnmp.MaxConn, maxconn, currestab) - } - - return sess -} - -// Read implements net.Conn -func (s *UDPSession) Read(b []byte) (n int, err error) { - for { - s.mu.Lock() - if len(s.bufptr) > 0 { // copy from buffer into b - n = copy(b, s.bufptr) - s.bufptr = s.bufptr[n:] - s.mu.Unlock() - atomic.AddUint64(&DefaultSnmp.BytesReceived, uint64(n)) - return n, nil - } - - if s.isClosed { - s.mu.Unlock() - return 0, errors.New(errBrokenPipe) - } - - if size := s.kcp.PeekSize(); size > 0 { // peek data size from kcp - if len(b) >= size { // receive data into 'b' directly - s.kcp.Recv(b) - s.mu.Unlock() - atomic.AddUint64(&DefaultSnmp.BytesReceived, uint64(size)) - return size, nil - } - - // if necessary resize the stream buffer to guarantee a sufficent buffer space - if cap(s.recvbuf) < size { - s.recvbuf = make([]byte, size) - } - - // resize the length of recvbuf to correspond to data size - s.recvbuf = s.recvbuf[:size] - s.kcp.Recv(s.recvbuf) - n = copy(b, s.recvbuf) // copy to 'b' - s.bufptr = s.recvbuf[n:] // pointer update - s.mu.Unlock() - atomic.AddUint64(&DefaultSnmp.BytesReceived, uint64(n)) - return n, nil - } - - // deadline for current reading operation - var timeout *time.Timer - var c <-chan time.Time - if !s.rd.IsZero() { - if time.Now().After(s.rd) { - s.mu.Unlock() - return 0, errTimeout{} - } - - delay := s.rd.Sub(time.Now()) - timeout = time.NewTimer(delay) - c = timeout.C - } - s.mu.Unlock() - - // wait for read event or timeout - select { - case <-s.chReadEvent: - case <-c: - case <-s.die: - case err = <-s.chReadError: - if timeout != nil { - timeout.Stop() - } - return n, err - } - - if timeout != nil { - timeout.Stop() - } - } -} - -// Write implements net.Conn -func (s *UDPSession) Write(b []byte) (n int, err error) { - for { - s.mu.Lock() - if s.isClosed { - s.mu.Unlock() - return 0, errors.New(errBrokenPipe) - } - - // controls how much data will be sent to kcp core - // to prevent the memory from exhuasting - if s.kcp.WaitSnd() < int(s.kcp.snd_wnd) { - n = len(b) - for { - if len(b) <= int(s.kcp.mss) { - s.kcp.Send(b) - break - } else { - s.kcp.Send(b[:s.kcp.mss]) - b = b[s.kcp.mss:] - } - } - - // flush immediately if the queue is full - if s.kcp.WaitSnd() >= int(s.kcp.snd_wnd) || !s.writeDelay { - s.kcp.flush(false) - } - s.mu.Unlock() - atomic.AddUint64(&DefaultSnmp.BytesSent, uint64(n)) - return n, nil - } - - // deadline for current writing operation - var timeout *time.Timer - var c <-chan time.Time - if !s.wd.IsZero() { - if time.Now().After(s.wd) { - s.mu.Unlock() - return 0, errTimeout{} - } - delay := s.wd.Sub(time.Now()) - timeout = time.NewTimer(delay) - c = timeout.C - } - s.mu.Unlock() - - // wait for write event or timeout - select { - case <-s.chWriteEvent: - case <-c: - case <-s.die: - case err = <-s.chWriteError: - if timeout != nil { - timeout.Stop() - } - return n, err - } - - if timeout != nil { - timeout.Stop() - } - } -} - -// Close closes the connection. -func (s *UDPSession) Close() error { - // remove current session from updater & listener(if necessary) - updater.removeSession(s) - if s.l != nil { // notify listener - s.l.closeSession(s.remote) - } - - s.mu.Lock() - defer s.mu.Unlock() - if s.isClosed { - return errors.New(errBrokenPipe) - } - close(s.die) - s.isClosed = true - atomic.AddUint64(&DefaultSnmp.CurrEstab, ^uint64(0)) - if s.l == nil { // client socket close - return s.conn.Close() - } - return nil -} - -// LocalAddr returns the local network address. The Addr returned is shared by all invocations of LocalAddr, so do not modify it. -func (s *UDPSession) LocalAddr() net.Addr { return s.conn.LocalAddr() } - -// RemoteAddr returns the remote network address. The Addr returned is shared by all invocations of RemoteAddr, so do not modify it. -func (s *UDPSession) RemoteAddr() net.Addr { return s.remote } - -// SetDeadline sets the deadline associated with the listener. A zero time value disables the deadline. -func (s *UDPSession) SetDeadline(t time.Time) error { - s.mu.Lock() - defer s.mu.Unlock() - s.rd = t - s.wd = t - s.notifyReadEvent() - s.notifyWriteEvent() - return nil -} - -// SetReadDeadline implements the Conn SetReadDeadline method. -func (s *UDPSession) SetReadDeadline(t time.Time) error { - s.mu.Lock() - defer s.mu.Unlock() - s.rd = t - s.notifyReadEvent() - return nil -} - -// SetWriteDeadline implements the Conn SetWriteDeadline method. -func (s *UDPSession) SetWriteDeadline(t time.Time) error { - s.mu.Lock() - defer s.mu.Unlock() - s.wd = t - s.notifyWriteEvent() - return nil -} - -// SetWriteDelay delays write for bulk transfer until the next update interval -func (s *UDPSession) SetWriteDelay(delay bool) { - s.mu.Lock() - defer s.mu.Unlock() - s.writeDelay = delay -} - -// SetWindowSize set maximum window size -func (s *UDPSession) SetWindowSize(sndwnd, rcvwnd int) { - s.mu.Lock() - defer s.mu.Unlock() - s.kcp.WndSize(sndwnd, rcvwnd) -} - -// SetMtu sets the maximum transmission unit(not including UDP header) -func (s *UDPSession) SetMtu(mtu int) bool { - if mtu > mtuLimit { - return false - } - - s.mu.Lock() - defer s.mu.Unlock() - s.kcp.SetMtu(mtu - s.headerSize) - return true -} - -// SetStreamMode toggles the stream mode on/off -func (s *UDPSession) SetStreamMode(enable bool) { - s.mu.Lock() - defer s.mu.Unlock() - if enable { - s.kcp.stream = 1 - } else { - s.kcp.stream = 0 - } -} - -// SetACKNoDelay changes ack flush option, set true to flush ack immediately, -func (s *UDPSession) SetACKNoDelay(nodelay bool) { - s.mu.Lock() - defer s.mu.Unlock() - s.ackNoDelay = nodelay -} - -// SetDUP duplicates udp packets for kcp output, for testing purpose only -func (s *UDPSession) SetDUP(dup int) { - s.mu.Lock() - defer s.mu.Unlock() - s.dup = dup -} - -// SetNoDelay calls nodelay() of kcp -// https://github.com/skywind3000/kcp/blob/master/README.en.md#protocol-configuration -func (s *UDPSession) SetNoDelay(nodelay, interval, resend, nc int) { - s.mu.Lock() - defer s.mu.Unlock() - s.kcp.NoDelay(nodelay, interval, resend, nc) -} - -// SetDSCP sets the 6bit DSCP field of IP header, no effect if it's accepted from Listener -func (s *UDPSession) SetDSCP(dscp int) error { - s.mu.Lock() - defer s.mu.Unlock() - if s.l == nil { - if nc, ok := s.conn.(net.Conn); ok { - if err := ipv4.NewConn(nc).SetTOS(dscp << 2); err != nil { - return ipv6.NewConn(nc).SetTrafficClass(dscp) - } - return nil - } - } - return errors.New(errInvalidOperation) -} - -// SetReadBuffer sets the socket read buffer, no effect if it's accepted from Listener -func (s *UDPSession) SetReadBuffer(bytes int) error { - s.mu.Lock() - defer s.mu.Unlock() - if s.l == nil { - if nc, ok := s.conn.(setReadBuffer); ok { - return nc.SetReadBuffer(bytes) - } - } - return errors.New(errInvalidOperation) -} - -// SetWriteBuffer sets the socket write buffer, no effect if it's accepted from Listener -func (s *UDPSession) SetWriteBuffer(bytes int) error { - s.mu.Lock() - defer s.mu.Unlock() - if s.l == nil { - if nc, ok := s.conn.(setWriteBuffer); ok { - return nc.SetWriteBuffer(bytes) - } - } - return errors.New(errInvalidOperation) -} - -// post-processing for sending a packet from kcp core -// steps: -// 0. Header extending -// 1. FEC packet generation -// 2. CRC32 integrity -// 3. Encryption -// 4. WriteTo kernel -func (s *UDPSession) output(buf []byte) { - var ecc [][]byte - - // 0. extend buf's header space(if necessary) - ext := buf - if s.headerSize > 0 { - ext = s.ext[:s.headerSize+len(buf)] - copy(ext[s.headerSize:], buf) - } - - // 1. FEC encoding - if s.fecEncoder != nil { - ecc = s.fecEncoder.encode(ext) - } - - // 2&3. crc32 & encryption - if s.block != nil { - s.nonce.Fill(ext[:nonceSize]) - checksum := crc32.ChecksumIEEE(ext[cryptHeaderSize:]) - binary.LittleEndian.PutUint32(ext[nonceSize:], checksum) - s.block.Encrypt(ext, ext) - - for k := range ecc { - s.nonce.Fill(ecc[k][:nonceSize]) - checksum := crc32.ChecksumIEEE(ecc[k][cryptHeaderSize:]) - binary.LittleEndian.PutUint32(ecc[k][nonceSize:], checksum) - s.block.Encrypt(ecc[k], ecc[k]) - } - } - - // 4. WriteTo kernel - nbytes := 0 - npkts := 0 - for i := 0; i < s.dup+1; i++ { - if n, err := s.conn.WriteTo(ext, s.remote); err == nil { - nbytes += n - npkts++ - } else { - s.notifyWriteError(err) - } - } - - for k := range ecc { - if n, err := s.conn.WriteTo(ecc[k], s.remote); err == nil { - nbytes += n - npkts++ - } else { - s.notifyWriteError(err) - } - } - atomic.AddUint64(&DefaultSnmp.OutPkts, uint64(npkts)) - atomic.AddUint64(&DefaultSnmp.OutBytes, uint64(nbytes)) -} - -// kcp update, returns interval for next calling -func (s *UDPSession) update() (interval time.Duration) { - s.mu.Lock() - waitsnd := s.kcp.WaitSnd() - interval = time.Duration(s.kcp.flush(false)) * time.Millisecond - if s.kcp.WaitSnd() < waitsnd { - s.notifyWriteEvent() - } - s.mu.Unlock() - return -} - -// GetConv gets conversation id of a session -func (s *UDPSession) GetConv() uint32 { return s.kcp.conv } - -func (s *UDPSession) notifyReadEvent() { - select { - case s.chReadEvent <- struct{}{}: - default: - } -} - -func (s *UDPSession) notifyWriteEvent() { - select { - case s.chWriteEvent <- struct{}{}: - default: - } -} - -func (s *UDPSession) notifyWriteError(err error) { - select { - case s.chWriteError <- err: - default: - } -} - -func (s *UDPSession) kcpInput(data []byte) { - var kcpInErrors, fecErrs, fecRecovered, fecParityShards uint64 - - if s.fecDecoder != nil { - if len(data) > fecHeaderSize { // must be larger than fec header size - f := s.fecDecoder.decodeBytes(data) - if f.flag == typeData || f.flag == typeFEC { // header check - if f.flag == typeFEC { - fecParityShards++ - } - recovers := s.fecDecoder.decode(f) - - s.mu.Lock() - waitsnd := s.kcp.WaitSnd() - if f.flag == typeData { - if ret := s.kcp.Input(data[fecHeaderSizePlus2:], true, s.ackNoDelay); ret != 0 { - kcpInErrors++ - } - } - - for _, r := range recovers { - if len(r) >= 2 { // must be larger than 2bytes - sz := binary.LittleEndian.Uint16(r) - if int(sz) <= len(r) && sz >= 2 { - if ret := s.kcp.Input(r[2:sz], false, s.ackNoDelay); ret == 0 { - fecRecovered++ - } else { - kcpInErrors++ - } - } else { - fecErrs++ - } - } else { - fecErrs++ - } - } - - // to notify the readers to receive the data - if n := s.kcp.PeekSize(); n > 0 { - s.notifyReadEvent() - } - // to notify the writers when queue is shorter(e.g. ACKed) - if s.kcp.WaitSnd() < waitsnd { - s.notifyWriteEvent() - } - s.mu.Unlock() - } else { - atomic.AddUint64(&DefaultSnmp.InErrs, 1) - } - } else { - atomic.AddUint64(&DefaultSnmp.InErrs, 1) - } - } else { - s.mu.Lock() - waitsnd := s.kcp.WaitSnd() - if ret := s.kcp.Input(data, true, s.ackNoDelay); ret != 0 { - kcpInErrors++ - } - if n := s.kcp.PeekSize(); n > 0 { - s.notifyReadEvent() - } - if s.kcp.WaitSnd() < waitsnd { - s.notifyWriteEvent() - } - s.mu.Unlock() - } - - atomic.AddUint64(&DefaultSnmp.InPkts, 1) - atomic.AddUint64(&DefaultSnmp.InBytes, uint64(len(data))) - if fecParityShards > 0 { - atomic.AddUint64(&DefaultSnmp.FECParityShards, fecParityShards) - } - if kcpInErrors > 0 { - atomic.AddUint64(&DefaultSnmp.KCPInErrors, kcpInErrors) - } - if fecErrs > 0 { - atomic.AddUint64(&DefaultSnmp.FECErrs, fecErrs) - } - if fecRecovered > 0 { - atomic.AddUint64(&DefaultSnmp.FECRecovered, fecRecovered) - } -} - -// the read loop for a client session -func (s *UDPSession) readLoop() { - buf := make([]byte, mtuLimit) - var src string - for { - if n, addr, err := s.conn.ReadFrom(buf); err == nil { - // make sure the packet is from the same source - if src == "" { // set source address - src = addr.String() - } else if addr.String() != src { - atomic.AddUint64(&DefaultSnmp.InErrs, 1) - continue - } - - if n >= s.headerSize+IKCP_OVERHEAD { - data := buf[:n] - dataValid := false - if s.block != nil { - s.block.Decrypt(data, data) - data = data[nonceSize:] - checksum := crc32.ChecksumIEEE(data[crcSize:]) - if checksum == binary.LittleEndian.Uint32(data) { - data = data[crcSize:] - dataValid = true - } else { - atomic.AddUint64(&DefaultSnmp.InCsumErrors, 1) - } - } else if s.block == nil { - dataValid = true - } - - if dataValid { - s.kcpInput(data) - } - } else { - atomic.AddUint64(&DefaultSnmp.InErrs, 1) - } - } else { - s.chReadError <- err - return - } - } -} - -type ( - // Listener defines a server which will be waiting to accept incoming connections - Listener struct { - block BlockCrypt // block encryption - dataShards int // FEC data shard - parityShards int // FEC parity shard - fecDecoder *fecDecoder // FEC mock initialization - conn net.PacketConn // the underlying packet connection - - sessions map[string]*UDPSession // all sessions accepted by this Listener - sessionLock sync.Mutex - chAccepts chan *UDPSession // Listen() backlog - chSessionClosed chan net.Addr // session close queue - headerSize int // the additional header to a KCP frame - die chan struct{} // notify the listener has closed - rd atomic.Value // read deadline for Accept() - wd atomic.Value - } -) - -// monitor incoming data for all connections of server -func (l *Listener) monitor() { - // a cache for session object last used - var lastAddr string - var lastSession *UDPSession - buf := make([]byte, mtuLimit) - for { - if n, from, err := l.conn.ReadFrom(buf); err == nil { - if n >= l.headerSize+IKCP_OVERHEAD { - data := buf[:n] - dataValid := false - if l.block != nil { - l.block.Decrypt(data, data) - data = data[nonceSize:] - checksum := crc32.ChecksumIEEE(data[crcSize:]) - if checksum == binary.LittleEndian.Uint32(data) { - data = data[crcSize:] - dataValid = true - } else { - atomic.AddUint64(&DefaultSnmp.InCsumErrors, 1) - } - } else if l.block == nil { - dataValid = true - } - - if dataValid { - addr := from.String() - var s *UDPSession - var ok bool - - // the packets received from an address always come in batch, - // cache the session for next packet, without querying map. - if addr == lastAddr { - s, ok = lastSession, true - } else { - l.sessionLock.Lock() - if s, ok = l.sessions[addr]; ok { - lastSession = s - lastAddr = addr - } - l.sessionLock.Unlock() - } - - if !ok { // new session - if len(l.chAccepts) < cap(l.chAccepts) { // do not let the new sessions overwhelm accept queue - var conv uint32 - convValid := false - if l.fecDecoder != nil { - isfec := binary.LittleEndian.Uint16(data[4:]) - if isfec == typeData { - conv = binary.LittleEndian.Uint32(data[fecHeaderSizePlus2:]) - convValid = true - } - } else { - conv = binary.LittleEndian.Uint32(data) - convValid = true - } - - if convValid { // creates a new session only if the 'conv' field in kcp is accessible - s := newUDPSession(conv, l.dataShards, l.parityShards, l, l.conn, from, l.block) - s.kcpInput(data) - l.sessionLock.Lock() - l.sessions[addr] = s - l.sessionLock.Unlock() - l.chAccepts <- s - } - } - } else { - s.kcpInput(data) - } - } - } else { - atomic.AddUint64(&DefaultSnmp.InErrs, 1) - } - } else { - return - } - } -} - -// SetReadBuffer sets the socket read buffer for the Listener -func (l *Listener) SetReadBuffer(bytes int) error { - if nc, ok := l.conn.(setReadBuffer); ok { - return nc.SetReadBuffer(bytes) - } - return errors.New(errInvalidOperation) -} - -// SetWriteBuffer sets the socket write buffer for the Listener -func (l *Listener) SetWriteBuffer(bytes int) error { - if nc, ok := l.conn.(setWriteBuffer); ok { - return nc.SetWriteBuffer(bytes) - } - return errors.New(errInvalidOperation) -} - -// SetDSCP sets the 6bit DSCP field of IP header -func (l *Listener) SetDSCP(dscp int) error { - if nc, ok := l.conn.(net.Conn); ok { - if err := ipv4.NewConn(nc).SetTOS(dscp << 2); err != nil { - return ipv6.NewConn(nc).SetTrafficClass(dscp) - } - return nil - } - return errors.New(errInvalidOperation) -} - -// Accept implements the Accept method in the Listener interface; it waits for the next call and returns a generic Conn. -func (l *Listener) Accept() (net.Conn, error) { - return l.AcceptKCP() -} - -// AcceptKCP accepts a KCP connection -func (l *Listener) AcceptKCP() (*UDPSession, error) { - var timeout <-chan time.Time - if tdeadline, ok := l.rd.Load().(time.Time); ok && !tdeadline.IsZero() { - timeout = time.After(tdeadline.Sub(time.Now())) - } - - select { - case <-timeout: - return nil, &errTimeout{} - case c := <-l.chAccepts: - return c, nil - case <-l.die: - return nil, errors.New(errBrokenPipe) - } -} - -// SetDeadline sets the deadline associated with the listener. A zero time value disables the deadline. -func (l *Listener) SetDeadline(t time.Time) error { - l.SetReadDeadline(t) - l.SetWriteDeadline(t) - return nil -} - -// SetReadDeadline implements the Conn SetReadDeadline method. -func (l *Listener) SetReadDeadline(t time.Time) error { - l.rd.Store(t) - return nil -} - -// SetWriteDeadline implements the Conn SetWriteDeadline method. -func (l *Listener) SetWriteDeadline(t time.Time) error { - l.wd.Store(t) - return nil -} - -// Close stops listening on the UDP address. Already Accepted connections are not closed. -func (l *Listener) Close() error { - close(l.die) - return l.conn.Close() -} - -// closeSession notify the listener that a session has closed -func (l *Listener) closeSession(remote net.Addr) (ret bool) { - l.sessionLock.Lock() - defer l.sessionLock.Unlock() - if _, ok := l.sessions[remote.String()]; ok { - delete(l.sessions, remote.String()) - return true - } - return false -} - -// Addr returns the listener's network address, The Addr returned is shared by all invocations of Addr, so do not modify it. -func (l *Listener) Addr() net.Addr { return l.conn.LocalAddr() } - -// Listen listens for incoming KCP packets addressed to the local address laddr on the network "udp", -func Listen(laddr string) (net.Listener, error) { return ListenWithOptions(laddr, nil, 0, 0) } - -// ListenWithOptions listens for incoming KCP packets addressed to the local address laddr on the network "udp" with packet encryption, -// rdataShards, parityShards defines Reed-Solomon Erasure Coding parametes -func ListenWithOptions(laddr string, block BlockCrypt, dataShards, parityShards int) (*Listener, error) { - udpaddr, err := net.ResolveUDPAddr("udp", laddr) - if err != nil { - return nil, errors.Wrap(err, "net.ResolveUDPAddr") - } - conn, err := net.ListenUDP("udp", udpaddr) - if err != nil { - return nil, errors.Wrap(err, "net.ListenUDP") - } - - return ServeConn(block, dataShards, parityShards, conn) -} - -// ServeConn serves KCP protocol for a single packet connection. -func ServeConn(block BlockCrypt, dataShards, parityShards int, conn net.PacketConn) (*Listener, error) { - l := new(Listener) - l.conn = conn - l.sessions = make(map[string]*UDPSession) - l.chAccepts = make(chan *UDPSession, acceptBacklog) - l.chSessionClosed = make(chan net.Addr) - l.die = make(chan struct{}) - l.dataShards = dataShards - l.parityShards = parityShards - l.block = block - l.fecDecoder = newFECDecoder(rxFECMulti*(dataShards+parityShards), dataShards, parityShards) - - // calculate header size - if l.block != nil { - l.headerSize += cryptHeaderSize - } - if l.fecDecoder != nil { - l.headerSize += fecHeaderSizePlus2 - } - - go l.monitor() - return l, nil -} - -// Dial connects to the remote address "raddr" on the network "udp" -func Dial(raddr string) (net.Conn, error) { return DialWithOptions(raddr, nil, 0, 0) } - -// DialWithOptions connects to the remote address "raddr" on the network "udp" with packet encryption -func DialWithOptions(raddr string, block BlockCrypt, dataShards, parityShards int) (*UDPSession, error) { - // network type detection - udpaddr, err := net.ResolveUDPAddr("udp", raddr) - if err != nil { - return nil, errors.Wrap(err, "net.ResolveUDPAddr") - } - network := "udp4" - if udpaddr.IP.To4() == nil { - network = "udp" - } - - conn, err := net.ListenUDP(network, nil) - if err != nil { - return nil, errors.Wrap(err, "net.DialUDP") - } - - return NewConn(raddr, block, dataShards, parityShards, conn) -} - -// NewConn establishes a session and talks KCP protocol over a packet connection. -func NewConn(raddr string, block BlockCrypt, dataShards, parityShards int, conn net.PacketConn) (*UDPSession, error) { - udpaddr, err := net.ResolveUDPAddr("udp", raddr) - if err != nil { - return nil, errors.Wrap(err, "net.ResolveUDPAddr") - } - - var convid uint32 - binary.Read(rand.Reader, binary.LittleEndian, &convid) - return newUDPSession(convid, dataShards, parityShards, nil, conn, udpaddr, block), nil -} - -// monotonic reference time point -var refTime time.Time = time.Now() - -// currentMs returns current elasped monotonic milliseconds since program startup -func currentMs() uint32 { return uint32(time.Now().Sub(refTime) / time.Millisecond) } diff --git a/vender/github.com/xtaci/kcp/sess_test.go b/vender/github.com/xtaci/kcp/sess_test.go deleted file mode 100644 index 4fce29a..0000000 --- a/vender/github.com/xtaci/kcp/sess_test.go +++ /dev/null @@ -1,475 +0,0 @@ -package kcp - -import ( - "crypto/sha1" - "fmt" - "io" - "log" - "net" - "net/http" - _ "net/http/pprof" - "sync" - "testing" - "time" - - "golang.org/x/crypto/pbkdf2" -) - -const portEcho = "127.0.0.1:9999" -const portSink = "127.0.0.1:19999" -const portTinyBufferEcho = "127.0.0.1:29999" -const portListerner = "127.0.0.1:9998" - -var key = []byte("testkey") -var pass = pbkdf2.Key(key, []byte(portSink), 4096, 32, sha1.New) - -func init() { - go func() { - log.Println(http.ListenAndServe("localhost:6060", nil)) - }() - - go echoServer() - go sinkServer() - go tinyBufferEchoServer() - println("beginning tests, encryption:salsa20, fec:10/3") -} - -func dialEcho() (*UDPSession, error) { - //block, _ := NewNoneBlockCrypt(pass) - //block, _ := NewSimpleXORBlockCrypt(pass) - //block, _ := NewTEABlockCrypt(pass[:16]) - //block, _ := NewAESBlockCrypt(pass) - block, _ := NewSalsa20BlockCrypt(pass) - sess, err := DialWithOptions(portEcho, block, 10, 3) - if err != nil { - panic(err) - } - - sess.SetStreamMode(true) - sess.SetStreamMode(false) - sess.SetStreamMode(true) - sess.SetWindowSize(1024, 1024) - sess.SetReadBuffer(16 * 1024 * 1024) - sess.SetWriteBuffer(16 * 1024 * 1024) - sess.SetStreamMode(true) - sess.SetNoDelay(1, 10, 2, 1) - sess.SetMtu(1400) - sess.SetMtu(1600) - sess.SetMtu(1400) - sess.SetACKNoDelay(true) - sess.SetACKNoDelay(false) - sess.SetDeadline(time.Now().Add(time.Minute)) - return sess, err -} - -func dialSink() (*UDPSession, error) { - sess, err := DialWithOptions(portSink, nil, 0, 0) - if err != nil { - panic(err) - } - - sess.SetStreamMode(true) - sess.SetWindowSize(1024, 1024) - sess.SetReadBuffer(16 * 1024 * 1024) - sess.SetWriteBuffer(16 * 1024 * 1024) - sess.SetStreamMode(true) - sess.SetNoDelay(1, 10, 2, 1) - sess.SetMtu(1400) - sess.SetACKNoDelay(false) - sess.SetDeadline(time.Now().Add(time.Minute)) - return sess, err -} - -func dialTinyBufferEcho() (*UDPSession, error) { - //block, _ := NewNoneBlockCrypt(pass) - //block, _ := NewSimpleXORBlockCrypt(pass) - //block, _ := NewTEABlockCrypt(pass[:16]) - //block, _ := NewAESBlockCrypt(pass) - block, _ := NewSalsa20BlockCrypt(pass) - sess, err := DialWithOptions(portTinyBufferEcho, block, 10, 3) - if err != nil { - panic(err) - } - return sess, err -} - -////////////////////////// -func listenEcho() (net.Listener, error) { - //block, _ := NewNoneBlockCrypt(pass) - //block, _ := NewSimpleXORBlockCrypt(pass) - //block, _ := NewTEABlockCrypt(pass[:16]) - //block, _ := NewAESBlockCrypt(pass) - block, _ := NewSalsa20BlockCrypt(pass) - return ListenWithOptions(portEcho, block, 10, 3) -} -func listenTinyBufferEcho() (net.Listener, error) { - //block, _ := NewNoneBlockCrypt(pass) - //block, _ := NewSimpleXORBlockCrypt(pass) - //block, _ := NewTEABlockCrypt(pass[:16]) - //block, _ := NewAESBlockCrypt(pass) - block, _ := NewSalsa20BlockCrypt(pass) - return ListenWithOptions(portTinyBufferEcho, block, 10, 3) -} - -func listenSink() (net.Listener, error) { - return ListenWithOptions(portSink, nil, 0, 0) -} - -func echoServer() { - l, err := listenEcho() - if err != nil { - panic(err) - } - - go func() { - kcplistener := l.(*Listener) - kcplistener.SetReadBuffer(4 * 1024 * 1024) - kcplistener.SetWriteBuffer(4 * 1024 * 1024) - kcplistener.SetDSCP(46) - for { - s, err := l.Accept() - if err != nil { - return - } - - // coverage test - s.(*UDPSession).SetReadBuffer(4 * 1024 * 1024) - s.(*UDPSession).SetWriteBuffer(4 * 1024 * 1024) - go handleEcho(s.(*UDPSession)) - } - }() -} - -func sinkServer() { - l, err := listenSink() - if err != nil { - panic(err) - } - - go func() { - kcplistener := l.(*Listener) - kcplistener.SetReadBuffer(4 * 1024 * 1024) - kcplistener.SetWriteBuffer(4 * 1024 * 1024) - kcplistener.SetDSCP(46) - for { - s, err := l.Accept() - if err != nil { - return - } - - go handleSink(s.(*UDPSession)) - } - }() -} - -func tinyBufferEchoServer() { - l, err := listenTinyBufferEcho() - if err != nil { - panic(err) - } - - go func() { - for { - s, err := l.Accept() - if err != nil { - return - } - go handleTinyBufferEcho(s.(*UDPSession)) - } - }() -} - -/////////////////////////// - -func handleEcho(conn *UDPSession) { - conn.SetStreamMode(true) - conn.SetWindowSize(4096, 4096) - conn.SetNoDelay(1, 10, 2, 1) - conn.SetDSCP(46) - conn.SetMtu(1400) - conn.SetACKNoDelay(false) - conn.SetReadDeadline(time.Now().Add(time.Hour)) - conn.SetWriteDeadline(time.Now().Add(time.Hour)) - buf := make([]byte, 65536) - for { - n, err := conn.Read(buf) - if err != nil { - panic(err) - } - conn.Write(buf[:n]) - } -} - -func handleSink(conn *UDPSession) { - conn.SetStreamMode(true) - conn.SetWindowSize(4096, 4096) - conn.SetNoDelay(1, 10, 2, 1) - conn.SetDSCP(46) - conn.SetMtu(1400) - conn.SetACKNoDelay(false) - conn.SetReadDeadline(time.Now().Add(time.Hour)) - conn.SetWriteDeadline(time.Now().Add(time.Hour)) - buf := make([]byte, 65536) - for { - _, err := conn.Read(buf) - if err != nil { - panic(err) - } - } -} - -func handleTinyBufferEcho(conn *UDPSession) { - conn.SetStreamMode(true) - buf := make([]byte, 2) - for { - n, err := conn.Read(buf) - if err != nil { - panic(err) - } - conn.Write(buf[:n]) - } -} - -/////////////////////////// - -func TestTimeout(t *testing.T) { - cli, err := dialEcho() - if err != nil { - panic(err) - } - buf := make([]byte, 10) - - //timeout - cli.SetDeadline(time.Now().Add(time.Second)) - <-time.After(2 * time.Second) - n, err := cli.Read(buf) - if n != 0 || err == nil { - t.Fail() - } - cli.Close() -} - -func TestSendRecv(t *testing.T) { - cli, err := dialEcho() - if err != nil { - panic(err) - } - cli.SetWriteDelay(true) - cli.SetDUP(1) - const N = 100 - buf := make([]byte, 10) - for i := 0; i < N; i++ { - msg := fmt.Sprintf("hello%v", i) - cli.Write([]byte(msg)) - if n, err := cli.Read(buf); err == nil { - if string(buf[:n]) != msg { - t.Fail() - } - } else { - panic(err) - } - } - cli.Close() -} - -func TestTinyBufferReceiver(t *testing.T) { - cli, err := dialTinyBufferEcho() - if err != nil { - panic(err) - } - const N = 100 - snd := byte(0) - fillBuffer := func(buf []byte) { - for i := 0; i < len(buf); i++ { - buf[i] = snd - snd++ - } - } - - rcv := byte(0) - check := func(buf []byte) bool { - for i := 0; i < len(buf); i++ { - if buf[i] != rcv { - return false - } - rcv++ - } - return true - } - sndbuf := make([]byte, 7) - rcvbuf := make([]byte, 7) - for i := 0; i < N; i++ { - fillBuffer(sndbuf) - cli.Write(sndbuf) - if n, err := io.ReadFull(cli, rcvbuf); err == nil { - if !check(rcvbuf[:n]) { - t.Fail() - } - } else { - panic(err) - } - } - cli.Close() -} - -func TestClose(t *testing.T) { - cli, err := dialEcho() - if err != nil { - panic(err) - } - buf := make([]byte, 10) - - cli.Close() - if cli.Close() == nil { - t.Fail() - } - n, err := cli.Write(buf) - if n != 0 || err == nil { - t.Fail() - } - n, err = cli.Read(buf) - if n != 0 || err == nil { - t.Fail() - } - cli.Close() -} - -func TestParallel1024CLIENT_64BMSG_64CNT(t *testing.T) { - var wg sync.WaitGroup - wg.Add(1024) - for i := 0; i < 1024; i++ { - go parallel_client(&wg) - } - wg.Wait() -} - -func parallel_client(wg *sync.WaitGroup) (err error) { - cli, err := dialEcho() - if err != nil { - panic(err) - } - - err = echo_tester(cli, 64, 64) - wg.Done() - return -} - -func BenchmarkEchoSpeed4K(b *testing.B) { - speedclient(b, 4096) -} - -func BenchmarkEchoSpeed64K(b *testing.B) { - speedclient(b, 65536) -} - -func BenchmarkEchoSpeed512K(b *testing.B) { - speedclient(b, 524288) -} - -func BenchmarkEchoSpeed1M(b *testing.B) { - speedclient(b, 1048576) -} - -func speedclient(b *testing.B, nbytes int) { - b.ReportAllocs() - cli, err := dialEcho() - if err != nil { - panic(err) - } - - if err := echo_tester(cli, nbytes, b.N); err != nil { - b.Fail() - } - b.SetBytes(int64(nbytes)) -} - -func BenchmarkSinkSpeed4K(b *testing.B) { - sinkclient(b, 4096) -} - -func BenchmarkSinkSpeed64K(b *testing.B) { - sinkclient(b, 65536) -} - -func BenchmarkSinkSpeed256K(b *testing.B) { - sinkclient(b, 524288) -} - -func BenchmarkSinkSpeed1M(b *testing.B) { - sinkclient(b, 1048576) -} - -func sinkclient(b *testing.B, nbytes int) { - b.ReportAllocs() - cli, err := dialSink() - if err != nil { - panic(err) - } - - sink_tester(cli, nbytes, b.N) - b.SetBytes(int64(nbytes)) -} - -func echo_tester(cli net.Conn, msglen, msgcount int) error { - buf := make([]byte, msglen) - for i := 0; i < msgcount; i++ { - // send packet - if _, err := cli.Write(buf); err != nil { - return err - } - - // receive packet - nrecv := 0 - for { - n, err := cli.Read(buf) - if err != nil { - return err - } else { - nrecv += n - if nrecv == msglen { - break - } - } - } - } - return nil -} - -func sink_tester(cli *UDPSession, msglen, msgcount int) error { - // sender - buf := make([]byte, msglen) - for i := 0; i < msgcount; i++ { - if _, err := cli.Write(buf); err != nil { - return err - } - } - return nil -} - -func TestSNMP(t *testing.T) { - t.Log(DefaultSnmp.Copy()) - t.Log(DefaultSnmp.Header()) - t.Log(DefaultSnmp.ToSlice()) - DefaultSnmp.Reset() - t.Log(DefaultSnmp.ToSlice()) -} - -func TestListenerClose(t *testing.T) { - l, err := ListenWithOptions(portListerner, nil, 10, 3) - if err != nil { - t.Fail() - } - l.SetReadDeadline(time.Now().Add(time.Second)) - l.SetWriteDeadline(time.Now().Add(time.Second)) - l.SetDeadline(time.Now().Add(time.Second)) - time.Sleep(2 * time.Second) - if _, err := l.Accept(); err == nil { - t.Fail() - } - - l.Close() - fakeaddr, _ := net.ResolveUDPAddr("udp6", "127.0.0.1:1111") - if l.closeSession(fakeaddr) { - t.Fail() - } -} diff --git a/vender/github.com/xtaci/kcp/snmp.go b/vender/github.com/xtaci/kcp/snmp.go deleted file mode 100644 index 607118e..0000000 --- a/vender/github.com/xtaci/kcp/snmp.go +++ /dev/null @@ -1,164 +0,0 @@ -package kcp - -import ( - "fmt" - "sync/atomic" -) - -// Snmp defines network statistics indicator -type Snmp struct { - BytesSent uint64 // bytes sent from upper level - BytesReceived uint64 // bytes received to upper level - MaxConn uint64 // max number of connections ever reached - ActiveOpens uint64 // accumulated active open connections - PassiveOpens uint64 // accumulated passive open connections - CurrEstab uint64 // current number of established connections - InErrs uint64 // UDP read errors reported from net.PacketConn - InCsumErrors uint64 // checksum errors from CRC32 - KCPInErrors uint64 // packet iput errors reported from KCP - InPkts uint64 // incoming packets count - OutPkts uint64 // outgoing packets count - InSegs uint64 // incoming KCP segments - OutSegs uint64 // outgoing KCP segments - InBytes uint64 // UDP bytes received - OutBytes uint64 // UDP bytes sent - RetransSegs uint64 // accmulated retransmited segments - FastRetransSegs uint64 // accmulated fast retransmitted segments - EarlyRetransSegs uint64 // accmulated early retransmitted segments - LostSegs uint64 // number of segs infered as lost - RepeatSegs uint64 // number of segs duplicated - FECRecovered uint64 // correct packets recovered from FEC - FECErrs uint64 // incorrect packets recovered from FEC - FECParityShards uint64 // FEC segments received - FECShortShards uint64 // number of data shards that's not enough for recovery -} - -func newSnmp() *Snmp { - return new(Snmp) -} - -// Header returns all field names -func (s *Snmp) Header() []string { - return []string{ - "BytesSent", - "BytesReceived", - "MaxConn", - "ActiveOpens", - "PassiveOpens", - "CurrEstab", - "InErrs", - "InCsumErrors", - "KCPInErrors", - "InPkts", - "OutPkts", - "InSegs", - "OutSegs", - "InBytes", - "OutBytes", - "RetransSegs", - "FastRetransSegs", - "EarlyRetransSegs", - "LostSegs", - "RepeatSegs", - "FECParityShards", - "FECErrs", - "FECRecovered", - "FECShortShards", - } -} - -// ToSlice returns current snmp info as slice -func (s *Snmp) ToSlice() []string { - snmp := s.Copy() - return []string{ - fmt.Sprint(snmp.BytesSent), - fmt.Sprint(snmp.BytesReceived), - fmt.Sprint(snmp.MaxConn), - fmt.Sprint(snmp.ActiveOpens), - fmt.Sprint(snmp.PassiveOpens), - fmt.Sprint(snmp.CurrEstab), - fmt.Sprint(snmp.InErrs), - fmt.Sprint(snmp.InCsumErrors), - fmt.Sprint(snmp.KCPInErrors), - fmt.Sprint(snmp.InPkts), - fmt.Sprint(snmp.OutPkts), - fmt.Sprint(snmp.InSegs), - fmt.Sprint(snmp.OutSegs), - fmt.Sprint(snmp.InBytes), - fmt.Sprint(snmp.OutBytes), - fmt.Sprint(snmp.RetransSegs), - fmt.Sprint(snmp.FastRetransSegs), - fmt.Sprint(snmp.EarlyRetransSegs), - fmt.Sprint(snmp.LostSegs), - fmt.Sprint(snmp.RepeatSegs), - fmt.Sprint(snmp.FECParityShards), - fmt.Sprint(snmp.FECErrs), - fmt.Sprint(snmp.FECRecovered), - fmt.Sprint(snmp.FECShortShards), - } -} - -// Copy make a copy of current snmp snapshot -func (s *Snmp) Copy() *Snmp { - d := newSnmp() - d.BytesSent = atomic.LoadUint64(&s.BytesSent) - d.BytesReceived = atomic.LoadUint64(&s.BytesReceived) - d.MaxConn = atomic.LoadUint64(&s.MaxConn) - d.ActiveOpens = atomic.LoadUint64(&s.ActiveOpens) - d.PassiveOpens = atomic.LoadUint64(&s.PassiveOpens) - d.CurrEstab = atomic.LoadUint64(&s.CurrEstab) - d.InErrs = atomic.LoadUint64(&s.InErrs) - d.InCsumErrors = atomic.LoadUint64(&s.InCsumErrors) - d.KCPInErrors = atomic.LoadUint64(&s.KCPInErrors) - d.InPkts = atomic.LoadUint64(&s.InPkts) - d.OutPkts = atomic.LoadUint64(&s.OutPkts) - d.InSegs = atomic.LoadUint64(&s.InSegs) - d.OutSegs = atomic.LoadUint64(&s.OutSegs) - d.InBytes = atomic.LoadUint64(&s.InBytes) - d.OutBytes = atomic.LoadUint64(&s.OutBytes) - d.RetransSegs = atomic.LoadUint64(&s.RetransSegs) - d.FastRetransSegs = atomic.LoadUint64(&s.FastRetransSegs) - d.EarlyRetransSegs = atomic.LoadUint64(&s.EarlyRetransSegs) - d.LostSegs = atomic.LoadUint64(&s.LostSegs) - d.RepeatSegs = atomic.LoadUint64(&s.RepeatSegs) - d.FECParityShards = atomic.LoadUint64(&s.FECParityShards) - d.FECErrs = atomic.LoadUint64(&s.FECErrs) - d.FECRecovered = atomic.LoadUint64(&s.FECRecovered) - d.FECShortShards = atomic.LoadUint64(&s.FECShortShards) - return d -} - -// Reset values to zero -func (s *Snmp) Reset() { - atomic.StoreUint64(&s.BytesSent, 0) - atomic.StoreUint64(&s.BytesReceived, 0) - atomic.StoreUint64(&s.MaxConn, 0) - atomic.StoreUint64(&s.ActiveOpens, 0) - atomic.StoreUint64(&s.PassiveOpens, 0) - atomic.StoreUint64(&s.CurrEstab, 0) - atomic.StoreUint64(&s.InErrs, 0) - atomic.StoreUint64(&s.InCsumErrors, 0) - atomic.StoreUint64(&s.KCPInErrors, 0) - atomic.StoreUint64(&s.InPkts, 0) - atomic.StoreUint64(&s.OutPkts, 0) - atomic.StoreUint64(&s.InSegs, 0) - atomic.StoreUint64(&s.OutSegs, 0) - atomic.StoreUint64(&s.InBytes, 0) - atomic.StoreUint64(&s.OutBytes, 0) - atomic.StoreUint64(&s.RetransSegs, 0) - atomic.StoreUint64(&s.FastRetransSegs, 0) - atomic.StoreUint64(&s.EarlyRetransSegs, 0) - atomic.StoreUint64(&s.LostSegs, 0) - atomic.StoreUint64(&s.RepeatSegs, 0) - atomic.StoreUint64(&s.FECParityShards, 0) - atomic.StoreUint64(&s.FECErrs, 0) - atomic.StoreUint64(&s.FECRecovered, 0) - atomic.StoreUint64(&s.FECShortShards, 0) -} - -// DefaultSnmp is the global KCP connection statistics collector -var DefaultSnmp *Snmp - -func init() { - DefaultSnmp = newSnmp() -} diff --git a/vender/github.com/xtaci/kcp/updater.go b/vender/github.com/xtaci/kcp/updater.go deleted file mode 100644 index 9a90c82..0000000 --- a/vender/github.com/xtaci/kcp/updater.go +++ /dev/null @@ -1,104 +0,0 @@ -package kcp - -import ( - "container/heap" - "sync" - "time" -) - -var updater updateHeap - -func init() { - updater.init() - go updater.updateTask() -} - -// entry contains a session update info -type entry struct { - ts time.Time - s *UDPSession -} - -// a global heap managed kcp.flush() caller -type updateHeap struct { - entries []entry - mu sync.Mutex - chWakeUp chan struct{} -} - -func (h *updateHeap) Len() int { return len(h.entries) } -func (h *updateHeap) Less(i, j int) bool { return h.entries[i].ts.Before(h.entries[j].ts) } -func (h *updateHeap) Swap(i, j int) { - h.entries[i], h.entries[j] = h.entries[j], h.entries[i] - h.entries[i].s.updaterIdx = i - h.entries[j].s.updaterIdx = j -} - -func (h *updateHeap) Push(x interface{}) { - h.entries = append(h.entries, x.(entry)) - n := len(h.entries) - h.entries[n-1].s.updaterIdx = n - 1 -} - -func (h *updateHeap) Pop() interface{} { - n := len(h.entries) - x := h.entries[n-1] - h.entries[n-1].s.updaterIdx = -1 - h.entries[n-1] = entry{} // manual set nil for GC - h.entries = h.entries[0 : n-1] - return x -} - -func (h *updateHeap) init() { - h.chWakeUp = make(chan struct{}, 1) -} - -func (h *updateHeap) addSession(s *UDPSession) { - h.mu.Lock() - heap.Push(h, entry{time.Now(), s}) - h.mu.Unlock() - h.wakeup() -} - -func (h *updateHeap) removeSession(s *UDPSession) { - h.mu.Lock() - if s.updaterIdx != -1 { - heap.Remove(h, s.updaterIdx) - } - h.mu.Unlock() -} - -func (h *updateHeap) wakeup() { - select { - case h.chWakeUp <- struct{}{}: - default: - } -} - -func (h *updateHeap) updateTask() { - var timer <-chan time.Time - for { - select { - case <-timer: - case <-h.chWakeUp: - } - - h.mu.Lock() - hlen := h.Len() - for i := 0; i < hlen; i++ { - entry := &h.entries[0] - if time.Now().After(entry.ts) { - interval := entry.s.update() - entry.ts = time.Now().Add(interval) - heap.Fix(h, 0) - } else { - break - } - } - - if hlen > 0 { - timer = time.After(h.entries[0].ts.Sub(time.Now())) - } - h.mu.Unlock() - } -} diff --git a/vender/golang.org/x/net/internal/socks/client.go b/vender/golang.org/x/net/internal/socks/client.go deleted file mode 100644 index 3d6f516..0000000 --- a/vender/golang.org/x/net/internal/socks/client.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package socks - -import ( - "context" - "errors" - "io" - "net" - "strconv" - "time" -) - -var ( - noDeadline = time.Time{} - aLongTimeAgo = time.Unix(1, 0) -) - -func (d *Dialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) { - host, port, err := splitHostPort(address) - if err != nil { - return nil, err - } - if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() { - c.SetDeadline(deadline) - defer c.SetDeadline(noDeadline) - } - if ctx != context.Background() { - errCh := make(chan error, 1) - done := make(chan struct{}) - defer func() { - close(done) - if ctxErr == nil { - ctxErr = <-errCh - } - }() - go func() { - select { - case <-ctx.Done(): - c.SetDeadline(aLongTimeAgo) - errCh <- ctx.Err() - case <-done: - errCh <- nil - } - }() - } - - b := make([]byte, 0, 6+len(host)) // the size here is just an estimate - b = append(b, Version5) - if len(d.AuthMethods) == 0 || d.Authenticate == nil { - b = append(b, 1, byte(AuthMethodNotRequired)) - } else { - ams := d.AuthMethods - if len(ams) > 255 { - return nil, errors.New("too many authentication methods") - } - b = append(b, byte(len(ams))) - for _, am := range ams { - b = append(b, byte(am)) - } - } - if _, ctxErr = c.Write(b); ctxErr != nil { - return - } - - if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil { - return - } - if b[0] != Version5 { - return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) - } - am := AuthMethod(b[1]) - if am == AuthMethodNoAcceptableMethods { - return nil, errors.New("no acceptable authentication methods") - } - if d.Authenticate != nil { - if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil { - return - } - } - - b = b[:0] - b = append(b, Version5, byte(d.cmd), 0) - if ip := net.ParseIP(host); ip != nil { - if ip4 := ip.To4(); ip4 != nil { - b = append(b, AddrTypeIPv4) - b = append(b, ip4...) - } else if ip6 := ip.To16(); ip6 != nil { - b = append(b, AddrTypeIPv6) - b = append(b, ip6...) - } else { - return nil, errors.New("unknown address type") - } - } else { - if len(host) > 255 { - return nil, errors.New("FQDN too long") - } - b = append(b, AddrTypeFQDN) - b = append(b, byte(len(host))) - b = append(b, host...) - } - b = append(b, byte(port>>8), byte(port)) - if _, ctxErr = c.Write(b); ctxErr != nil { - return - } - - if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil { - return - } - if b[0] != Version5 { - return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) - } - if cmdErr := Reply(b[1]); cmdErr != StatusSucceeded { - return nil, errors.New("unknown error " + cmdErr.String()) - } - if b[2] != 0 { - return nil, errors.New("non-zero reserved field") - } - l := 2 - var a Addr - switch b[3] { - case AddrTypeIPv4: - l += net.IPv4len - a.IP = make(net.IP, net.IPv4len) - case AddrTypeIPv6: - l += net.IPv6len - a.IP = make(net.IP, net.IPv6len) - case AddrTypeFQDN: - if _, err := io.ReadFull(c, b[:1]); err != nil { - return nil, err - } - l += int(b[0]) - default: - return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3]))) - } - if cap(b) < l { - b = make([]byte, l) - } else { - b = b[:l] - } - if _, ctxErr = io.ReadFull(c, b); ctxErr != nil { - return - } - if a.IP != nil { - copy(a.IP, b) - } else { - a.Name = string(b[:len(b)-2]) - } - a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1]) - return &a, nil -} - -func splitHostPort(address string) (string, int, error) { - host, port, err := net.SplitHostPort(address) - if err != nil { - return "", 0, err - } - portnum, err := strconv.Atoi(port) - if err != nil { - return "", 0, err - } - if 1 > portnum || portnum > 0xffff { - return "", 0, errors.New("port number out of range " + port) - } - return host, portnum, nil -} diff --git a/vender/golang.org/x/net/internal/socks/dial_test.go b/vender/golang.org/x/net/internal/socks/dial_test.go deleted file mode 100644 index 3a7a31b..0000000 --- a/vender/golang.org/x/net/internal/socks/dial_test.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package socks_test - -import ( - "context" - "io" - "math/rand" - "net" - "os" - "testing" - "time" - - "golang.org/x/net/internal/socks" - "golang.org/x/net/internal/sockstest" -) - -func TestDial(t *testing.T) { - t.Run("Connect", func(t *testing.T) { - ss, err := sockstest.NewServer(sockstest.NoAuthRequired, sockstest.NoProxyRequired) - if err != nil { - t.Fatal(err) - } - defer ss.Close() - d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String()) - d.AuthMethods = []socks.AuthMethod{ - socks.AuthMethodNotRequired, - socks.AuthMethodUsernamePassword, - } - d.Authenticate = (&socks.UsernamePassword{ - Username: "username", - Password: "password", - }).Authenticate - c, err := d.DialContext(context.Background(), ss.TargetAddr().Network(), ss.TargetAddr().String()) - if err != nil { - t.Fatal(err) - } - c.(*socks.Conn).BoundAddr() - c.Close() - }) - t.Run("ConnectWithConn", func(t *testing.T) { - ss, err := sockstest.NewServer(sockstest.NoAuthRequired, sockstest.NoProxyRequired) - if err != nil { - t.Fatal(err) - } - defer ss.Close() - c, err := net.Dial(ss.Addr().Network(), ss.Addr().String()) - if err != nil { - t.Fatal(err) - } - defer c.Close() - d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String()) - d.AuthMethods = []socks.AuthMethod{ - socks.AuthMethodNotRequired, - socks.AuthMethodUsernamePassword, - } - d.Authenticate = (&socks.UsernamePassword{ - Username: "username", - Password: "password", - }).Authenticate - a, err := d.DialWithConn(context.Background(), c, ss.TargetAddr().Network(), ss.TargetAddr().String()) - if err != nil { - t.Fatal(err) - } - if _, ok := a.(*socks.Addr); !ok { - t.Fatalf("got %+v; want socks.Addr", a) - } - }) - t.Run("Cancel", func(t *testing.T) { - ss, err := sockstest.NewServer(sockstest.NoAuthRequired, blackholeCmdFunc) - if err != nil { - t.Fatal(err) - } - defer ss.Close() - d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String()) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - dialErr := make(chan error) - go func() { - c, err := d.DialContext(ctx, ss.TargetAddr().Network(), ss.TargetAddr().String()) - if err == nil { - c.Close() - } - dialErr <- err - }() - time.Sleep(100 * time.Millisecond) - cancel() - err = <-dialErr - if perr, nerr := parseDialError(err); perr != context.Canceled && nerr == nil { - t.Fatalf("got %v; want context.Canceled or equivalent", err) - } - }) - t.Run("Deadline", func(t *testing.T) { - ss, err := sockstest.NewServer(sockstest.NoAuthRequired, blackholeCmdFunc) - if err != nil { - t.Fatal(err) - } - defer ss.Close() - d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String()) - ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(100*time.Millisecond)) - defer cancel() - c, err := d.DialContext(ctx, ss.TargetAddr().Network(), ss.TargetAddr().String()) - if err == nil { - c.Close() - } - if perr, nerr := parseDialError(err); perr != context.DeadlineExceeded && nerr == nil { - t.Fatalf("got %v; want context.DeadlineExceeded or equivalent", err) - } - }) - t.Run("WithRogueServer", func(t *testing.T) { - ss, err := sockstest.NewServer(sockstest.NoAuthRequired, rogueCmdFunc) - if err != nil { - t.Fatal(err) - } - defer ss.Close() - d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String()) - for i := 0; i < 2*len(rogueCmdList); i++ { - ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(100*time.Millisecond)) - defer cancel() - c, err := d.DialContext(ctx, ss.TargetAddr().Network(), ss.TargetAddr().String()) - if err == nil { - t.Log(c.(*socks.Conn).BoundAddr()) - c.Close() - t.Error("should fail") - } - } - }) -} - -func blackholeCmdFunc(rw io.ReadWriter, b []byte) error { - if _, err := sockstest.ParseCmdRequest(b); err != nil { - return err - } - var bb [1]byte - for { - if _, err := rw.Read(bb[:]); err != nil { - return err - } - } -} - -func rogueCmdFunc(rw io.ReadWriter, b []byte) error { - if _, err := sockstest.ParseCmdRequest(b); err != nil { - return err - } - rw.Write(rogueCmdList[rand.Intn(len(rogueCmdList))]) - return nil -} - -var rogueCmdList = [][]byte{ - {0x05}, - {0x06, 0x00, 0x00, 0x01, 192, 0, 2, 1, 0x17, 0x4b}, - {0x05, 0x00, 0xff, 0x01, 192, 0, 2, 2, 0x17, 0x4b}, - {0x05, 0x00, 0x00, 0x01, 192, 0, 2, 3}, - {0x05, 0x00, 0x00, 0x03, 0x04, 'F', 'Q', 'D', 'N'}, -} - -func parseDialError(err error) (perr, nerr error) { - if e, ok := err.(*net.OpError); ok { - err = e.Err - nerr = e - } - if e, ok := err.(*os.SyscallError); ok { - err = e.Err - } - perr = err - return -} diff --git a/vender/golang.org/x/net/internal/socks/socks.go b/vender/golang.org/x/net/internal/socks/socks.go deleted file mode 100644 index 6929a9f..0000000 --- a/vender/golang.org/x/net/internal/socks/socks.go +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package socks provides a SOCKS version 5 client implementation. -// -// SOCKS protocol version 5 is defined in RFC 1928. -// Username/Password authentication for SOCKS version 5 is defined in -// RFC 1929. -package socks - -import ( - "context" - "errors" - "io" - "net" - "strconv" -) - -// A Command represents a SOCKS command. -type Command int - -func (cmd Command) String() string { - switch cmd { - case CmdConnect: - return "socks connect" - case cmdBind: - return "socks bind" - default: - return "socks " + strconv.Itoa(int(cmd)) - } -} - -// An AuthMethod represents a SOCKS authentication method. -type AuthMethod int - -// A Reply represents a SOCKS command reply code. -type Reply int - -func (code Reply) String() string { - switch code { - case StatusSucceeded: - return "succeeded" - case 0x01: - return "general SOCKS server failure" - case 0x02: - return "connection not allowed by ruleset" - case 0x03: - return "network unreachable" - case 0x04: - return "host unreachable" - case 0x05: - return "connection refused" - case 0x06: - return "TTL expired" - case 0x07: - return "command not supported" - case 0x08: - return "address type not supported" - default: - return "unknown code: " + strconv.Itoa(int(code)) - } -} - -// Wire protocol constants. -const ( - Version5 = 0x05 - - AddrTypeIPv4 = 0x01 - AddrTypeFQDN = 0x03 - AddrTypeIPv6 = 0x04 - - CmdConnect Command = 0x01 // establishes an active-open forward proxy connection - cmdBind Command = 0x02 // establishes a passive-open forward proxy connection - - AuthMethodNotRequired AuthMethod = 0x00 // no authentication required - AuthMethodUsernamePassword AuthMethod = 0x02 // use username/password - AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods - - StatusSucceeded Reply = 0x00 -) - -// An Addr represents a SOCKS-specific address. -// Either Name or IP is used exclusively. -type Addr struct { - Name string // fully-qualified domain name - IP net.IP - Port int -} - -func (a *Addr) Network() string { return "socks" } - -func (a *Addr) String() string { - if a == nil { - return "" - } - port := strconv.Itoa(a.Port) - if a.IP == nil { - return net.JoinHostPort(a.Name, port) - } - return net.JoinHostPort(a.IP.String(), port) -} - -// A Conn represents a forward proxy connection. -type Conn struct { - net.Conn - - boundAddr net.Addr -} - -// BoundAddr returns the address assigned by the proxy server for -// connecting to the command target address from the proxy server. -func (c *Conn) BoundAddr() net.Addr { - if c == nil { - return nil - } - return c.boundAddr -} - -// A Dialer holds SOCKS-specific options. -type Dialer struct { - cmd Command // either CmdConnect or cmdBind - proxyNetwork string // network between a proxy server and a client - proxyAddress string // proxy server address - - // ProxyDial specifies the optional dial function for - // establishing the transport connection. - ProxyDial func(context.Context, string, string) (net.Conn, error) - - // AuthMethods specifies the list of request authention - // methods. - // If empty, SOCKS client requests only AuthMethodNotRequired. - AuthMethods []AuthMethod - - // Authenticate specifies the optional authentication - // function. It must be non-nil when AuthMethods is not empty. - // It must return an error when the authentication is failed. - Authenticate func(context.Context, io.ReadWriter, AuthMethod) error -} - -// DialContext connects to the provided address on the provided -// network. -// -// The returned error value may be a net.OpError. When the Op field of -// net.OpError contains "socks", the Source field contains a proxy -// server address and the Addr field contains a command target -// address. -// -// See func Dial of the net package of standard library for a -// description of the network and address parameters. -func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { - if err := d.validateTarget(network, address); err != nil { - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} - } - if ctx == nil { - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")} - } - var err error - var c net.Conn - if d.ProxyDial != nil { - c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress) - } else { - var dd net.Dialer - c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress) - } - if err != nil { - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} - } - a, err := d.connect(ctx, c, address) - if err != nil { - c.Close() - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} - } - return &Conn{Conn: c, boundAddr: a}, nil -} - -// DialWithConn initiates a connection from SOCKS server to the target -// network and address using the connection c that is already -// connected to the SOCKS server. -// -// It returns the connection's local address assigned by the SOCKS -// server. -func (d *Dialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) { - if err := d.validateTarget(network, address); err != nil { - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} - } - if ctx == nil { - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")} - } - a, err := d.connect(ctx, c, address) - if err != nil { - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} - } - return a, nil -} - -// Dial connects to the provided address on the provided network. -// -// Unlike DialContext, it returns a raw transport connection instead -// of a forward proxy connection. -// -// Deprecated: Use DialContext or DialWithConn instead. -func (d *Dialer) Dial(network, address string) (net.Conn, error) { - if err := d.validateTarget(network, address); err != nil { - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} - } - var err error - var c net.Conn - if d.ProxyDial != nil { - c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress) - } else { - c, err = net.Dial(d.proxyNetwork, d.proxyAddress) - } - if err != nil { - proxy, dst, _ := d.pathAddrs(address) - return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} - } - if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil { - c.Close() - return nil, err - } - return c, nil -} - -func (d *Dialer) validateTarget(network, address string) error { - switch network { - case "tcp", "tcp6", "tcp4": - default: - return errors.New("network not implemented") - } - switch d.cmd { - case CmdConnect, cmdBind: - default: - return errors.New("command not implemented") - } - return nil -} - -func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) { - for i, s := range []string{d.proxyAddress, address} { - host, port, err := splitHostPort(s) - if err != nil { - return nil, nil, err - } - a := &Addr{Port: port} - a.IP = net.ParseIP(host) - if a.IP == nil { - a.Name = host - } - if i == 0 { - proxy = a - } else { - dst = a - } - } - return -} - -// NewDialer returns a new Dialer that dials through the provided -// proxy server's network and address. -func NewDialer(network, address string) *Dialer { - return &Dialer{proxyNetwork: network, proxyAddress: address, cmd: CmdConnect} -} - -const ( - authUsernamePasswordVersion = 0x01 - authStatusSucceeded = 0x00 -) - -// UsernamePassword are the credentials for the username/password -// authentication method. -type UsernamePassword struct { - Username string - Password string -} - -// Authenticate authenticates a pair of username and password with the -// proxy server. -func (up *UsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth AuthMethod) error { - switch auth { - case AuthMethodNotRequired: - return nil - case AuthMethodUsernamePassword: - if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) == 0 || len(up.Password) > 255 { - return errors.New("invalid username/password") - } - b := []byte{authUsernamePasswordVersion} - b = append(b, byte(len(up.Username))) - b = append(b, up.Username...) - b = append(b, byte(len(up.Password))) - b = append(b, up.Password...) - // TODO(mikio): handle IO deadlines and cancelation if - // necessary - if _, err := rw.Write(b); err != nil { - return err - } - if _, err := io.ReadFull(rw, b[:2]); err != nil { - return err - } - if b[0] != authUsernamePasswordVersion { - return errors.New("invalid username/password version") - } - if b[1] != authStatusSucceeded { - return errors.New("username/password authentication failed") - } - return nil - } - return errors.New("unsupported authentication method " + strconv.Itoa(int(auth))) -} diff --git a/vender/golang.org/x/net/proxy/direct.go b/vender/golang.org/x/net/proxy/direct.go deleted file mode 100644 index 4c5ad88..0000000 --- a/vender/golang.org/x/net/proxy/direct.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proxy - -import ( - "net" -) - -type direct struct{} - -// Direct is a direct proxy: one that makes network connections directly. -var Direct = direct{} - -func (direct) Dial(network, addr string) (net.Conn, error) { - return net.Dial(network, addr) -} diff --git a/vender/golang.org/x/net/proxy/per_host.go b/vender/golang.org/x/net/proxy/per_host.go deleted file mode 100644 index 0689bb6..0000000 --- a/vender/golang.org/x/net/proxy/per_host.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proxy - -import ( - "net" - "strings" -) - -// A PerHost directs connections to a default Dialer unless the host name -// requested matches one of a number of exceptions. -type PerHost struct { - def, bypass Dialer - - bypassNetworks []*net.IPNet - bypassIPs []net.IP - bypassZones []string - bypassHosts []string -} - -// NewPerHost returns a PerHost Dialer that directs connections to either -// defaultDialer or bypass, depending on whether the connection matches one of -// the configured rules. -func NewPerHost(defaultDialer, bypass Dialer) *PerHost { - return &PerHost{ - def: defaultDialer, - bypass: bypass, - } -} - -// Dial connects to the address addr on the given network through either -// defaultDialer or bypass. -func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) { - host, _, err := net.SplitHostPort(addr) - if err != nil { - return nil, err - } - - return p.dialerForRequest(host).Dial(network, addr) -} - -func (p *PerHost) dialerForRequest(host string) Dialer { - if ip := net.ParseIP(host); ip != nil { - for _, net := range p.bypassNetworks { - if net.Contains(ip) { - return p.bypass - } - } - for _, bypassIP := range p.bypassIPs { - if bypassIP.Equal(ip) { - return p.bypass - } - } - return p.def - } - - for _, zone := range p.bypassZones { - if strings.HasSuffix(host, zone) { - return p.bypass - } - if host == zone[1:] { - // For a zone ".example.com", we match "example.com" - // too. - return p.bypass - } - } - for _, bypassHost := range p.bypassHosts { - if bypassHost == host { - return p.bypass - } - } - return p.def -} - -// AddFromString parses a string that contains comma-separated values -// specifying hosts that should use the bypass proxy. Each value is either an -// IP address, a CIDR range, a zone (*.example.com) or a host name -// (localhost). A best effort is made to parse the string and errors are -// ignored. -func (p *PerHost) AddFromString(s string) { - hosts := strings.Split(s, ",") - for _, host := range hosts { - host = strings.TrimSpace(host) - if len(host) == 0 { - continue - } - if strings.Contains(host, "/") { - // We assume that it's a CIDR address like 127.0.0.0/8 - if _, net, err := net.ParseCIDR(host); err == nil { - p.AddNetwork(net) - } - continue - } - if ip := net.ParseIP(host); ip != nil { - p.AddIP(ip) - continue - } - if strings.HasPrefix(host, "*.") { - p.AddZone(host[1:]) - continue - } - p.AddHost(host) - } -} - -// AddIP specifies an IP address that will use the bypass proxy. Note that -// this will only take effect if a literal IP address is dialed. A connection -// to a named host will never match an IP. -func (p *PerHost) AddIP(ip net.IP) { - p.bypassIPs = append(p.bypassIPs, ip) -} - -// AddNetwork specifies an IP range that will use the bypass proxy. Note that -// this will only take effect if a literal IP address is dialed. A connection -// to a named host will never match. -func (p *PerHost) AddNetwork(net *net.IPNet) { - p.bypassNetworks = append(p.bypassNetworks, net) -} - -// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of -// "example.com" matches "example.com" and all of its subdomains. -func (p *PerHost) AddZone(zone string) { - if strings.HasSuffix(zone, ".") { - zone = zone[:len(zone)-1] - } - if !strings.HasPrefix(zone, ".") { - zone = "." + zone - } - p.bypassZones = append(p.bypassZones, zone) -} - -// AddHost specifies a host name that will use the bypass proxy. -func (p *PerHost) AddHost(host string) { - if strings.HasSuffix(host, ".") { - host = host[:len(host)-1] - } - p.bypassHosts = append(p.bypassHosts, host) -} diff --git a/vender/golang.org/x/net/proxy/per_host_test.go b/vender/golang.org/x/net/proxy/per_host_test.go deleted file mode 100644 index a7d8095..0000000 --- a/vender/golang.org/x/net/proxy/per_host_test.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proxy - -import ( - "errors" - "net" - "reflect" - "testing" -) - -type recordingProxy struct { - addrs []string -} - -func (r *recordingProxy) Dial(network, addr string) (net.Conn, error) { - r.addrs = append(r.addrs, addr) - return nil, errors.New("recordingProxy") -} - -func TestPerHost(t *testing.T) { - var def, bypass recordingProxy - perHost := NewPerHost(&def, &bypass) - perHost.AddFromString("localhost,*.zone,127.0.0.1,10.0.0.1/8,1000::/16") - - expectedDef := []string{ - "example.com:123", - "1.2.3.4:123", - "[1001::]:123", - } - expectedBypass := []string{ - "localhost:123", - "zone:123", - "foo.zone:123", - "127.0.0.1:123", - "10.1.2.3:123", - "[1000::]:123", - } - - for _, addr := range expectedDef { - perHost.Dial("tcp", addr) - } - for _, addr := range expectedBypass { - perHost.Dial("tcp", addr) - } - - if !reflect.DeepEqual(expectedDef, def.addrs) { - t.Errorf("Hosts which went to the default proxy didn't match. Got %v, want %v", def.addrs, expectedDef) - } - if !reflect.DeepEqual(expectedBypass, bypass.addrs) { - t.Errorf("Hosts which went to the bypass proxy didn't match. Got %v, want %v", bypass.addrs, expectedBypass) - } -} diff --git a/vender/golang.org/x/net/proxy/proxy.go b/vender/golang.org/x/net/proxy/proxy.go deleted file mode 100644 index 9f232f8..0000000 --- a/vender/golang.org/x/net/proxy/proxy.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package proxy provides support for a variety of protocols to proxy network -// data. -package proxy - -import ( - "errors" - "net" - "net/url" - "os" - "sync" -) - -// A Dialer is a means to establish a connection. -type Dialer interface { - // Dial connects to the given address via the proxy. - Dial(network, addr string) (c net.Conn, err error) -} - -// Auth contains authentication parameters that specific Dialers may require. -type Auth struct { - User, Password string -} - -// FromEnvironment returns the dialer specified by the proxy related variables in -// the environment. -func FromEnvironment() Dialer { - allProxy := allProxyEnv.Get() - if len(allProxy) == 0 { - return Direct - } - - proxyURL, err := url.Parse(allProxy) - if err != nil { - return Direct - } - proxy, err := FromURL(proxyURL, Direct) - if err != nil { - return Direct - } - - noProxy := noProxyEnv.Get() - if len(noProxy) == 0 { - return proxy - } - - perHost := NewPerHost(proxy, Direct) - perHost.AddFromString(noProxy) - return perHost -} - -// proxySchemes is a map from URL schemes to a function that creates a Dialer -// from a URL with such a scheme. -var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error) - -// RegisterDialerType takes a URL scheme and a function to generate Dialers from -// a URL with that scheme and a forwarding Dialer. Registered schemes are used -// by FromURL. -func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) { - if proxySchemes == nil { - proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error)) - } - proxySchemes[scheme] = f -} - -// FromURL returns a Dialer given a URL specification and an underlying -// Dialer for it to make network requests. -func FromURL(u *url.URL, forward Dialer) (Dialer, error) { - var auth *Auth - if u.User != nil { - auth = new(Auth) - auth.User = u.User.Username() - if p, ok := u.User.Password(); ok { - auth.Password = p - } - } - - switch u.Scheme { - case "socks5": - return SOCKS5("tcp", u.Host, auth, forward) - } - - // If the scheme doesn't match any of the built-in schemes, see if it - // was registered by another package. - if proxySchemes != nil { - if f, ok := proxySchemes[u.Scheme]; ok { - return f(u, forward) - } - } - - return nil, errors.New("proxy: unknown scheme: " + u.Scheme) -} - -var ( - allProxyEnv = &envOnce{ - names: []string{"ALL_PROXY", "all_proxy"}, - } - noProxyEnv = &envOnce{ - names: []string{"NO_PROXY", "no_proxy"}, - } -) - -// envOnce looks up an environment variable (optionally by multiple -// names) once. It mitigates expensive lookups on some platforms -// (e.g. Windows). -// (Borrowed from net/http/transport.go) -type envOnce struct { - names []string - once sync.Once - val string -} - -func (e *envOnce) Get() string { - e.once.Do(e.init) - return e.val -} - -func (e *envOnce) init() { - for _, n := range e.names { - e.val = os.Getenv(n) - if e.val != "" { - return - } - } -} - -// reset is used by tests -func (e *envOnce) reset() { - e.once = sync.Once{} - e.val = "" -} diff --git a/vender/golang.org/x/net/proxy/proxy_test.go b/vender/golang.org/x/net/proxy/proxy_test.go deleted file mode 100644 index 0be1b42..0000000 --- a/vender/golang.org/x/net/proxy/proxy_test.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proxy - -import ( - "bytes" - "fmt" - "net/url" - "os" - "strings" - "testing" - - "golang.org/x/net/internal/sockstest" -) - -type proxyFromEnvTest struct { - allProxyEnv string - noProxyEnv string - wantTypeOf Dialer -} - -func (t proxyFromEnvTest) String() string { - var buf bytes.Buffer - space := func() { - if buf.Len() > 0 { - buf.WriteByte(' ') - } - } - if t.allProxyEnv != "" { - fmt.Fprintf(&buf, "all_proxy=%q", t.allProxyEnv) - } - if t.noProxyEnv != "" { - space() - fmt.Fprintf(&buf, "no_proxy=%q", t.noProxyEnv) - } - return strings.TrimSpace(buf.String()) -} - -func TestFromEnvironment(t *testing.T) { - ResetProxyEnv() - - type dummyDialer struct { - direct - } - - RegisterDialerType("irc", func(_ *url.URL, _ Dialer) (Dialer, error) { - return dummyDialer{}, nil - }) - - proxyFromEnvTests := []proxyFromEnvTest{ - {allProxyEnv: "127.0.0.1:8080", noProxyEnv: "localhost, 127.0.0.1", wantTypeOf: direct{}}, - {allProxyEnv: "ftp://example.com:8000", noProxyEnv: "localhost, 127.0.0.1", wantTypeOf: direct{}}, - {allProxyEnv: "socks5://example.com:8080", noProxyEnv: "localhost, 127.0.0.1", wantTypeOf: &PerHost{}}, - {allProxyEnv: "irc://example.com:8000", wantTypeOf: dummyDialer{}}, - {noProxyEnv: "localhost, 127.0.0.1", wantTypeOf: direct{}}, - {wantTypeOf: direct{}}, - } - - for _, tt := range proxyFromEnvTests { - os.Setenv("ALL_PROXY", tt.allProxyEnv) - os.Setenv("NO_PROXY", tt.noProxyEnv) - ResetCachedEnvironment() - - d := FromEnvironment() - if got, want := fmt.Sprintf("%T", d), fmt.Sprintf("%T", tt.wantTypeOf); got != want { - t.Errorf("%v: got type = %T, want %T", tt, d, tt.wantTypeOf) - } - } -} - -func TestFromURL(t *testing.T) { - ss, err := sockstest.NewServer(sockstest.NoAuthRequired, sockstest.NoProxyRequired) - if err != nil { - t.Fatal(err) - } - defer ss.Close() - url, err := url.Parse("socks5://user:password@" + ss.Addr().String()) - if err != nil { - t.Fatal(err) - } - proxy, err := FromURL(url, nil) - if err != nil { - t.Fatal(err) - } - c, err := proxy.Dial("tcp", "fqdn.doesnotexist:5963") - if err != nil { - t.Fatal(err) - } - c.Close() -} - -func TestSOCKS5(t *testing.T) { - ss, err := sockstest.NewServer(sockstest.NoAuthRequired, sockstest.NoProxyRequired) - if err != nil { - t.Fatal(err) - } - defer ss.Close() - proxy, err := SOCKS5("tcp", ss.Addr().String(), nil, nil) - if err != nil { - t.Fatal(err) - } - c, err := proxy.Dial("tcp", ss.TargetAddr().String()) - if err != nil { - t.Fatal(err) - } - c.Close() -} - -func ResetProxyEnv() { - for _, env := range []*envOnce{allProxyEnv, noProxyEnv} { - for _, v := range env.names { - os.Setenv(v, "") - } - } - ResetCachedEnvironment() -} - -func ResetCachedEnvironment() { - allProxyEnv.reset() - noProxyEnv.reset() -} diff --git a/vender/golang.org/x/net/proxy/socks5.go b/vender/golang.org/x/net/proxy/socks5.go deleted file mode 100644 index 00d225e..0000000 --- a/vender/golang.org/x/net/proxy/socks5.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proxy - -import ( - "context" - "net" - - "github.com/cnlh/nps/vender/golang.org/x/net/internal/socks" -) - -// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given -// address with an optional username and password. -// See RFC 1928 and RFC 1929. -func SOCKS5(network, address string, auth *Auth, forward Dialer) (Dialer, error) { - d := socks.NewDialer(network, address) - if forward != nil { - d.ProxyDial = func(_ context.Context, network string, address string) (net.Conn, error) { - return forward.Dial(network, address) - } - } - if auth != nil { - up := socks.UsernamePassword{ - Username: auth.User, - Password: auth.Password, - } - d.AuthMethods = []socks.AuthMethod{ - socks.AuthMethodNotRequired, - socks.AuthMethodUsernamePassword, - } - d.Authenticate = up.Authenticate - } - return d, nil -} diff --git a/web/controllers/auth.go b/web/controllers/auth.go index 5649e82..5d8cac6 100644 --- a/web/controllers/auth.go +++ b/web/controllers/auth.go @@ -3,7 +3,7 @@ package controllers import ( "encoding/hex" "github.com/cnlh/nps/lib/crypt" - "github.com/cnlh/nps/vender/github.com/astaxie/beego" + "github.com/astaxie/beego" "time" ) diff --git a/web/controllers/base.go b/web/controllers/base.go index cbfa1cc..089cee4 100755 --- a/web/controllers/base.go +++ b/web/controllers/base.go @@ -5,7 +5,7 @@ import ( "github.com/cnlh/nps/lib/crypt" "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/server" - "github.com/cnlh/nps/vender/github.com/astaxie/beego" + "github.com/astaxie/beego" "html" "math" "strconv" diff --git a/web/controllers/client.go b/web/controllers/client.go index 78d2d07..ffe5f59 100644 --- a/web/controllers/client.go +++ b/web/controllers/client.go @@ -5,7 +5,7 @@ import ( "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/lib/rate" "github.com/cnlh/nps/server" - "github.com/cnlh/nps/vender/github.com/astaxie/beego" + "github.com/astaxie/beego" ) type ClientController struct { diff --git a/web/controllers/login.go b/web/controllers/login.go index 7b8a55d..da40e64 100755 --- a/web/controllers/login.go +++ b/web/controllers/login.go @@ -4,7 +4,7 @@ import ( "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/server" - "github.com/cnlh/nps/vender/github.com/astaxie/beego" + "github.com/astaxie/beego" "time" ) diff --git a/web/routers/router.go b/web/routers/router.go index 690df3b..f86facf 100755 --- a/web/routers/router.go +++ b/web/routers/router.go @@ -1,7 +1,7 @@ package routers import ( - "github.com/cnlh/nps/vender/github.com/astaxie/beego" + "github.com/astaxie/beego" "github.com/cnlh/nps/web/controllers" ) From b0d16d3b3da215c45af6e59d5531a15f302f44c6 Mon Sep 17 00:00:00 2001 From: exfly Date: Sat, 10 Aug 2019 11:15:25 +0800 Subject: [PATCH 06/58] style: fmt --- bridge/bridge.go | 19 ++++++++++--------- client/client.go | 11 ++++++----- client/client_test.go | 7 ++++--- client/control.go | 19 ++++++++++--------- client/health.go | 13 +++++++------ client/local.go | 13 +++++++------ client/register.go | 3 ++- cmd/npc/npc.go | 11 ++++++----- cmd/nps/nps.go | 11 ++++++----- lib/common/util.go | 5 +++-- lib/config/config.go | 5 +++-- lib/conn/conn.go | 17 +++++++++-------- lib/conn/listener.go | 5 +++-- lib/conn/snappy.go | 3 ++- lib/crypt/tls.go | 3 ++- lib/daemon/daemon.go | 3 ++- lib/daemon/reload.go | 5 +++-- lib/file/db.go | 7 ++++--- lib/file/file.go | 5 +++-- lib/file/obj.go | 5 +++-- lib/install/install.go | 3 ++- lib/mux/conn.go | 3 ++- lib/mux/mux.go | 5 +++-- lib/mux/mux_test.go | 7 ++++--- lib/mux/pmux.go | 7 ++++--- lib/mux/pmux_test.go | 5 +++-- lib/mux/queue.go | 3 ++- lib/pool/pool.go | 3 ++- server/connection/connection.go | 7 ++++--- server/proxy/base.go | 9 +++++---- server/proxy/http.go | 15 ++++++++------- server/proxy/https.go | 13 +++++++------ server/proxy/p2p.go | 7 ++++--- server/proxy/socks5.go | 11 ++++++----- server/proxy/transport.go | 5 +++-- server/proxy/udp.go | 7 ++++--- server/server.go | 4 ++-- server/test/test.go | 7 ++++--- server/tool/utils.go | 9 +++++---- web/controllers/auth.go | 5 +++-- web/controllers/base.go | 11 ++++++----- web/controllers/client.go | 2 +- web/controllers/login.go | 5 +++-- 43 files changed, 182 insertions(+), 141 deletions(-) diff --git a/bridge/bridge.go b/bridge/bridge.go index abaa737..53a2e76 100755 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -4,6 +4,15 @@ import ( "encoding/binary" "errors" "fmt" + "net" + "os" + "strconv" + "strings" + "sync" + "time" + + "github.com/astaxie/beego" + "github.com/astaxie/beego/logs" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/crypt" @@ -12,14 +21,6 @@ import ( "github.com/cnlh/nps/lib/version" "github.com/cnlh/nps/server/connection" "github.com/cnlh/nps/server/tool" - "github.com/astaxie/beego" - "github.com/astaxie/beego/logs" - "net" - "os" - "strconv" - "strings" - "sync" - "time" ) type Client struct { @@ -146,7 +147,7 @@ func (s *Bridge) GetHealthFromClient(id int, c *conn.Conn) { }) } } - s.DelClient(id, ) + s.DelClient(id) } //验证失败,返回错误验证flag,并且关闭连接 diff --git a/client/client.go b/client/client.go index c338293..52da907 100755 --- a/client/client.go +++ b/client/client.go @@ -2,17 +2,18 @@ package client import ( "bufio" + "net" + "net/http" + "strconv" + "time" + + "github.com/astaxie/beego/logs" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/config" "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/crypt" "github.com/cnlh/nps/lib/mux" - "github.com/astaxie/beego/logs" "github.com/xtaci/kcp-go" - "net" - "net/http" - "strconv" - "time" ) type TRPClient struct { diff --git a/client/client_test.go b/client/client_test.go index 3ab27db..84ff3b0 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -1,12 +1,13 @@ package client import ( - "github.com/cnlh/nps/lib/common" - conn2 "github.com/cnlh/nps/lib/conn" - "github.com/cnlh/nps/lib/file" "net" "sync" "testing" + + "github.com/cnlh/nps/lib/common" + conn2 "github.com/cnlh/nps/lib/conn" + "github.com/cnlh/nps/lib/file" ) func TestConfig(t *testing.T) { diff --git a/client/control.go b/client/control.go index 7b0e39b..5673f14 100644 --- a/client/control.go +++ b/client/control.go @@ -5,14 +5,6 @@ import ( "encoding/binary" "errors" "fmt" - "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/config" - "github.com/cnlh/nps/lib/conn" - "github.com/cnlh/nps/lib/crypt" - "github.com/cnlh/nps/lib/version" - "github.com/astaxie/beego/logs" - "github.com/xtaci/kcp-go" - "golang.org/x/net/proxy" "io/ioutil" "log" "math" @@ -26,6 +18,15 @@ import ( "strconv" "strings" "time" + + "github.com/astaxie/beego/logs" + "github.com/cnlh/nps/lib/common" + "github.com/cnlh/nps/lib/config" + "github.com/cnlh/nps/lib/conn" + "github.com/cnlh/nps/lib/crypt" + "github.com/cnlh/nps/lib/version" + "github.com/xtaci/kcp-go" + "golang.org/x/net/proxy" ) func GetTaskStatus(path string) { @@ -379,7 +380,7 @@ func sendP2PTestMsg(localConn *net.UDPConn, remoteAddr1, remoteAddr2, remoteAddr ip := common.GetIpByAddr(remoteAddr2) go func() { ports := getRandomPortArr(common.GetPortByAddr(remoteAddr3), common.GetPortByAddr(remoteAddr3)+interval*50) - for i := 0; i <= 50; i ++ { + for i := 0; i <= 50; i++ { go func(port int) { trueAddress := ip + ":" + strconv.Itoa(port) logs.Trace("try send test packet to target %s", trueAddress) diff --git a/client/health.go b/client/health.go index b57e7c0..9e0760f 100644 --- a/client/health.go +++ b/client/health.go @@ -2,15 +2,16 @@ package client import ( "container/heap" - "github.com/cnlh/nps/lib/conn" - "github.com/cnlh/nps/lib/file" - "github.com/cnlh/nps/lib/sheap" - "github.com/astaxie/beego/logs" - "github.com/pkg/errors" "net" "net/http" "strings" "time" + + "github.com/astaxie/beego/logs" + "github.com/cnlh/nps/lib/conn" + "github.com/cnlh/nps/lib/file" + "github.com/cnlh/nps/lib/sheap" + "github.com/pkg/errors" ) var isStart bool @@ -70,7 +71,7 @@ func check(t *file.Health) { var rs *http.Response for _, v := range arr { if t.HealthCheckType == "tcp" { - _, err = net.DialTimeout("tcp", v, time.Duration(t.HealthCheckTimeout)*time.Second); + _, err = net.DialTimeout("tcp", v, time.Duration(t.HealthCheckTimeout)*time.Second) } else { client := &http.Client{} client.Timeout = time.Duration(t.HealthCheckTimeout) * time.Second diff --git a/client/local.go b/client/local.go index 212fd70..55b9df9 100644 --- a/client/local.go +++ b/client/local.go @@ -1,6 +1,12 @@ package client import ( + "net" + "net/http" + "sync" + "time" + + "github.com/astaxie/beego/logs" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/config" "github.com/cnlh/nps/lib/conn" @@ -8,12 +14,7 @@ import ( "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/lib/mux" "github.com/cnlh/nps/server/proxy" - "github.com/astaxie/beego/logs" "github.com/xtaci/kcp-go" - "net" - "net/http" - "sync" - "time" ) var ( @@ -116,7 +117,7 @@ func StartLocalServer(l *config.LocalServer, config *config.CommonConfig) error func handleUdpMonitor(config *config.CommonConfig, l *config.LocalServer) { ticker := time.NewTicker(time.Second * 1) - for{ + for { select { case <-ticker.C: if !udpConnStatus { diff --git a/client/register.go b/client/register.go index 2d994aa..c03fb3c 100644 --- a/client/register.go +++ b/client/register.go @@ -2,9 +2,10 @@ package client import ( "encoding/binary" - "github.com/cnlh/nps/lib/common" "log" "os" + + "github.com/cnlh/nps/lib/common" ) func RegisterLocalIp(server string, vKey string, tp string, proxyUrl string, hour int) { diff --git a/cmd/npc/npc.go b/cmd/npc/npc.go index 501718b..fe5b3f5 100644 --- a/cmd/npc/npc.go +++ b/cmd/npc/npc.go @@ -3,17 +3,18 @@ package main import ( "flag" "fmt" + "os" + "strings" + "time" + + "github.com/astaxie/beego/logs" + "github.com/ccding/go-stun/stun" "github.com/cnlh/nps/client" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/config" "github.com/cnlh/nps/lib/daemon" "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/lib/version" - "github.com/astaxie/beego/logs" - "github.com/ccding/go-stun/stun" - "os" - "strings" - "time" ) var ( diff --git a/cmd/nps/nps.go b/cmd/nps/nps.go index ff54052..f66fe66 100644 --- a/cmd/nps/nps.go +++ b/cmd/nps/nps.go @@ -2,6 +2,12 @@ package main import ( "flag" + "log" + "os" + "path/filepath" + + "github.com/astaxie/beego" + "github.com/astaxie/beego/logs" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/crypt" "github.com/cnlh/nps/lib/daemon" @@ -12,12 +18,7 @@ import ( "github.com/cnlh/nps/server/connection" "github.com/cnlh/nps/server/test" "github.com/cnlh/nps/server/tool" - "github.com/astaxie/beego" - "github.com/astaxie/beego/logs" _ "github.com/cnlh/nps/web/routers" - "log" - "os" - "path/filepath" ) var ( diff --git a/lib/common/util.go b/lib/common/util.go index ce4381d..41f8b3c 100755 --- a/lib/common/util.go +++ b/lib/common/util.go @@ -4,8 +4,6 @@ import ( "bytes" "encoding/base64" "encoding/binary" - "github.com/cnlh/nps/lib/crypt" - "github.com/cnlh/nps/lib/pool" "html/template" "io" "io/ioutil" @@ -16,6 +14,9 @@ import ( "strconv" "strings" "sync" + + "github.com/cnlh/nps/lib/crypt" + "github.com/cnlh/nps/lib/pool" ) //Get the corresponding IP address through domain name diff --git a/lib/config/config.go b/lib/config/config.go index 7b4ce5c..c4d144e 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -3,10 +3,11 @@ package config import ( "errors" "fmt" - "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/file" "regexp" "strings" + + "github.com/cnlh/nps/lib/common" + "github.com/cnlh/nps/lib/file" ) type CommonConfig struct { diff --git a/lib/conn/conn.go b/lib/conn/conn.go index 91d1779..c60941e 100755 --- a/lib/conn/conn.go +++ b/lib/conn/conn.go @@ -6,13 +6,6 @@ import ( "encoding/binary" "encoding/json" "errors" - "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/crypt" - "github.com/cnlh/nps/lib/file" - "github.com/cnlh/nps/lib/mux" - "github.com/cnlh/nps/lib/pool" - "github.com/cnlh/nps/lib/rate" - "github.com/xtaci/kcp-go" "io" "net" "net/http" @@ -21,6 +14,14 @@ import ( "strings" "sync" "time" + + "github.com/cnlh/nps/lib/common" + "github.com/cnlh/nps/lib/crypt" + "github.com/cnlh/nps/lib/file" + "github.com/cnlh/nps/lib/mux" + "github.com/cnlh/nps/lib/pool" + "github.com/cnlh/nps/lib/rate" + "github.com/xtaci/kcp-go" ) type Conn struct { @@ -373,7 +374,7 @@ func CopyWaitGroup(conn1, conn2 net.Conn, crypt bool, snappy bool, rate *rate.Ra } //get crypt or snappy conn -func GetConn(conn net.Conn, cpt, snappy bool, rt *rate.Rate, isServer bool) (io.ReadWriteCloser) { +func GetConn(conn net.Conn, cpt, snappy bool, rt *rate.Rate, isServer bool) io.ReadWriteCloser { if cpt { if isServer { return rate.NewRateConn(crypt.NewTlsServerConn(conn), rt) diff --git a/lib/conn/listener.go b/lib/conn/listener.go index 1d23644..f80e01d 100644 --- a/lib/conn/listener.go +++ b/lib/conn/listener.go @@ -1,10 +1,11 @@ package conn import ( - "github.com/astaxie/beego/logs" - "github.com/xtaci/kcp-go" "net" "strings" + + "github.com/astaxie/beego/logs" + "github.com/xtaci/kcp-go" ) func NewTcpListenerAndProcess(addr string, f func(c net.Conn), listener *net.Listener) error { diff --git a/lib/conn/snappy.go b/lib/conn/snappy.go index 729acb3..a655627 100644 --- a/lib/conn/snappy.go +++ b/lib/conn/snappy.go @@ -1,9 +1,10 @@ package conn import ( + "io" + "github.com/cnlh/nps/lib/pool" "github.com/golang/snappy" - "io" ) type SnappyConn struct { diff --git a/lib/crypt/tls.go b/lib/crypt/tls.go index 75f291a..35a0a74 100644 --- a/lib/crypt/tls.go +++ b/lib/crypt/tls.go @@ -2,9 +2,10 @@ package crypt import ( "crypto/tls" - "github.com/astaxie/beego/logs" "net" "os" + + "github.com/astaxie/beego/logs" ) var pemPath, keyPath string diff --git a/lib/daemon/daemon.go b/lib/daemon/daemon.go index 54454b2..3c41086 100644 --- a/lib/daemon/daemon.go +++ b/lib/daemon/daemon.go @@ -1,7 +1,6 @@ package daemon import ( - "github.com/cnlh/nps/lib/common" "io/ioutil" "log" "os" @@ -9,6 +8,8 @@ import ( "path/filepath" "strconv" "strings" + + "github.com/cnlh/nps/lib/common" ) func InitDaemon(f string, runPath string, pidPath string) { diff --git a/lib/daemon/reload.go b/lib/daemon/reload.go index 6b075b6..2db00ac 100644 --- a/lib/daemon/reload.go +++ b/lib/daemon/reload.go @@ -3,12 +3,13 @@ package daemon import ( - "github.com/cnlh/nps/lib/common" - "github.com/astaxie/beego" "os" "os/signal" "path/filepath" "syscall" + + "github.com/astaxie/beego" + "github.com/cnlh/nps/lib/common" ) func init() { diff --git a/lib/file/db.go b/lib/file/db.go index 69e33d6..c48df2e 100644 --- a/lib/file/db.go +++ b/lib/file/db.go @@ -3,14 +3,15 @@ package file import ( "errors" "fmt" - "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/crypt" - "github.com/cnlh/nps/lib/rate" "net/http" "regexp" "sort" "strings" "sync" + + "github.com/cnlh/nps/lib/common" + "github.com/cnlh/nps/lib/crypt" + "github.com/cnlh/nps/lib/rate" ) type DbUtils struct { diff --git a/lib/file/file.go b/lib/file/file.go index 541e617..63f3cb7 100644 --- a/lib/file/file.go +++ b/lib/file/file.go @@ -3,13 +3,14 @@ package file import ( "encoding/json" "errors" - "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/rate" "os" "path/filepath" "strings" "sync" "sync/atomic" + + "github.com/cnlh/nps/lib/common" + "github.com/cnlh/nps/lib/rate" ) func NewJsonDb(runPath string) *JsonDb { diff --git a/lib/file/obj.go b/lib/file/obj.go index 3e7acf0..d3a1fbe 100644 --- a/lib/file/obj.go +++ b/lib/file/obj.go @@ -1,12 +1,13 @@ package file import ( - "github.com/cnlh/nps/lib/rate" - "github.com/pkg/errors" "strings" "sync" "sync/atomic" "time" + + "github.com/cnlh/nps/lib/rate" + "github.com/pkg/errors" ) type Flow struct { diff --git a/lib/install/install.go b/lib/install/install.go index 5b2a515..411a2e2 100644 --- a/lib/install/install.go +++ b/lib/install/install.go @@ -3,12 +3,13 @@ package install import ( "errors" "fmt" - "github.com/cnlh/nps/lib/common" "io" "log" "os" "path/filepath" "strings" + + "github.com/cnlh/nps/lib/common" ) func InstallNps() { diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 9e66577..5016771 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -2,11 +2,12 @@ package mux import ( "errors" - "github.com/cnlh/nps/lib/pool" "io" "net" "sync" "time" + + "github.com/cnlh/nps/lib/pool" ) type conn struct { diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 315bc68..0365a8b 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -4,12 +4,13 @@ import ( "bytes" "encoding/binary" "errors" - "github.com/cnlh/nps/lib/pool" "math" "net" "sync" "sync/atomic" "time" + + "github.com/cnlh/nps/lib/pool" ) const ( @@ -174,7 +175,7 @@ func (s *Mux) readSession() { case conn.getStatusCh <- struct{}{}: default: } - conn.hasWrite -- + conn.hasWrite-- case MUX_NEW_CONN_OK: //conn ok conn.connStatusOkCh <- struct{}{} case MUX_NEW_CONN_Fail: diff --git a/lib/mux/mux_test.go b/lib/mux/mux_test.go index 463291a..b89e4e9 100644 --- a/lib/mux/mux_test.go +++ b/lib/mux/mux_test.go @@ -1,15 +1,16 @@ package mux import ( - "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/pool" - "github.com/astaxie/beego/logs" "log" "net" "net/http" _ "net/http/pprof" "testing" "time" + + "github.com/astaxie/beego/logs" + "github.com/cnlh/nps/lib/common" + "github.com/cnlh/nps/lib/pool" ) var conn1 net.Conn diff --git a/lib/mux/pmux.go b/lib/mux/pmux.go index b750838..e593bb0 100644 --- a/lib/mux/pmux.go +++ b/lib/mux/pmux.go @@ -5,15 +5,16 @@ package mux import ( "bufio" "bytes" - "github.com/cnlh/nps/lib/common" - "github.com/astaxie/beego/logs" - "github.com/pkg/errors" "io" "net" "os" "strconv" "strings" "time" + + "github.com/astaxie/beego/logs" + "github.com/cnlh/nps/lib/common" + "github.com/pkg/errors" ) const ( diff --git a/lib/mux/pmux_test.go b/lib/mux/pmux_test.go index c3c0705..4c8e44e 100644 --- a/lib/mux/pmux_test.go +++ b/lib/mux/pmux_test.go @@ -1,9 +1,10 @@ package mux import ( - "github.com/astaxie/beego/logs" "testing" "time" + + "github.com/astaxie/beego/logs" ) func TestPortMux_Close(t *testing.T) { @@ -11,7 +12,7 @@ func TestPortMux_Close(t *testing.T) { logs.EnableFuncCallDepth(true) logs.SetLogFuncCallDepth(3) - pMux := NewPortMux(8888,"Ds") + pMux := NewPortMux(8888, "Ds") go func() { if pMux.Start() != nil { logs.Warn("Error") diff --git a/lib/mux/queue.go b/lib/mux/queue.go index f03bafd..9487845 100644 --- a/lib/mux/queue.go +++ b/lib/mux/queue.go @@ -2,8 +2,9 @@ package mux import ( "errors" - "github.com/cnlh/nps/lib/pool" "sync" + + "github.com/cnlh/nps/lib/pool" ) type Element *bufNode diff --git a/lib/pool/pool.go b/lib/pool/pool.go index 70e0477..ace8b07 100644 --- a/lib/pool/pool.go +++ b/lib/pool/pool.go @@ -36,6 +36,7 @@ var BufPoolCopy = sync.Pool{ return &buf }, } + func PutBufPoolUdp(buf []byte) { if cap(buf) == PoolSizeUdp { BufPoolUdp.Put(buf[:PoolSizeUdp]) @@ -48,7 +49,7 @@ func PutBufPoolCopy(buf []byte) { } } -func GetBufPoolCopy() ([]byte) { +func GetBufPoolCopy() []byte { return (*BufPoolCopy.Get().(*[]byte))[:PoolSizeCopy] } diff --git a/server/connection/connection.go b/server/connection/connection.go index 73eac1d..dbd74ca 100644 --- a/server/connection/connection.go +++ b/server/connection/connection.go @@ -1,12 +1,13 @@ package connection import ( - "github.com/cnlh/nps/lib/mux" - "github.com/astaxie/beego" - "github.com/astaxie/beego/logs" "net" "os" "strconv" + + "github.com/astaxie/beego" + "github.com/astaxie/beego/logs" + "github.com/cnlh/nps/lib/mux" ) var pMux *mux.PortMux diff --git a/server/proxy/base.go b/server/proxy/base.go index 68cce5b..93774f3 100644 --- a/server/proxy/base.go +++ b/server/proxy/base.go @@ -2,14 +2,15 @@ package proxy import ( "errors" + "net" + "net/http" + "sync" + + "github.com/astaxie/beego/logs" "github.com/cnlh/nps/bridge" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/file" - "github.com/astaxie/beego/logs" - "net" - "net/http" - "sync" ) type Service interface { diff --git a/server/proxy/http.go b/server/proxy/http.go index bf12060..31ec81c 100644 --- a/server/proxy/http.go +++ b/server/proxy/http.go @@ -3,13 +3,6 @@ package proxy import ( "bufio" "crypto/tls" - "github.com/cnlh/nps/bridge" - "github.com/cnlh/nps/lib/cache" - "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/conn" - "github.com/cnlh/nps/lib/file" - "github.com/cnlh/nps/server/connection" - "github.com/astaxie/beego/logs" "io" "net" "net/http" @@ -19,6 +12,14 @@ import ( "strconv" "strings" "sync" + + "github.com/astaxie/beego/logs" + "github.com/cnlh/nps/bridge" + "github.com/cnlh/nps/lib/cache" + "github.com/cnlh/nps/lib/common" + "github.com/cnlh/nps/lib/conn" + "github.com/cnlh/nps/lib/file" + "github.com/cnlh/nps/server/connection" ) type httpServer struct { diff --git a/server/proxy/https.go b/server/proxy/https.go index 997a851..303b92d 100644 --- a/server/proxy/https.go +++ b/server/proxy/https.go @@ -1,18 +1,19 @@ package proxy import ( + "net" + "net/http" + "net/url" + "sync" + + "github.com/astaxie/beego" + "github.com/astaxie/beego/logs" "github.com/cnlh/nps/lib/cache" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/crypt" "github.com/cnlh/nps/lib/file" - "github.com/astaxie/beego" - "github.com/astaxie/beego/logs" "github.com/pkg/errors" - "net" - "net/http" - "net/url" - "sync" ) type HttpsServer struct { diff --git a/server/proxy/p2p.go b/server/proxy/p2p.go index 470963f..dc6eb07 100644 --- a/server/proxy/p2p.go +++ b/server/proxy/p2p.go @@ -1,12 +1,13 @@ package proxy import ( - "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/pool" - "github.com/astaxie/beego/logs" "net" "strings" "time" + + "github.com/astaxie/beego/logs" + "github.com/cnlh/nps/lib/common" + "github.com/cnlh/nps/lib/pool" ) type P2PServer struct { diff --git a/server/proxy/socks5.go b/server/proxy/socks5.go index 2215734..2fe72c1 100755 --- a/server/proxy/socks5.go +++ b/server/proxy/socks5.go @@ -3,13 +3,14 @@ package proxy import ( "encoding/binary" "errors" - "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/conn" - "github.com/cnlh/nps/lib/file" - "github.com/astaxie/beego/logs" "io" "net" "strconv" + + "github.com/astaxie/beego/logs" + "github.com/cnlh/nps/lib/common" + "github.com/cnlh/nps/lib/conn" + "github.com/cnlh/nps/lib/file" ) const ( @@ -273,4 +274,4 @@ func NewSock5ModeServer(bridge NetBridge, task *file.Tunnel) *Sock5ModeServer { //close func (s *Sock5ModeServer) Close() error { return s.listener.Close() -} \ No newline at end of file +} diff --git a/server/proxy/transport.go b/server/proxy/transport.go index 364a7b8..d622683 100644 --- a/server/proxy/transport.go +++ b/server/proxy/transport.go @@ -3,11 +3,12 @@ package proxy import ( - "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/conn" "net" "strconv" "syscall" + + "github.com/cnlh/nps/lib/common" + "github.com/cnlh/nps/lib/conn" ) func HandleTrans(c *conn.Conn, s *TunnelModeServer) error { diff --git a/server/proxy/udp.go b/server/proxy/udp.go index 82f2cf2..d2bc130 100755 --- a/server/proxy/udp.go +++ b/server/proxy/udp.go @@ -1,14 +1,15 @@ package proxy import ( + "net" + "strings" + + "github.com/astaxie/beego/logs" "github.com/cnlh/nps/bridge" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/lib/pool" - "github.com/astaxie/beego/logs" - "net" - "strings" ) type UdpModeServer struct { diff --git a/server/server.go b/server/server.go index 2534f6e..5e72617 100644 --- a/server/server.go +++ b/server/server.go @@ -8,13 +8,13 @@ import ( "strings" "time" + "github.com/astaxie/beego" + "github.com/astaxie/beego/logs" "github.com/cnlh/nps/bridge" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/server/proxy" "github.com/cnlh/nps/server/tool" - "github.com/astaxie/beego" - "github.com/astaxie/beego/logs" "github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/load" "github.com/shirou/gopsutil/mem" diff --git a/server/test/test.go b/server/test/test.go index fbd8eb7..0a8fbfd 100644 --- a/server/test/test.go +++ b/server/test/test.go @@ -1,12 +1,13 @@ package test import ( - "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/file" - "github.com/astaxie/beego" "log" "path/filepath" "strconv" + + "github.com/astaxie/beego" + "github.com/cnlh/nps/lib/common" + "github.com/cnlh/nps/lib/file" ) func TestServerConfig() { diff --git a/server/tool/utils.go b/server/tool/utils.go index 9d801a6..6a58bab 100644 --- a/server/tool/utils.go +++ b/server/tool/utils.go @@ -1,15 +1,16 @@ package tool import ( - "github.com/cnlh/nps/lib/common" + "math" + "strconv" + "time" + "github.com/astaxie/beego" + "github.com/cnlh/nps/lib/common" "github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/load" "github.com/shirou/gopsutil/mem" "github.com/shirou/gopsutil/net" - "math" - "strconv" - "time" ) var ( diff --git a/web/controllers/auth.go b/web/controllers/auth.go index 5d8cac6..3b6b4c5 100644 --- a/web/controllers/auth.go +++ b/web/controllers/auth.go @@ -2,9 +2,10 @@ package controllers import ( "encoding/hex" - "github.com/cnlh/nps/lib/crypt" - "github.com/astaxie/beego" "time" + + "github.com/astaxie/beego" + "github.com/cnlh/nps/lib/crypt" ) type AuthController struct { diff --git a/web/controllers/base.go b/web/controllers/base.go index 089cee4..b608478 100755 --- a/web/controllers/base.go +++ b/web/controllers/base.go @@ -1,16 +1,17 @@ package controllers import ( - "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/crypt" - "github.com/cnlh/nps/lib/file" - "github.com/cnlh/nps/server" - "github.com/astaxie/beego" "html" "math" "strconv" "strings" "time" + + "github.com/astaxie/beego" + "github.com/cnlh/nps/lib/common" + "github.com/cnlh/nps/lib/crypt" + "github.com/cnlh/nps/lib/file" + "github.com/cnlh/nps/server" ) type BaseController struct { diff --git a/web/controllers/client.go b/web/controllers/client.go index ffe5f59..8a3ae31 100644 --- a/web/controllers/client.go +++ b/web/controllers/client.go @@ -1,11 +1,11 @@ package controllers import ( + "github.com/astaxie/beego" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/lib/rate" "github.com/cnlh/nps/server" - "github.com/astaxie/beego" ) type ClientController struct { diff --git a/web/controllers/login.go b/web/controllers/login.go index da40e64..c31e9a1 100755 --- a/web/controllers/login.go +++ b/web/controllers/login.go @@ -1,11 +1,12 @@ package controllers import ( + "time" + + "github.com/astaxie/beego" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/server" - "github.com/astaxie/beego" - "time" ) type LoginController struct { From 7178b3380720e910d283036a8d39879a94105515 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Fri, 16 Aug 2019 10:48:48 +0800 Subject: [PATCH 07/58] Change to 755, fixes #176 --- lib/install/install.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/install/install.go b/lib/install/install.go index 5b2a515..6bd20d4 100644 --- a/lib/install/install.go +++ b/lib/install/install.go @@ -33,11 +33,11 @@ func InstallNps() { if _, err := copyFile(filepath.Join(common.GetAppPath(), "nps"), "/usr/local/bin/nps"); err != nil { log.Fatalln(err) } else { - os.Chmod("/usr/local/bin/nps", 0777) + os.Chmod("/usr/local/bin/nps", 0755) log.Println("Executable files have been copied to", "/usr/local/bin/nps") } } else { - os.Chmod("/usr/bin/nps", 0777) + os.Chmod("/usr/bin/nps", 0755) log.Println("Executable files have been copied to", "/usr/bin/nps") } From fe79fe9fc73962928f1d0f16eb53e95c5abaa6d2 Mon Sep 17 00:00:00 2001 From: libotony Date: Mon, 19 Aug 2019 21:46:27 +0800 Subject: [PATCH 08/58] get real ip of http request --- web/controllers/login.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/controllers/login.go b/web/controllers/login.go index c31e9a1..64873a4 100755 --- a/web/controllers/login.go +++ b/web/controllers/login.go @@ -22,7 +22,7 @@ func (self *LoginController) Verify() { if self.GetString("password") == beego.AppConfig.String("web_password") && self.GetString("username") == beego.AppConfig.String("web_username") { self.SetSession("isAdmin", true) auth = true - server.Bridge.Register.Store(common.GetIpByAddr(self.Ctx.Request.RemoteAddr), time.Now().Add(time.Hour*time.Duration(2))) + server.Bridge.Register.Store(common.GetIpByAddr(self.Ctx.Input.IP()), time.Now().Add(time.Hour*time.Duration(2))) } b, err := beego.AppConfig.Bool("allow_user_login") if err == nil && b && !auth { From 3cc42341173ffabd3149cec35f8d1cf44c99742c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B2=B3?= Date: Wed, 21 Aug 2019 01:20:19 +0800 Subject: [PATCH 09/58] =?UTF-8?q?fix:=E7=AB=AF=E5=8F=A3=E8=8C=83=E5=9B=B4?= =?UTF-8?q?=E6=98=A0=E5=B0=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bridge/bridge.go | 1 + lib/config/config.go | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/bridge/bridge.go b/bridge/bridge.go index 53a2e76..3247dd8 100755 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -473,6 +473,7 @@ loop: tl.Remark = t.Remark } else { tl.Remark = t.Remark + "_" + strconv.Itoa(tl.Port) + tl.Target = new(file.Target) if t.TargetAddr != "" { tl.Target.TargetStr = t.TargetAddr + ":" + strconv.Itoa(targets[i]) } else { diff --git a/lib/config/config.go b/lib/config/config.go index c4d144e..c35afb7 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -227,8 +227,10 @@ func dealTunnel(s string) *file.Tunnel { t.ServerIp = item[1] case "mode": t.Mode = item[1] - case "target_port", "target_addr": + case "target_addr": t.Target.TargetStr = strings.Replace(item[1], ",", "\n", -1) + case "target_port": + t.Target.TargetStr = item[1] case "target_ip": t.TargetAddr = item[1] case "password": From 18c11f108b149527ef069b9833ff683aeb2b8f52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B2=B3?= Date: Wed, 21 Aug 2019 01:34:23 +0800 Subject: [PATCH 10/58] change version --- lib/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version/version.go b/lib/version/version.go index 01ab818..902b30b 100644 --- a/lib/version/version.go +++ b/lib/version/version.go @@ -1,6 +1,6 @@ package version -const VERSION = "0.23.1" +const VERSION = "0.23.2" // Compulsory minimum version, Minimum downward compatibility to this version func GetVersion() string { From 00900c13156af77cd8919168f67ad8662888c077 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Fri, 23 Aug 2019 18:53:36 +0800 Subject: [PATCH 11/58] mux test --- lib/common/const.go | 12 +++ lib/common/netpackager.go | 175 ++++++++++++++++++++++++++++++++++++ lib/mux/bytes.go | 2 +- lib/mux/conn.go | 42 ++++----- lib/mux/mux.go | 185 ++++++++++++++++++-------------------- lib/mux/mux_test.go | 4 +- lib/pool/pool.go | 32 ++++++- 7 files changed, 324 insertions(+), 128 deletions(-) create mode 100644 lib/common/netpackager.go diff --git a/lib/common/const.go b/lib/common/const.go index ffb2fa6..d77f16b 100644 --- a/lib/common/const.go +++ b/lib/common/const.go @@ -36,3 +36,15 @@ WWW-Authenticate: Basic realm="easyProxy" ` ) + +const ( + MUX_PING_FLAG uint8 = iota + MUX_NEW_CONN_OK + MUX_NEW_CONN_Fail + MUX_NEW_MSG + MUX_MSG_SEND_OK + MUX_NEW_CONN + MUX_CONN_CLOSE + MUX_PING_RETURN + MUX_PING int32 = -1 +) diff --git a/lib/common/netpackager.go b/lib/common/netpackager.go new file mode 100644 index 0000000..315f645 --- /dev/null +++ b/lib/common/netpackager.go @@ -0,0 +1,175 @@ +package common + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "github.com/cnlh/nps/lib/pool" + "io" + "strings" +) + +type NetPackager interface { + Pack(writer io.Writer) (err error) + UnPack(reader io.Reader) (err error) +} + +type BasePackager struct { + Length uint32 + Content []byte +} + +func (Self *BasePackager) NewPac(contents ...interface{}) (err error) { + Self.clean() + for _, content := range contents { + switch content.(type) { + case nil: + Self.Content = Self.Content[:0] + case []byte: + Self.Content = append(Self.Content, content.([]byte)...) + case string: + Self.Content = append(Self.Content, []byte(content.(string))...) + Self.Content = append(Self.Content, []byte(CONN_DATA_SEQ)...) + default: + err = Self.marshal(content) + } + } + Self.setLength() + return +} + +//似乎这里涉及到父类作用域问题,当子类调用父类的方法时,其struct仅仅为父类的 +func (Self *BasePackager) Pack(writer io.Writer) (err error) { + err = binary.Write(writer, binary.LittleEndian, Self.Length) + if err != nil { + return + } + err = binary.Write(writer, binary.LittleEndian, Self.Content) + //logs.Warn(Self.Length, string(Self.Content)) + return +} + +//Unpack 会导致传入的数字类型转化成float64!! +//主要原因是json unmarshal并未传入正确的数据类型 +func (Self *BasePackager) UnPack(reader io.Reader) (err error) { + err = binary.Read(reader, binary.LittleEndian, &Self.Length) + if err != nil { + return + } + Self.Content = pool.GetBufPoolCopy() + Self.Content = Self.Content[:Self.Length] + //n, err := io.ReadFull(reader, Self.Content) + //if n != int(Self.Length) { + // err = io.ErrUnexpectedEOF + //} + err = binary.Read(reader, binary.LittleEndian, &Self.Content) + return +} + +func (Self *BasePackager) marshal(content interface{}) (err error) { + tmp, err := json.Marshal(content) + if err != nil { + return err + } + Self.Content = append(Self.Content, tmp...) + return +} + +func (Self *BasePackager) Unmarshal(content interface{}) (err error) { + err = json.Unmarshal(Self.Content, content) + if err != nil { + return err + } + return +} + +func (Self *BasePackager) setLength() { + Self.Length = uint32(len(Self.Content)) + return +} + +func (Self *BasePackager) clean() { + Self.Length = 0 + Self.Content = Self.Content[:0] +} + +func (Self *BasePackager) Split() (strList []string) { + n := bytes.IndexByte(Self.Content, 0) + strList = strings.Split(string(Self.Content[:n]), CONN_DATA_SEQ) + strList = strList[0 : len(strList)-1] + return +} + +type ConnPackager struct { // Todo + ConnType uint8 + BasePackager +} + +func (Self *ConnPackager) NewPac(connType uint8, content ...interface{}) (err error) { + Self.ConnType = connType + err = Self.BasePackager.NewPac(content...) + return +} + +func (Self *ConnPackager) Pack(writer io.Writer) (err error) { + err = binary.Write(writer, binary.LittleEndian, Self.ConnType) + if err != nil { + return + } + err = Self.BasePackager.Pack(writer) + return +} + +func (Self *ConnPackager) UnPack(reader io.Reader) (err error) { + err = binary.Read(reader, binary.LittleEndian, &Self.ConnType) + if err != nil && err != io.EOF { + return + } + err = Self.BasePackager.UnPack(reader) + return +} + +type MuxPackager struct { + Flag uint8 + Id int32 + BasePackager +} + +func (Self *MuxPackager) NewPac(flag uint8, id int32, content ...interface{}) (err error) { + Self.Flag = flag + Self.Id = id + if flag == MUX_NEW_MSG { + err = Self.BasePackager.NewPac(content...) + } + return +} + +func (Self *MuxPackager) Pack(writer io.Writer) (err error) { + err = binary.Write(writer, binary.LittleEndian, Self.Flag) + if err != nil { + return + } + err = binary.Write(writer, binary.LittleEndian, Self.Id) + if err != nil { + return + } + if Self.Flag == MUX_NEW_MSG { + err = Self.BasePackager.Pack(writer) + } + return +} + +func (Self *MuxPackager) UnPack(reader io.Reader) (err error) { + err = binary.Read(reader, binary.LittleEndian, &Self.Flag) + if err != nil { + return + } + err = binary.Read(reader, binary.LittleEndian, &Self.Id) + if err != nil { + return + } + if Self.Flag == MUX_NEW_MSG { + err = Self.BasePackager.UnPack(reader) + } + return +} diff --git a/lib/mux/bytes.go b/lib/mux/bytes.go index a7e17f7..c44bad4 100644 --- a/lib/mux/bytes.go +++ b/lib/mux/bytes.go @@ -20,7 +20,7 @@ func WriteLenBytes(buf []byte, w io.Writer) (int, error) { //read bytes by length func ReadLenBytes(buf []byte, r io.Reader) (int, error) { - var l int32 + var l uint32 var err error if binary.Read(r, binary.LittleEndian, &l) != nil { return 0, err diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 9e66577..a14e98d 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -2,10 +2,11 @@ package mux import ( "errors" + "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/pool" + "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "io" "net" - "sync" "time" ) @@ -30,8 +31,6 @@ type conn struct { mux *Mux } -var connPool = sync.Pool{} - func NewConn(connId int32, mux *Mux) *conn { c := &conn{ readCh: make(chan struct{}), @@ -73,9 +72,15 @@ func (s *conn) Read(buf []byte) (n int, err error) { return 0, io.EOF } else { pool.PutBufPoolCopy(s.readBuffer) - s.readBuffer = node.val - s.endRead = node.l - s.startRead = 0 + if node.val == nil { + //close + s.Close() + logs.Warn("close from read msg ", s.connId) + } else { + s.readBuffer = node.val + s.endRead = node.l + s.startRead = 0 + } } } if len(buf) < s.endRead-s.startRead { @@ -84,12 +89,11 @@ func (s *conn) Read(buf []byte) (n int, err error) { } else { n = copy(buf, s.readBuffer[s.startRead:s.endRead]) s.startRead += n - s.mux.sendInfo(MUX_MSG_SEND_OK, s.connId, nil) } return } -func (s *conn) Write(buf []byte) (int, error) { +func (s *conn) Write(buf []byte) (n int, err error) { if s.isClose { return 0, errors.New("the conn has closed") } @@ -115,15 +119,11 @@ func (s *conn) write(buf []byte, ch chan struct{}) { start := 0 l := len(buf) for { - if s.hasWrite > 50 { - <-s.getStatusCh - } - s.hasWrite++ if l-start > pool.PoolSizeCopy { - s.mux.sendInfo(MUX_NEW_MSG, s.connId, buf[start:start+pool.PoolSizeCopy]) + s.mux.sendInfo(common.MUX_NEW_MSG, s.connId, buf[start:start+pool.PoolSizeCopy]) start += pool.PoolSizeCopy } else { - s.mux.sendInfo(MUX_NEW_MSG, s.connId, buf[start:l]) + s.mux.sendInfo(common.MUX_NEW_MSG, s.connId, buf[start:l]) break } } @@ -132,16 +132,7 @@ func (s *conn) write(buf []byte, ch chan struct{}) { func (s *conn) Close() error { if s.isClose { - return errors.New("the conn has closed") - } - times := 0 -retry: - if s.waitQueue.Size() > 0 && times < 600 { - time.Sleep(time.Millisecond * 100) - times++ - goto retry - } - if s.isClose { + logs.Warn("already closed", s.connId) return errors.New("the conn has closed") } s.isClose = true @@ -152,9 +143,8 @@ retry: s.waitQueue.Clear() s.mux.connMap.Delete(s.connId) if !s.mux.IsClose { - s.mux.sendInfo(MUX_CONN_CLOSE, s.connId, nil) + s.mux.sendInfo(common.MUX_CONN_CLOSE, s.connId, nil) } - connPool.Put(s) return nil } diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 315bc68..bfd82ff 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -1,10 +1,10 @@ package mux import ( - "bytes" - "encoding/binary" "errors" + "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/pool" + "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "math" "net" "sync" @@ -12,40 +12,30 @@ import ( "time" ) -const ( - MUX_PING_FLAG int32 = iota - MUX_NEW_CONN_OK - MUX_NEW_CONN_Fail - MUX_NEW_MSG - MUX_MSG_SEND_OK - MUX_NEW_CONN - MUX_PING - MUX_CONN_CLOSE - MUX_PING_RETURN -) - type Mux struct { net.Listener - conn net.Conn - connMap *connMap - newConnCh chan *conn - id int32 - closeChan chan struct{} - IsClose bool - pingOk int - connType string + conn net.Conn + connMap *connMap + newConnCh chan *conn + id int32 + closeChan chan struct{} + IsClose bool + pingOk int + connType string + writeQueue *sliceEntry sync.Mutex } func NewMux(c net.Conn, connType string) *Mux { m := &Mux{ - conn: c, - connMap: NewConnMap(), - id: 0, - closeChan: make(chan struct{}), - newConnCh: make(chan *conn), - IsClose: false, - connType: connType, + conn: c, + connMap: NewConnMap(), + id: 0, + closeChan: make(chan struct{}), + newConnCh: make(chan *conn), + IsClose: false, + connType: connType, + writeQueue: NewQueue(), } //read session by flag go m.readSession() @@ -61,7 +51,7 @@ func (s *Mux) NewConn() (*conn, error) { conn := NewConn(s.getId(), s) //it must be set before send s.connMap.Set(conn.connId, conn) - if err := s.sendInfo(MUX_NEW_CONN, conn.connId, nil); err != nil { + if err := s.sendInfo(common.MUX_NEW_CONN, conn.connId, nil); err != nil { return nil, err } //set a timer timeout 30 second @@ -91,19 +81,28 @@ func (s *Mux) Addr() net.Addr { return s.conn.LocalAddr() } -func (s *Mux) sendInfo(flag int32, id int32, content []byte) error { - raw := bytes.NewBuffer([]byte{}) - binary.Write(raw, binary.LittleEndian, flag) - binary.Write(raw, binary.LittleEndian, id) - if content != nil && len(content) > 0 { - binary.Write(raw, binary.LittleEndian, int32(len(content))) - binary.Write(raw, binary.LittleEndian, content) - } - if _, err := s.conn.Write(raw.Bytes()); err != nil { +func (s *Mux) sendInfo(flag uint8, id int32, content []byte) (err error) { + buf := pool.BuffPool.Get() + defer pool.BuffPool.Put(buf) + pack := common.MuxPackager{} + err = pack.NewPac(flag, id, content) + if err != nil { s.Close() - return err + logs.Warn("new pack err", err) + return } - return nil + err = pack.Pack(buf) + if err != nil { + s.Close() + logs.Warn("pack err", err) + return + } + _, err = buf.WriteTo(s.conn) + if err != nil { + s.Close() + logs.Warn("write err", err) + } + return } func (s *Mux) ping() { @@ -117,7 +116,7 @@ func (s *Mux) ping() { if (math.MaxInt32 - s.id) < 10000 { s.id = 0 } - if err := s.sendInfo(MUX_PING_FLAG, MUX_PING, nil); err != nil || (s.pingOk > 10 && s.connType == "kcp") { + if err := s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, nil); err != nil || (s.pingOk > 10 && s.connType == "kcp") { s.Close() break } @@ -130,65 +129,48 @@ func (s *Mux) ping() { } func (s *Mux) readSession() { - var buf []byte + var pack common.MuxPackager go func() { for { - var flag, i int32 - var n int - var err error - if binary.Read(s.conn, binary.LittleEndian, &flag) == nil { - if binary.Read(s.conn, binary.LittleEndian, &i) != nil { - break - } - s.pingOk = 0 - switch flag { - case MUX_NEW_CONN: //new conn - conn := NewConn(i, s) - s.connMap.Set(i, conn) //it has been set before send ok - s.newConnCh <- conn - s.sendInfo(MUX_NEW_CONN_OK, i, nil) - continue - case MUX_PING_FLAG: //ping - s.sendInfo(MUX_PING_RETURN, MUX_PING, nil) - continue - case MUX_PING_RETURN: - continue - case MUX_NEW_MSG: - buf = pool.GetBufPoolCopy() - if n, err = ReadLenBytes(buf, s.conn); err != nil { - break - } - } - if conn, ok := s.connMap.Get(i); ok && !conn.isClose { - switch flag { - case MUX_NEW_MSG: //new msg from remote conn - //insert wait queue - conn.waitQueue.Push(NewBufNode(buf, n)) - //judge len if >xxx ,send stop - if conn.readWait { - conn.readWait = false - conn.readCh <- struct{}{} - } - case MUX_MSG_SEND_OK: //the remote has read - select { - case conn.getStatusCh <- struct{}{}: - default: - } - conn.hasWrite -- - case MUX_NEW_CONN_OK: //conn ok - conn.connStatusOkCh <- struct{}{} - case MUX_NEW_CONN_Fail: - conn.connStatusFailCh <- struct{}{} - case MUX_CONN_CLOSE: //close the connection - go conn.Close() - s.connMap.Delete(i) - } - } else if flag == MUX_NEW_MSG { - pool.PutBufPoolCopy(buf) - } - } else { + if pack.UnPack(s.conn) != nil { break } + s.pingOk = 0 + switch pack.Flag { + case common.MUX_NEW_CONN: //new conn + logs.Warn("mux new conn", pack.Id) + conn := NewConn(pack.Id, s) + s.connMap.Set(pack.Id, conn) //it has been set before send ok + s.newConnCh <- conn + s.sendInfo(common.MUX_NEW_CONN_OK, pack.Id, nil) + continue + case common.MUX_PING_FLAG: //ping + s.sendInfo(common.MUX_PING_RETURN, common.MUX_PING, nil) + continue + case common.MUX_PING_RETURN: + continue + } + if conn, ok := s.connMap.Get(pack.Id); ok && !conn.isClose { + switch pack.Flag { + case common.MUX_NEW_MSG: //new msg from remote conn + //insert wait queue + conn.waitQueue.Push(NewBufNode(pack.Content, int(pack.Length))) + //judge len if >xxx ,send stop + if conn.readWait { + conn.readWait = false + conn.readCh <- struct{}{} + } + case common.MUX_NEW_CONN_OK: //conn ok + conn.connStatusOkCh <- struct{}{} + case common.MUX_NEW_CONN_Fail: + conn.connStatusFailCh <- struct{}{} + case common.MUX_CONN_CLOSE: //close the connection + conn.waitQueue.Push(NewBufNode(nil, 0)) + s.connMap.Delete(pack.Id) + } + } else if pack.Flag == common.MUX_NEW_MSG { + pool.PutBufPoolCopy(pack.Content) + } } s.Close() }() @@ -198,6 +180,7 @@ func (s *Mux) readSession() { } func (s *Mux) Close() error { + logs.Warn("close mux") if s.IsClose { return errors.New("the mux has closed") } @@ -214,6 +197,10 @@ func (s *Mux) Close() error { } //get new connId as unique flag -func (s *Mux) getId() int32 { - return atomic.AddInt32(&s.id, 1) +func (s *Mux) getId() (id int32) { + id = atomic.AddInt32(&s.id, 1) + if _, ok := s.connMap.Get(id); ok { + s.getId() + } + return } diff --git a/lib/mux/mux_test.go b/lib/mux/mux_test.go index f84e378..067e939 100644 --- a/lib/mux/mux_test.go +++ b/lib/mux/mux_test.go @@ -32,13 +32,14 @@ func TestNewMux(t *testing.T) { log.Fatalln(err) } go func(c net.Conn) { - c2, err := net.Dial("tcp", "127.0.0.1:8082") + c2, err := net.Dial("tcp", "127.0.0.1:80") if err != nil { log.Fatalln(err) } go common.CopyBuffer(c2, c) common.CopyBuffer(c, c2) c.Close() + //logs.Warn("close from out npc ") c2.Close() }(c) } @@ -64,6 +65,7 @@ func TestNewMux(t *testing.T) { common.CopyBuffer(conn, tmpCpnn) conn.Close() tmpCpnn.Close() + logs.Warn("close from out nps ", tmpCpnn.connId) }(conn) } }() diff --git a/lib/pool/pool.go b/lib/pool/pool.go index 70e0477..fb337a2 100644 --- a/lib/pool/pool.go +++ b/lib/pool/pool.go @@ -1,6 +1,7 @@ package pool import ( + "bytes" "sync" ) @@ -36,6 +37,7 @@ var BufPoolCopy = sync.Pool{ return &buf }, } + func PutBufPoolUdp(buf []byte) { if cap(buf) == PoolSizeUdp { BufPoolUdp.Put(buf[:PoolSizeUdp]) @@ -48,7 +50,7 @@ func PutBufPoolCopy(buf []byte) { } } -func GetBufPoolCopy() ([]byte) { +func GetBufPoolCopy() []byte { return (*BufPoolCopy.Get().(*[]byte))[:PoolSizeCopy] } @@ -57,3 +59,31 @@ func PutBufPoolMax(buf []byte) { BufPoolMax.Put(buf[:PoolSize]) } } + +type BufferPool struct { + pool sync.Pool +} + +func (Self *BufferPool) New() { + Self.pool = sync.Pool{ + New: func() interface{} { + return new(bytes.Buffer) + }, + } +} + +func (Self *BufferPool) Get() *bytes.Buffer { + return Self.pool.Get().(*bytes.Buffer) +} + +func (Self *BufferPool) Put(x *bytes.Buffer) { + x.Reset() + Self.pool.Put(x) +} + +var once = sync.Once{} +var BuffPool = BufferPool{} + +func init() { + once.Do(BuffPool.New) +} From f35a73f7347448c996a5bd7faa71024f901a4d9e Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Mon, 26 Aug 2019 18:47:23 +0800 Subject: [PATCH 12/58] mux test --- lib/common/netpackager.go | 2 +- lib/common/util.go | 3 +++ lib/mux/conn.go | 35 +++++++++++++++++++++------ lib/mux/mux.go | 51 ++++++++++++++++++++++++++++++++++----- lib/mux/mux_test.go | 20 +++++++++------ 5 files changed, 89 insertions(+), 22 deletions(-) diff --git a/lib/common/netpackager.go b/lib/common/netpackager.go index 315f645..8e91de8 100644 --- a/lib/common/netpackager.go +++ b/lib/common/netpackager.go @@ -45,13 +45,13 @@ func (Self *BasePackager) Pack(writer io.Writer) (err error) { return } err = binary.Write(writer, binary.LittleEndian, Self.Content) - //logs.Warn(Self.Length, string(Self.Content)) return } //Unpack 会导致传入的数字类型转化成float64!! //主要原因是json unmarshal并未传入正确的数据类型 func (Self *BasePackager) UnPack(reader io.Reader) (err error) { + Self.clean() err = binary.Read(reader, binary.LittleEndian, &Self.Length) if err != nil { return diff --git a/lib/common/util.go b/lib/common/util.go index ce4381d..ce2b896 100755 --- a/lib/common/util.go +++ b/lib/common/util.go @@ -6,6 +6,7 @@ import ( "encoding/binary" "github.com/cnlh/nps/lib/crypt" "github.com/cnlh/nps/lib/pool" + "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "html/template" "io" "io/ioutil" @@ -268,8 +269,10 @@ func CopyBuffer(dst io.Writer, src io.Reader) (written int64, err error) { defer pool.PutBufPoolCopy(buf) for { nr, er := src.Read(buf) + logs.Warn("read finish", nr, er) if nr > 0 { nw, ew := dst.Write(buf[0:nr]) + logs.Warn("write finish", nw, ew) if nw > 0 { written += int64(nw) } diff --git a/lib/mux/conn.go b/lib/mux/conn.go index a14e98d..cbaf935 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -22,11 +22,12 @@ type conn struct { endRead int //now end read readFlag bool readCh chan struct{} - waitQueue *sliceEntry + readQueue *sliceEntry stopWrite bool connId int32 isClose bool readWait bool + sendClose bool hasWrite int mux *Mux } @@ -37,7 +38,7 @@ func NewConn(connId int32, mux *Mux) *conn { getStatusCh: make(chan struct{}), connStatusOkCh: make(chan struct{}), connStatusFailCh: make(chan struct{}), - waitQueue: NewQueue(), + readQueue: NewQueue(), connId: connId, mux: mux, } @@ -45,11 +46,12 @@ func NewConn(connId int32, mux *Mux) *conn { } func (s *conn) Read(buf []byte) (n int, err error) { + logs.Warn("starting read ", s.connId) if s.isClose || buf == nil { return 0, errors.New("the conn has closed") } if s.endRead-s.startRead == 0 { //read finish or start - if s.waitQueue.Size() == 0 { + if s.readQueue.Size() == 0 { s.readWait = true if t := s.readTimeOut.Sub(time.Now()); t > 0 { timer := time.NewTimer(t) @@ -67,19 +69,22 @@ func (s *conn) Read(buf []byte) (n int, err error) { if s.isClose { //If the connection is closed instead of continuing command return 0, errors.New("the conn has closed") } - if node, err := s.waitQueue.Pop(); err != nil { + if node, err := s.readQueue.Pop(); err != nil { s.Close() return 0, io.EOF } else { pool.PutBufPoolCopy(s.readBuffer) if node.val == nil { //close + s.sendClose = true s.Close() logs.Warn("close from read msg ", s.connId) + return 0, io.EOF } else { s.readBuffer = node.val s.endRead = node.l s.startRead = 0 + logs.Warn("get a new data buffer ", s.connId) } } } @@ -90,10 +95,12 @@ func (s *conn) Read(buf []byte) (n int, err error) { n = copy(buf, s.readBuffer[s.startRead:s.endRead]) s.startRead += n } + logs.Warn("end read ", s.connId) return } func (s *conn) Write(buf []byte) (n int, err error) { + logs.Warn("trying write", s.connId) if s.isClose { return 0, errors.New("the conn has closed") } @@ -113,6 +120,7 @@ func (s *conn) Write(buf []byte) (n int, err error) { if s.isClose { return 0, io.EOF } + logs.Warn("write success ", s.connId) return len(buf), nil } func (s *conn) write(buf []byte, ch chan struct{}) { @@ -130,7 +138,8 @@ func (s *conn) write(buf []byte, ch chan struct{}) { ch <- struct{}{} } -func (s *conn) Close() error { +func (s *conn) Close() (err error) { + logs.Warn("start closing ", s.connId) if s.isClose { logs.Warn("already closed", s.connId) return errors.New("the conn has closed") @@ -140,12 +149,22 @@ func (s *conn) Close() error { if s.readWait { s.readCh <- struct{}{} } - s.waitQueue.Clear() + s.readQueue.Clear() s.mux.connMap.Delete(s.connId) if !s.mux.IsClose { - s.mux.sendInfo(common.MUX_CONN_CLOSE, s.connId, nil) + if !s.sendClose { + logs.Warn("start send closing msg", s.connId) + err = s.mux.sendInfo(common.MUX_CONN_CLOSE, s.connId, nil) + logs.Warn("send closing msg ok ", s.connId) + if err != nil { + logs.Warn(err) + return + } + } else { + logs.Warn("send mux conn close pass ", s.connId) + } } - return nil + return } func (s *conn) LocalAddr() net.Addr { diff --git a/lib/mux/mux.go b/lib/mux/mux.go index bfd82ff..c099d51 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -1,6 +1,7 @@ package mux import ( + "bytes" "errors" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/pool" @@ -22,7 +23,7 @@ type Mux struct { IsClose bool pingOk int connType string - writeQueue *sliceEntry + writeQueue chan *bytes.Buffer sync.Mutex } @@ -35,12 +36,13 @@ func NewMux(c net.Conn, connType string) *Mux { newConnCh: make(chan *conn), IsClose: false, connType: connType, - writeQueue: NewQueue(), + writeQueue: make(chan *bytes.Buffer, 20), } //read session by flag go m.readSession() //ping go m.ping() + //go m.writeSession() return m } @@ -82,8 +84,10 @@ func (s *Mux) Addr() net.Addr { } func (s *Mux) sendInfo(flag uint8, id int32, content []byte) (err error) { + if flag == common.MUX_NEW_MSG { + logs.Warn("trying write to mux new msg", id) + } buf := pool.BuffPool.Get() - defer pool.BuffPool.Put(buf) pack := common.MuxPackager{} err = pack.NewPac(flag, id, content) if err != nil { @@ -97,14 +101,39 @@ func (s *Mux) sendInfo(flag uint8, id int32, content []byte) (err error) { logs.Warn("pack err", err) return } + //s.writeQueue <- buf _, err = buf.WriteTo(s.conn) if err != nil { s.Close() logs.Warn("write err", err) } + pool.BuffPool.Put(buf) + if flag == common.MUX_CONN_CLOSE { + logs.Warn("write to mux conn close success", id) + } + if flag == common.MUX_NEW_MSG { + logs.Warn("write to mux new msg success", id) + } return } +func (s *Mux) writeSession() { + go func() { + for { + buf := <-s.writeQueue + l := buf.Len() + n, err := buf.WriteTo(s.conn) + pool.BuffPool.Put(buf) + if err != nil || int(n) != l { + logs.Warn("close from write to ", err, n, l) + s.Close() + break + } + } + }() + <-s.closeChan +} + func (s *Mux) ping() { go func() { ticker := time.NewTicker(time.Second * 1) @@ -138,7 +167,7 @@ func (s *Mux) readSession() { s.pingOk = 0 switch pack.Flag { case common.MUX_NEW_CONN: //new conn - logs.Warn("mux new conn", pack.Id) + //logs.Warn("mux new conn", pack.Id) conn := NewConn(pack.Id, s) s.connMap.Set(pack.Id, conn) //it has been set before send ok s.newConnCh <- conn @@ -151,22 +180,30 @@ func (s *Mux) readSession() { continue } if conn, ok := s.connMap.Get(pack.Id); ok && !conn.isClose { + logs.Warn("read session flag id", pack.Flag, pack.Id) switch pack.Flag { case common.MUX_NEW_MSG: //new msg from remote conn //insert wait queue - conn.waitQueue.Push(NewBufNode(pack.Content, int(pack.Length))) + conn.readQueue.Push(NewBufNode(pack.Content, int(pack.Length))) //judge len if >xxx ,send stop if conn.readWait { conn.readWait = false conn.readCh <- struct{}{} } + logs.Warn("push a read buffer ", conn.connId, pack.Id) case common.MUX_NEW_CONN_OK: //conn ok conn.connStatusOkCh <- struct{}{} case common.MUX_NEW_CONN_Fail: conn.connStatusFailCh <- struct{}{} case common.MUX_CONN_CLOSE: //close the connection - conn.waitQueue.Push(NewBufNode(nil, 0)) + conn.readQueue.Push(NewBufNode(nil, 0)) + if conn.readWait { + logs.Warn("close read wait", pack.Id) + conn.readWait = false + conn.readCh <- struct{}{} + } s.connMap.Delete(pack.Id) + logs.Warn("read session mux conn close finish", pack.Id) } } else if pack.Flag == common.MUX_NEW_MSG { pool.PutBufPoolCopy(pack.Content) @@ -192,6 +229,8 @@ func (s *Mux) Close() error { select { case s.closeChan <- struct{}{}: } + s.closeChan <- struct{}{} + close(s.writeQueue) close(s.newConnCh) return s.conn.Close() } diff --git a/lib/mux/mux_test.go b/lib/mux/mux_test.go index 067e939..5b571d0 100644 --- a/lib/mux/mux_test.go +++ b/lib/mux/mux_test.go @@ -26,22 +26,25 @@ func TestNewMux(t *testing.T) { time.Sleep(time.Second * 3) go func() { m2 := NewMux(conn2, "tcp") + connCh := make(chan bool, 1) for { c, err := m2.Accept() if err != nil { log.Fatalln(err) } - go func(c net.Conn) { + connCh <- true + go func(c net.Conn, ch chan bool) { c2, err := net.Dial("tcp", "127.0.0.1:80") if err != nil { log.Fatalln(err) } go common.CopyBuffer(c2, c) common.CopyBuffer(c, c2) - c.Close() - //logs.Warn("close from out npc ") c2.Close() - }(c) + c.Close() + logs.Warn("close npc") + <-ch + }(c, connCh) } }() @@ -51,12 +54,14 @@ func TestNewMux(t *testing.T) { if err != nil { log.Fatalln(err) } + connCh := make(chan bool, 1) for { conn, err := l.Accept() if err != nil { log.Fatalln(err) } - go func(conn net.Conn) { + connCh <- true + go func(conn net.Conn, ch chan bool) { tmpCpnn, err := m1.NewConn() if err != nil { log.Fatalln(err) @@ -64,9 +69,10 @@ func TestNewMux(t *testing.T) { go common.CopyBuffer(tmpCpnn, conn) common.CopyBuffer(conn, tmpCpnn) conn.Close() - tmpCpnn.Close() + //tmpCpnn.Close() logs.Warn("close from out nps ", tmpCpnn.connId) - }(conn) + <-ch + }(conn, connCh) } }() From 4bb7e33b16688539e230e77467fa8dc99ee35e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B2=B3?= Date: Mon, 26 Aug 2019 21:42:20 +0800 Subject: [PATCH 13/58] no message --- lib/common/netpackager.go | 1 + lib/common/util.go | 5 ++-- lib/mux/conn.go | 12 +--------- lib/mux/mux.go | 11 ++++----- lib/mux/mux_test.go | 48 ++++++++++++++++----------------------- lib/pool/pool.go | 7 +++--- 6 files changed, 32 insertions(+), 52 deletions(-) diff --git a/lib/common/netpackager.go b/lib/common/netpackager.go index 8e91de8..1252710 100644 --- a/lib/common/netpackager.go +++ b/lib/common/netpackager.go @@ -160,6 +160,7 @@ func (Self *MuxPackager) Pack(writer io.Writer) (err error) { } func (Self *MuxPackager) UnPack(reader io.Reader) (err error) { + Self.Length=0 err = binary.Read(reader, binary.LittleEndian, &Self.Flag) if err != nil { return diff --git a/lib/common/util.go b/lib/common/util.go index ce2b896..812c543 100755 --- a/lib/common/util.go +++ b/lib/common/util.go @@ -264,15 +264,14 @@ func GetPortByAddr(addr string) int { return p } -func CopyBuffer(dst io.Writer, src io.Reader) (written int64, err error) { +func CopyBuffer(dst io.Writer, src io.Reader,connId int32) (written int64, err error) { buf := pool.GetBufPoolCopy() defer pool.PutBufPoolCopy(buf) for { nr, er := src.Read(buf) - logs.Warn("read finish", nr, er) if nr > 0 { + logs.Warn("write",connId, nr, string(buf[0:10])) nw, ew := dst.Write(buf[0:nr]) - logs.Warn("write finish", nw, ew) if nw > 0 { written += int64(nw) } diff --git a/lib/mux/conn.go b/lib/mux/conn.go index cbaf935..6c6ab95 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -46,7 +46,6 @@ func NewConn(connId int32, mux *Mux) *conn { } func (s *conn) Read(buf []byte) (n int, err error) { - logs.Warn("starting read ", s.connId) if s.isClose || buf == nil { return 0, errors.New("the conn has closed") } @@ -73,18 +72,16 @@ func (s *conn) Read(buf []byte) (n int, err error) { s.Close() return 0, io.EOF } else { - pool.PutBufPoolCopy(s.readBuffer) + //pool.PutBufPoolCopy(s.readBuffer) if node.val == nil { //close s.sendClose = true s.Close() - logs.Warn("close from read msg ", s.connId) return 0, io.EOF } else { s.readBuffer = node.val s.endRead = node.l s.startRead = 0 - logs.Warn("get a new data buffer ", s.connId) } } } @@ -95,12 +92,10 @@ func (s *conn) Read(buf []byte) (n int, err error) { n = copy(buf, s.readBuffer[s.startRead:s.endRead]) s.startRead += n } - logs.Warn("end read ", s.connId) return } func (s *conn) Write(buf []byte) (n int, err error) { - logs.Warn("trying write", s.connId) if s.isClose { return 0, errors.New("the conn has closed") } @@ -120,7 +115,6 @@ func (s *conn) Write(buf []byte) (n int, err error) { if s.isClose { return 0, io.EOF } - logs.Warn("write success ", s.connId) return len(buf), nil } func (s *conn) write(buf []byte, ch chan struct{}) { @@ -139,9 +133,7 @@ func (s *conn) write(buf []byte, ch chan struct{}) { } func (s *conn) Close() (err error) { - logs.Warn("start closing ", s.connId) if s.isClose { - logs.Warn("already closed", s.connId) return errors.New("the conn has closed") } s.isClose = true @@ -153,7 +145,6 @@ func (s *conn) Close() (err error) { s.mux.connMap.Delete(s.connId) if !s.mux.IsClose { if !s.sendClose { - logs.Warn("start send closing msg", s.connId) err = s.mux.sendInfo(common.MUX_CONN_CLOSE, s.connId, nil) logs.Warn("send closing msg ok ", s.connId) if err != nil { @@ -161,7 +152,6 @@ func (s *conn) Close() (err error) { return } } else { - logs.Warn("send mux conn close pass ", s.connId) } } return diff --git a/lib/mux/mux.go b/lib/mux/mux.go index c099d51..e6daae7 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -85,7 +85,6 @@ func (s *Mux) Addr() net.Addr { func (s *Mux) sendInfo(flag uint8, id int32, content []byte) (err error) { if flag == common.MUX_NEW_MSG { - logs.Warn("trying write to mux new msg", id) } buf := pool.BuffPool.Get() pack := common.MuxPackager{} @@ -109,10 +108,8 @@ func (s *Mux) sendInfo(flag uint8, id int32, content []byte) (err error) { } pool.BuffPool.Put(buf) if flag == common.MUX_CONN_CLOSE { - logs.Warn("write to mux conn close success", id) } if flag == common.MUX_NEW_MSG { - logs.Warn("write to mux new msg success", id) } return } @@ -164,6 +161,11 @@ func (s *Mux) readSession() { if pack.UnPack(s.conn) != nil { break } + if pack.Flag != 0 && pack.Flag != 7 { + if pack.Length>10 { + logs.Warn(pack.Flag, pack.Id, pack.Length,string(pack.Content[:10])) + } + } s.pingOk = 0 switch pack.Flag { case common.MUX_NEW_CONN: //new conn @@ -180,7 +182,6 @@ func (s *Mux) readSession() { continue } if conn, ok := s.connMap.Get(pack.Id); ok && !conn.isClose { - logs.Warn("read session flag id", pack.Flag, pack.Id) switch pack.Flag { case common.MUX_NEW_MSG: //new msg from remote conn //insert wait queue @@ -190,7 +191,6 @@ func (s *Mux) readSession() { conn.readWait = false conn.readCh <- struct{}{} } - logs.Warn("push a read buffer ", conn.connId, pack.Id) case common.MUX_NEW_CONN_OK: //conn ok conn.connStatusOkCh <- struct{}{} case common.MUX_NEW_CONN_Fail: @@ -203,7 +203,6 @@ func (s *Mux) readSession() { conn.readCh <- struct{}{} } s.connMap.Delete(pack.Id) - logs.Warn("read session mux conn close finish", pack.Id) } } else if pack.Flag == common.MUX_NEW_MSG { pool.PutBufPoolCopy(pack.Content) diff --git a/lib/mux/mux_test.go b/lib/mux/mux_test.go index 5b571d0..2d3d2d0 100644 --- a/lib/mux/mux_test.go +++ b/lib/mux/mux_test.go @@ -26,25 +26,20 @@ func TestNewMux(t *testing.T) { time.Sleep(time.Second * 3) go func() { m2 := NewMux(conn2, "tcp") - connCh := make(chan bool, 1) for { c, err := m2.Accept() if err != nil { log.Fatalln(err) } - connCh <- true - go func(c net.Conn, ch chan bool) { - c2, err := net.Dial("tcp", "127.0.0.1:80") - if err != nil { - log.Fatalln(err) - } - go common.CopyBuffer(c2, c) - common.CopyBuffer(c, c2) - c2.Close() - c.Close() - logs.Warn("close npc") - <-ch - }(c, connCh) + c2, err := net.Dial("tcp", "127.0.0.1:8080") + if err != nil { + log.Fatalln(err) + } + go common.CopyBuffer(c2, c,0) + common.CopyBuffer(c, c2,0) + c2.Close() + c.Close() + logs.Warn("close npc") } }() @@ -54,25 +49,22 @@ func TestNewMux(t *testing.T) { if err != nil { log.Fatalln(err) } - connCh := make(chan bool, 1) for { conn, err := l.Accept() if err != nil { log.Fatalln(err) } - connCh <- true - go func(conn net.Conn, ch chan bool) { - tmpCpnn, err := m1.NewConn() - if err != nil { - log.Fatalln(err) - } - go common.CopyBuffer(tmpCpnn, conn) - common.CopyBuffer(conn, tmpCpnn) - conn.Close() - //tmpCpnn.Close() - logs.Warn("close from out nps ", tmpCpnn.connId) - <-ch - }(conn, connCh) + + tmpCpnn, err := m1.NewConn() + if err != nil { + log.Fatalln(err) + } + go common.CopyBuffer(tmpCpnn, conn,tmpCpnn.connId) + _, err = common.CopyBuffer(conn, tmpCpnn,tmpCpnn.connId) + logs.Warn(err, tmpCpnn.connId) + conn.Close() + tmpCpnn.Close() + logs.Warn("close from out nps ", tmpCpnn.connId) } }() diff --git a/lib/pool/pool.go b/lib/pool/pool.go index fb337a2..e491a5e 100644 --- a/lib/pool/pool.go +++ b/lib/pool/pool.go @@ -33,8 +33,7 @@ var BufPoolSmall = sync.Pool{ } var BufPoolCopy = sync.Pool{ New: func() interface{} { - buf := make([]byte, PoolSizeCopy) - return &buf + return make([]byte, PoolSizeCopy) }, } @@ -46,12 +45,12 @@ func PutBufPoolUdp(buf []byte) { func PutBufPoolCopy(buf []byte) { if cap(buf) == PoolSizeCopy { - BufPoolCopy.Put(&buf) + BufPoolCopy.Put(buf[:PoolSizeCopy]) } } func GetBufPoolCopy() []byte { - return (*BufPoolCopy.Get().(*[]byte))[:PoolSizeCopy] + return (BufPoolCopy.Get().([]byte))[:PoolSizeCopy] } func PutBufPoolMax(buf []byte) { From 53c2e472ae5dd79b86c3584ca11e13dfeb3ab1de Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Mon, 26 Aug 2019 23:29:22 +0800 Subject: [PATCH 14/58] Change BuffSizeCopy pool --- lib/common/netpackager.go | 8 +++++--- lib/mux/conn.go | 4 ++-- lib/mux/mux.go | 6 +++--- lib/mux/queue.go | 2 +- lib/pool/pool.go | 29 ++++++++++++++++++++++++++++- 5 files changed, 39 insertions(+), 10 deletions(-) diff --git a/lib/common/netpackager.go b/lib/common/netpackager.go index 1252710..abaff31 100644 --- a/lib/common/netpackager.go +++ b/lib/common/netpackager.go @@ -20,6 +20,7 @@ type BasePackager struct { } func (Self *BasePackager) NewPac(contents ...interface{}) (err error) { + Self.Content = pool.CopyBuff.Get() Self.clean() for _, content := range contents { switch content.(type) { @@ -45,6 +46,7 @@ func (Self *BasePackager) Pack(writer io.Writer) (err error) { return } err = binary.Write(writer, binary.LittleEndian, Self.Content) + pool.CopyBuff.Put(Self.Content) return } @@ -56,13 +58,13 @@ func (Self *BasePackager) UnPack(reader io.Reader) (err error) { if err != nil { return } - Self.Content = pool.GetBufPoolCopy() + Self.Content = pool.CopyBuff.Get() Self.Content = Self.Content[:Self.Length] //n, err := io.ReadFull(reader, Self.Content) //if n != int(Self.Length) { // err = io.ErrUnexpectedEOF //} - err = binary.Read(reader, binary.LittleEndian, &Self.Content) + err = binary.Read(reader, binary.LittleEndian, Self.Content) return } @@ -160,7 +162,7 @@ func (Self *MuxPackager) Pack(writer io.Writer) (err error) { } func (Self *MuxPackager) UnPack(reader io.Reader) (err error) { - Self.Length=0 + Self.Length = 0 err = binary.Read(reader, binary.LittleEndian, &Self.Flag) if err != nil { return diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 6c6ab95..d30bedc 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -72,7 +72,6 @@ func (s *conn) Read(buf []byte) (n int, err error) { s.Close() return 0, io.EOF } else { - //pool.PutBufPoolCopy(s.readBuffer) if node.val == nil { //close s.sendClose = true @@ -91,6 +90,7 @@ func (s *conn) Read(buf []byte) (n int, err error) { } else { n = copy(buf, s.readBuffer[s.startRead:s.endRead]) s.startRead += n + pool.CopyBuff.Put(s.readBuffer) } return } @@ -137,7 +137,7 @@ func (s *conn) Close() (err error) { return errors.New("the conn has closed") } s.isClose = true - pool.PutBufPoolCopy(s.readBuffer) + pool.CopyBuff.Put(s.readBuffer) if s.readWait { s.readCh <- struct{}{} } diff --git a/lib/mux/mux.go b/lib/mux/mux.go index e6daae7..2073593 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -162,8 +162,8 @@ func (s *Mux) readSession() { break } if pack.Flag != 0 && pack.Flag != 7 { - if pack.Length>10 { - logs.Warn(pack.Flag, pack.Id, pack.Length,string(pack.Content[:10])) + if pack.Length > 10 { + logs.Warn(pack.Flag, pack.Id, pack.Length, string(pack.Content[:10])) } } s.pingOk = 0 @@ -205,7 +205,7 @@ func (s *Mux) readSession() { s.connMap.Delete(pack.Id) } } else if pack.Flag == common.MUX_NEW_MSG { - pool.PutBufPoolCopy(pack.Content) + pool.CopyBuff.Put(pack.Content) } } s.Close() diff --git a/lib/mux/queue.go b/lib/mux/queue.go index f03bafd..6a14a8d 100644 --- a/lib/mux/queue.go +++ b/lib/mux/queue.go @@ -63,7 +63,7 @@ func (entry *sliceEntry) Clear() bool { return false } for i := 0; i < entry.Size(); i++ { - pool.PutBufPoolCopy(entry.element[i].val) + pool.CopyBuff.Put(entry.element[i].val) entry.element[i] = nil } entry.element = nil diff --git a/lib/pool/pool.go b/lib/pool/pool.go index e491a5e..26a91f5 100644 --- a/lib/pool/pool.go +++ b/lib/pool/pool.go @@ -59,6 +59,27 @@ func PutBufPoolMax(buf []byte) { } } +type CopyBufferPool struct { + pool sync.Pool +} + +func (Self *CopyBufferPool) New() { + Self.pool = sync.Pool{ + New: func() interface{} { + return make([]byte, PoolSizeCopy) + }, + } +} + +func (Self *CopyBufferPool) Get() []byte { + return Self.pool.Get().([]byte) +} + +func (Self *CopyBufferPool) Put(x []byte) { + x = x[:0] + Self.pool.Put(x) +} + type BufferPool struct { pool sync.Pool } @@ -82,7 +103,13 @@ func (Self *BufferPool) Put(x *bytes.Buffer) { var once = sync.Once{} var BuffPool = BufferPool{} +var CopyBuff = CopyBufferPool{} + +func newPool() { + BuffPool.New() + CopyBuff.New() +} func init() { - once.Do(BuffPool.New) + once.Do(newPool) } From 41c282b38bef8553c7d12c9eef321887042159e9 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Tue, 27 Aug 2019 20:07:37 +0800 Subject: [PATCH 15/58] fix buffer size bug --- lib/common/netpackager.go | 28 +++++++++++++++++++++------- lib/common/util.go | 20 ++++++++++---------- lib/mux/mux.go | 2 +- lib/pool/pool.go | 5 +++-- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/lib/common/netpackager.go b/lib/common/netpackager.go index abaff31..2d589aa 100644 --- a/lib/common/netpackager.go +++ b/lib/common/netpackager.go @@ -27,10 +27,13 @@ func (Self *BasePackager) NewPac(contents ...interface{}) (err error) { case nil: Self.Content = Self.Content[:0] case []byte: - Self.Content = append(Self.Content, content.([]byte)...) + err = Self.appendByte(content.([]byte)) case string: - Self.Content = append(Self.Content, []byte(content.(string))...) - Self.Content = append(Self.Content, []byte(CONN_DATA_SEQ)...) + err = Self.appendByte([]byte(content.(string))) + if err != nil { + return + } + err = Self.appendByte([]byte(CONN_DATA_SEQ)) default: err = Self.marshal(content) } @@ -39,6 +42,18 @@ func (Self *BasePackager) NewPac(contents ...interface{}) (err error) { return } +func (Self *BasePackager) appendByte(data []byte) (err error) { + m := len(Self.Content) + n := m + len(data) + if n <= cap(Self.Content) { + Self.Content = Self.Content[0:n] // grow the length for copy + copy(Self.Content[m:n], data) + return nil + } else { + return bytes.ErrTooLarge + } +} + //似乎这里涉及到父类作用域问题,当子类调用父类的方法时,其struct仅仅为父类的 func (Self *BasePackager) Pack(writer io.Writer) (err error) { err = binary.Write(writer, binary.LittleEndian, Self.Length) @@ -53,12 +68,12 @@ func (Self *BasePackager) Pack(writer io.Writer) (err error) { //Unpack 会导致传入的数字类型转化成float64!! //主要原因是json unmarshal并未传入正确的数据类型 func (Self *BasePackager) UnPack(reader io.Reader) (err error) { + Self.Content = pool.CopyBuff.Get() Self.clean() err = binary.Read(reader, binary.LittleEndian, &Self.Length) if err != nil { return } - Self.Content = pool.CopyBuff.Get() Self.Content = Self.Content[:Self.Length] //n, err := io.ReadFull(reader, Self.Content) //if n != int(Self.Length) { @@ -73,7 +88,7 @@ func (Self *BasePackager) marshal(content interface{}) (err error) { if err != nil { return err } - Self.Content = append(Self.Content, tmp...) + err = Self.appendByte(tmp) return } @@ -92,7 +107,7 @@ func (Self *BasePackager) setLength() { func (Self *BasePackager) clean() { Self.Length = 0 - Self.Content = Self.Content[:0] + Self.Content = Self.Content[:0] // reset length } func (Self *BasePackager) Split() (strList []string) { @@ -162,7 +177,6 @@ func (Self *MuxPackager) Pack(writer io.Writer) (err error) { } func (Self *MuxPackager) UnPack(reader io.Reader) (err error) { - Self.Length = 0 err = binary.Read(reader, binary.LittleEndian, &Self.Flag) if err != nil { return diff --git a/lib/common/util.go b/lib/common/util.go index 812c543..25cfee2 100755 --- a/lib/common/util.go +++ b/lib/common/util.go @@ -264,13 +264,19 @@ func GetPortByAddr(addr string) int { return p } -func CopyBuffer(dst io.Writer, src io.Reader,connId int32) (written int64, err error) { - buf := pool.GetBufPoolCopy() - defer pool.PutBufPoolCopy(buf) +func CopyBuffer(dst io.Writer, src io.Reader, connId int32) (written int64, err error) { + buf := pool.CopyBuff.Get() + defer pool.CopyBuff.Put(buf) for { nr, er := src.Read(buf) + if er != nil { + if er != io.EOF { + err = er + } + break + } if nr > 0 { - logs.Warn("write",connId, nr, string(buf[0:10])) + logs.Warn("write", connId, nr, string(buf[0:10])) nw, ew := dst.Write(buf[0:nr]) if nw > 0 { written += int64(nw) @@ -284,12 +290,6 @@ func CopyBuffer(dst io.Writer, src io.Reader,connId int32) (written int64, err e break } } - if er != nil { - if er != io.EOF { - err = er - } - break - } } return written, err } diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 2073593..ad17cb0 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -228,7 +228,7 @@ func (s *Mux) Close() error { select { case s.closeChan <- struct{}{}: } - s.closeChan <- struct{}{} + //s.closeChan <- struct{}{} close(s.writeQueue) close(s.newConnCh) return s.conn.Close() diff --git a/lib/pool/pool.go b/lib/pool/pool.go index 26a91f5..0540a9d 100644 --- a/lib/pool/pool.go +++ b/lib/pool/pool.go @@ -66,13 +66,14 @@ type CopyBufferPool struct { func (Self *CopyBufferPool) New() { Self.pool = sync.Pool{ New: func() interface{} { - return make([]byte, PoolSizeCopy) + return make([]byte, PoolSizeCopy, PoolSizeCopy) }, } } func (Self *CopyBufferPool) Get() []byte { - return Self.pool.Get().([]byte) + buf := Self.pool.Get().([]byte) + return buf[:cap(buf)] // grow to capacity } func (Self *CopyBufferPool) Put(x []byte) { From bb2cffe10a1f296337f3b72643dea5631ddc2789 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Fri, 30 Aug 2019 20:05:09 +0800 Subject: [PATCH 16/58] Change pool, change mux connection close ,change copy buffer --- lib/common/netpackager.go | 16 +++-- lib/{pool => common}/pool.go | 38 ++++++++++-- lib/common/util.go | 114 +++++++++++++++++++++++++++-------- lib/conn/conn.go | 11 ++-- lib/conn/snappy.go | 6 +- lib/mux/conn.go | 42 +++++++------ lib/mux/mux.go | 74 ++++++++++++++--------- lib/mux/mux_test.go | 65 ++++++++++++-------- lib/mux/queue.go | 4 +- server/proxy/p2p.go | 3 +- server/proxy/udp.go | 7 +-- 11 files changed, 257 insertions(+), 123 deletions(-) rename lib/{pool => common}/pool.go (71%) diff --git a/lib/common/netpackager.go b/lib/common/netpackager.go index 2d589aa..6d67f44 100644 --- a/lib/common/netpackager.go +++ b/lib/common/netpackager.go @@ -4,7 +4,8 @@ import ( "bytes" "encoding/binary" "encoding/json" - "github.com/cnlh/nps/lib/pool" + "errors" + "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "io" "strings" ) @@ -20,7 +21,6 @@ type BasePackager struct { } func (Self *BasePackager) NewPac(contents ...interface{}) (err error) { - Self.Content = pool.CopyBuff.Get() Self.clean() for _, content := range contents { switch content.(type) { @@ -50,7 +50,8 @@ func (Self *BasePackager) appendByte(data []byte) (err error) { copy(Self.Content[m:n], data) return nil } else { - return bytes.ErrTooLarge + logs.Warn(len(data), len(Self.Content), cap(Self.Content)) + return errors.New("pack content too large") } } @@ -61,20 +62,22 @@ func (Self *BasePackager) Pack(writer io.Writer) (err error) { return } err = binary.Write(writer, binary.LittleEndian, Self.Content) - pool.CopyBuff.Put(Self.Content) return } //Unpack 会导致传入的数字类型转化成float64!! //主要原因是json unmarshal并未传入正确的数据类型 func (Self *BasePackager) UnPack(reader io.Reader) (err error) { - Self.Content = pool.CopyBuff.Get() Self.clean() err = binary.Read(reader, binary.LittleEndian, &Self.Length) if err != nil { return } - Self.Content = Self.Content[:Self.Length] + if int(Self.Length) > cap(Self.Content) { + logs.Warn("unpack", cap(Self.Content)) + err = errors.New("unpack err, content length too large") + } + Self.Content = Self.Content[:int(Self.Length)] //n, err := io.ReadFull(reader, Self.Content) //if n != int(Self.Length) { // err = io.ErrUnexpectedEOF @@ -177,6 +180,7 @@ func (Self *MuxPackager) Pack(writer io.Writer) (err error) { } func (Self *MuxPackager) UnPack(reader io.Reader) (err error) { + Self.BasePackager.clean() // also clean the content err = binary.Read(reader, binary.LittleEndian, &Self.Flag) if err != nil { return diff --git a/lib/pool/pool.go b/lib/common/pool.go similarity index 71% rename from lib/pool/pool.go rename to lib/common/pool.go index 0540a9d..205378d 100644 --- a/lib/pool/pool.go +++ b/lib/common/pool.go @@ -1,4 +1,4 @@ -package pool +package common import ( "bytes" @@ -73,12 +73,15 @@ func (Self *CopyBufferPool) New() { func (Self *CopyBufferPool) Get() []byte { buf := Self.pool.Get().([]byte) - return buf[:cap(buf)] // grow to capacity + return buf[:PoolSizeCopy] // just like make a new slice, but data may not be 0 } func (Self *CopyBufferPool) Put(x []byte) { - x = x[:0] - Self.pool.Put(x) + if len(x) == PoolSizeCopy { + Self.pool.Put(x) + } else { + x = nil // buf is not full, maybe truncated by gc in pool, not allowed + } } type BufferPool struct { @@ -102,13 +105,40 @@ func (Self *BufferPool) Put(x *bytes.Buffer) { Self.pool.Put(x) } +type MuxPackagerPool struct { + pool sync.Pool +} + +func (Self *MuxPackagerPool) New() { + Self.pool = sync.Pool{ + New: func() interface{} { + pack := MuxPackager{} + return &pack + }, + } +} + +func (Self *MuxPackagerPool) Get() *MuxPackager { + pack := Self.pool.Get().(*MuxPackager) + buf := CopyBuff.Get() + pack.Content = buf + return pack +} + +func (Self *MuxPackagerPool) Put(pack *MuxPackager) { + CopyBuff.Put(pack.Content) + Self.pool.Put(pack) +} + var once = sync.Once{} var BuffPool = BufferPool{} var CopyBuff = CopyBufferPool{} +var MuxPack = MuxPackagerPool{} func newPool() { BuffPool.New() CopyBuff.New() + MuxPack.New() } func init() { diff --git a/lib/common/util.go b/lib/common/util.go index 25cfee2..3b4369f 100755 --- a/lib/common/util.go +++ b/lib/common/util.go @@ -4,8 +4,8 @@ import ( "bytes" "encoding/base64" "encoding/binary" + "errors" "github.com/cnlh/nps/lib/crypt" - "github.com/cnlh/nps/lib/pool" "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "html/template" "io" @@ -264,34 +264,96 @@ func GetPortByAddr(addr string) int { return p } -func CopyBuffer(dst io.Writer, src io.Reader, connId int32) (written int64, err error) { - buf := pool.CopyBuff.Get() - defer pool.CopyBuff.Put(buf) - for { - nr, er := src.Read(buf) - if er != nil { - if er != io.EOF { - err = er - } - break +type ConnCopy struct { + dst net.Conn + src net.Conn + buf []byte + connId int32 +} + +func (Self *ConnCopy) New(dst net.Conn, src net.Conn, connId int32) { + Self.dst = dst + Self.src = src + Self.buf = CopyBuff.Get() + Self.connId = connId +} + +func (Self *ConnCopy) copyBufferOnce() (written int64, err error) { + nr, er := Self.src.Read(Self.buf) + if nr > 0 { + //logs.Warn("write", Self.connId, nr, string(buf[0:10])) + nw, ew := Self.dst.Write(Self.buf[0:nr]) + if nw > 0 { + written = int64(nw) } - if nr > 0 { - logs.Warn("write", connId, nr, string(buf[0:10])) - nw, ew := dst.Write(buf[0:nr]) - if nw > 0 { - written += int64(nw) - } - if ew != nil { - err = ew - break - } - if nr != nw { - err = io.ErrShortWrite - break - } + if ew != nil { + //logs.Warn("write err ew id nw", ew, Self.connId, nw) + err = ew + return + } + if nr != nw { + err = io.ErrShortWrite + return + } + if nw == 0 { + err = errors.New("io: write on closed pipe") + //logs.Warn("write buffer", err) + return } } - return written, err + if nr == 0 && er == nil { + err = errors.New("io: read on closed pipe") + //logs.Warn("read buffer", err) + return + } + if er != nil { + err = er + return + } + return +} + +func (Self *ConnCopy) copyBuffer() (written int64, err error) { + var write int64 + write, err = Self.copyBufferOnce() // first copy, if written is zero and err is io.EOF + // means conn already closed, so need to close all the conn + written += write + if err == io.EOF && written == 0 { + err = errors.New("io: read on closed pipe") + return + } else if err == io.EOF && written > 0 { + err = nil + return + } + for { + write, err = Self.copyBufferOnce() + written += write + if err != nil { + if err == io.EOF { + err = nil + } + return + } + } +} + +func (Self *ConnCopy) CopyConn() (written int64, err error) { + defer CopyBuff.Put(Self.buf) + if Self.dst != nil && Self.src != nil { + written, err = Self.copyBuffer() + } else { + return 0, errors.New("copy conn nil src or dst") + } + if err != nil { // copyBuffer do not return io.EOF ,close all conn + logs.Warn("close by copy conn ", Self.connId, err) + if Self.dst != nil { + Self.dst.Close() + } + if Self.src != nil { + Self.src.Close() + } + } + return } //send this ip forget to get a local udp port diff --git a/lib/conn/conn.go b/lib/conn/conn.go index 7b6e729..058b7d8 100755 --- a/lib/conn/conn.go +++ b/lib/conn/conn.go @@ -10,7 +10,6 @@ import ( "github.com/cnlh/nps/lib/crypt" "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/lib/mux" - "github.com/cnlh/nps/lib/pool" "github.com/cnlh/nps/lib/rate" "github.com/cnlh/nps/vender/github.com/xtaci/kcp" "io" @@ -158,8 +157,8 @@ func (s *Conn) SendHealthInfo(info, status string) (int, error) { //get health info from conn func (s *Conn) GetHealthInfo() (info string, status bool, err error) { var l int - buf := pool.BufPoolMax.Get().([]byte) - defer pool.PutBufPoolMax(buf) + buf := common.BufPoolMax.Get().([]byte) + defer common.PutBufPoolMax(buf) if l, err = s.GetLen(); err != nil { return } else if _, err = s.ReadLen(l, buf); err != nil { @@ -232,8 +231,8 @@ func (s *Conn) SendInfo(t interface{}, flag string) (int, error) { //get task info func (s *Conn) getInfo(t interface{}) (err error) { var l int - buf := pool.BufPoolMax.Get().([]byte) - defer pool.PutBufPoolMax(buf) + buf := common.BufPoolMax.Get().([]byte) + defer common.PutBufPoolMax(buf) if l, err = s.GetLen(); err != nil { return } else if _, err = s.ReadLen(l, buf); err != nil { @@ -373,7 +372,7 @@ func CopyWaitGroup(conn1, conn2 net.Conn, crypt bool, snappy bool, rate *rate.Ra } //get crypt or snappy conn -func GetConn(conn net.Conn, cpt, snappy bool, rt *rate.Rate, isServer bool) (io.ReadWriteCloser) { +func GetConn(conn net.Conn, cpt, snappy bool, rt *rate.Rate, isServer bool) io.ReadWriteCloser { if cpt { if isServer { return rate.NewRateConn(crypt.NewTlsServerConn(conn), rt) diff --git a/lib/conn/snappy.go b/lib/conn/snappy.go index cfd33c4..cda20b5 100644 --- a/lib/conn/snappy.go +++ b/lib/conn/snappy.go @@ -1,7 +1,7 @@ package conn import ( - "github.com/cnlh/nps/lib/pool" + "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/vender/github.com/golang/snappy" "io" ) @@ -31,8 +31,8 @@ func (s *SnappyConn) Write(b []byte) (n int, err error) { //snappy压缩读 func (s *SnappyConn) Read(b []byte) (n int, err error) { - buf := pool.BufPool.Get().([]byte) - defer pool.BufPool.Put(buf) + buf := common.BufPool.Get().([]byte) + defer common.BufPool.Put(buf) if n, err = s.r.Read(buf); err != nil { return } diff --git a/lib/mux/conn.go b/lib/mux/conn.go index d30bedc..7430454 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -3,7 +3,6 @@ package mux import ( "errors" "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/pool" "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "io" "net" @@ -27,7 +26,8 @@ type conn struct { connId int32 isClose bool readWait bool - sendClose bool + sendClose bool // MUX_CONN_CLOSE already send + writeClose bool // close conn Write hasWrite int mux *Mux } @@ -69,12 +69,14 @@ func (s *conn) Read(buf []byte) (n int, err error) { return 0, errors.New("the conn has closed") } if node, err := s.readQueue.Pop(); err != nil { + logs.Warn("conn close by read pop err", s.connId, err) s.Close() return 0, io.EOF } else { if node.val == nil { //close s.sendClose = true + logs.Warn("conn close by read ", s.connId) s.Close() return 0, io.EOF } else { @@ -90,7 +92,7 @@ func (s *conn) Read(buf []byte) (n int, err error) { } else { n = copy(buf, s.readBuffer[s.startRead:s.endRead]) s.startRead += n - pool.CopyBuff.Put(s.readBuffer) + common.CopyBuff.Put(s.readBuffer) } return } @@ -99,6 +101,12 @@ func (s *conn) Write(buf []byte) (n int, err error) { if s.isClose { return 0, errors.New("the conn has closed") } + if s.writeClose { + s.sendClose = true + logs.Warn("conn close by write ", s.connId) + s.Close() + return 0, errors.New("io: write on closed conn") + } ch := make(chan struct{}) go s.write(buf, ch) if t := s.writeTimeOut.Sub(time.Now()); t > 0 { @@ -112,19 +120,22 @@ func (s *conn) Write(buf []byte) (n int, err error) { } else { <-ch } - if s.isClose { - return 0, io.EOF - } + close(ch) + //if s.isClose { + // return 0, io.ErrClosedPipe + //} return len(buf), nil } func (s *conn) write(buf []byte, ch chan struct{}) { start := 0 l := len(buf) for { - if l-start > pool.PoolSizeCopy { - s.mux.sendInfo(common.MUX_NEW_MSG, s.connId, buf[start:start+pool.PoolSizeCopy]) - start += pool.PoolSizeCopy + if l-start > common.PoolSizeCopy { + logs.Warn("conn write > poolsizecopy") + s.mux.sendInfo(common.MUX_NEW_MSG, s.connId, buf[start:start+common.PoolSizeCopy]) + start += common.PoolSizeCopy } else { + logs.Warn("conn write <= poolsizecopy, start, len", start, l) s.mux.sendInfo(common.MUX_NEW_MSG, s.connId, buf[start:l]) break } @@ -137,21 +148,16 @@ func (s *conn) Close() (err error) { return errors.New("the conn has closed") } s.isClose = true - pool.CopyBuff.Put(s.readBuffer) + s.mux.connMap.Delete(s.connId) + common.CopyBuff.Put(s.readBuffer) if s.readWait { s.readCh <- struct{}{} } s.readQueue.Clear() - s.mux.connMap.Delete(s.connId) if !s.mux.IsClose { if !s.sendClose { - err = s.mux.sendInfo(common.MUX_CONN_CLOSE, s.connId, nil) - logs.Warn("send closing msg ok ", s.connId) - if err != nil { - logs.Warn(err) - return - } - } else { + logs.Warn("conn send close") + go s.mux.sendInfo(common.MUX_CONN_CLOSE, s.connId, nil) } } return diff --git a/lib/mux/mux.go b/lib/mux/mux.go index ad17cb0..c40427d 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -4,7 +4,6 @@ import ( "bytes" "errors" "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/pool" "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "math" "net" @@ -42,7 +41,7 @@ func NewMux(c net.Conn, connType string) *Mux { go m.readSession() //ping go m.ping() - //go m.writeSession() + go m.writeSession() return m } @@ -53,9 +52,8 @@ func (s *Mux) NewConn() (*conn, error) { conn := NewConn(s.getId(), s) //it must be set before send s.connMap.Set(conn.connId, conn) - if err := s.sendInfo(common.MUX_NEW_CONN, conn.connId, nil); err != nil { - return nil, err - } + s.sendInfo(common.MUX_NEW_CONN, conn.connId, nil) + logs.Warn("send mux new conn ", conn.connId) //set a timer timeout 30 second timer := time.NewTimer(time.Minute * 2) defer timer.Stop() @@ -83,34 +81,41 @@ func (s *Mux) Addr() net.Addr { return s.conn.LocalAddr() } -func (s *Mux) sendInfo(flag uint8, id int32, content []byte) (err error) { +func (s *Mux) sendInfo(flag uint8, id int32, content []byte) { + var err error if flag == common.MUX_NEW_MSG { + if len(content) == 0 { + logs.Warn("send info content is nil") + } } - buf := pool.BuffPool.Get() - pack := common.MuxPackager{} + buf := common.BuffPool.Get() + //defer pool.BuffPool.Put(buf) + pack := common.MuxPack.Get() err = pack.NewPac(flag, id, content) if err != nil { s.Close() logs.Warn("new pack err", err) + common.BuffPool.Put(buf) return } err = pack.Pack(buf) if err != nil { s.Close() logs.Warn("pack err", err) + common.BuffPool.Put(buf) return } - //s.writeQueue <- buf - _, err = buf.WriteTo(s.conn) - if err != nil { - s.Close() - logs.Warn("write err", err) - } - pool.BuffPool.Put(buf) - if flag == common.MUX_CONN_CLOSE { - } - if flag == common.MUX_NEW_MSG { - } + s.writeQueue <- buf + common.MuxPack.Put(pack) + //_, err = buf.WriteTo(s.conn) + //if err != nil { + // s.Close() + // logs.Warn("write err, close mux", err) + //} + //if flag == common.MUX_CONN_CLOSE { + //} + //if flag == common.MUX_NEW_MSG { + //} return } @@ -120,7 +125,7 @@ func (s *Mux) writeSession() { buf := <-s.writeQueue l := buf.Len() n, err := buf.WriteTo(s.conn) - pool.BuffPool.Put(buf) + common.BuffPool.Put(buf) if err != nil || int(n) != l { logs.Warn("close from write to ", err, n, l) s.Close() @@ -142,7 +147,9 @@ func (s *Mux) ping() { if (math.MaxInt32 - s.id) < 10000 { s.id = 0 } - if err := s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, nil); err != nil || (s.pingOk > 10 && s.connType == "kcp") { + //logs.Warn("send mux ping") + s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, nil) + if s.pingOk > 10 && s.connType == "kcp" { s.Close() break } @@ -155,28 +162,30 @@ func (s *Mux) ping() { } func (s *Mux) readSession() { - var pack common.MuxPackager go func() { for { + pack := common.MuxPack.Get() if pack.UnPack(s.conn) != nil { break } if pack.Flag != 0 && pack.Flag != 7 { if pack.Length > 10 { - logs.Warn(pack.Flag, pack.Id, pack.Length, string(pack.Content[:10])) + //logs.Warn(pack.Flag, pack.Id, pack.Length, string(pack.Content[:10])) } } s.pingOk = 0 switch pack.Flag { case common.MUX_NEW_CONN: //new conn - //logs.Warn("mux new conn", pack.Id) + logs.Warn("mux new conn", pack.Id) conn := NewConn(pack.Id, s) s.connMap.Set(pack.Id, conn) //it has been set before send ok s.newConnCh <- conn s.sendInfo(common.MUX_NEW_CONN_OK, pack.Id, nil) + logs.Warn("send mux new conn ok", pack.Id) continue case common.MUX_PING_FLAG: //ping - s.sendInfo(common.MUX_PING_RETURN, common.MUX_PING, nil) + //logs.Warn("send mux ping return") + go s.sendInfo(common.MUX_PING_RETURN, common.MUX_PING, nil) continue case common.MUX_PING_RETURN: continue @@ -185,6 +194,7 @@ func (s *Mux) readSession() { switch pack.Flag { case common.MUX_NEW_MSG: //new msg from remote conn //insert wait queue + logs.Warn("mux new msg ", pack.Id) conn.readQueue.Push(NewBufNode(pack.Content, int(pack.Length))) //judge len if >xxx ,send stop if conn.readWait { @@ -192,21 +202,29 @@ func (s *Mux) readSession() { conn.readCh <- struct{}{} } case common.MUX_NEW_CONN_OK: //conn ok + logs.Warn("mux new conn ok ", pack.Id) conn.connStatusOkCh <- struct{}{} case common.MUX_NEW_CONN_Fail: + logs.Warn("mux new conn fail", pack.Id) conn.connStatusFailCh <- struct{}{} case common.MUX_CONN_CLOSE: //close the connection + logs.Warn("mux conn close", pack.Id) + s.connMap.Delete(pack.Id) + conn.writeClose = true conn.readQueue.Push(NewBufNode(nil, 0)) if conn.readWait { logs.Warn("close read wait", pack.Id) conn.readWait = false conn.readCh <- struct{}{} } - s.connMap.Delete(pack.Id) + logs.Warn("receive mux conn close, finish", conn.connId) } } else if pack.Flag == common.MUX_NEW_MSG { - pool.CopyBuff.Put(pack.Content) + common.CopyBuff.Put(pack.Content) + } else if pack.Flag == common.MUX_CONN_CLOSE { + logs.Warn("mux conn close no id ", pack.Id) } + common.MuxPack.Put(pack) } s.Close() }() @@ -228,7 +246,7 @@ func (s *Mux) Close() error { select { case s.closeChan <- struct{}{}: } - //s.closeChan <- struct{}{} + s.closeChan <- struct{}{} close(s.writeQueue) close(s.newConnCh) return s.conn.Close() diff --git a/lib/mux/mux_test.go b/lib/mux/mux_test.go index 2d3d2d0..728dfa3 100644 --- a/lib/mux/mux_test.go +++ b/lib/mux/mux_test.go @@ -2,9 +2,7 @@ package mux import ( "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/pool" "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" - "log" "net" "net/http" _ "net/http/pprof" @@ -27,19 +25,29 @@ func TestNewMux(t *testing.T) { go func() { m2 := NewMux(conn2, "tcp") for { + logs.Warn("npc starting accept") c, err := m2.Accept() if err != nil { - log.Fatalln(err) + logs.Warn(err) + continue } - c2, err := net.Dial("tcp", "127.0.0.1:8080") + logs.Warn("npc accept success ") + c2, err := net.Dial("tcp", "127.0.0.1:80") if err != nil { - log.Fatalln(err) + logs.Warn(err) + continue + } + var npcToServer common.ConnCopy + npcToServer.New(c2, c, 0) + go npcToServer.CopyConn() + var serverToNpc common.ConnCopy + serverToNpc.New(c, c2, 10000) + _, err = serverToNpc.CopyConn() + if err == nil { + logs.Warn("close npc") + c2.Close() + c.Close() } - go common.CopyBuffer(c2, c,0) - common.CopyBuffer(c, c2,0) - c2.Close() - c.Close() - logs.Warn("close npc") } }() @@ -47,24 +55,33 @@ func TestNewMux(t *testing.T) { m1 := NewMux(conn1, "tcp") l, err := net.Listen("tcp", "127.0.0.1:7777") if err != nil { - log.Fatalln(err) + logs.Warn(err) } for { + logs.Warn("nps starting accept") conn, err := l.Accept() if err != nil { - log.Fatalln(err) + logs.Warn(err) + continue } - + logs.Warn("nps accept success starting new conn") tmpCpnn, err := m1.NewConn() if err != nil { - log.Fatalln(err) + logs.Warn("nps new conn err ", err) + continue + } + logs.Warn("nps new conn success ", tmpCpnn.connId) + var userToNps common.ConnCopy + userToNps.New(tmpCpnn, conn, tmpCpnn.connId) + go userToNps.CopyConn() + var npsToUser common.ConnCopy + npsToUser.New(conn, tmpCpnn, tmpCpnn.connId+10000) + _, err = npsToUser.CopyConn() + if err == nil { + logs.Warn("close from out nps ", tmpCpnn.connId) + conn.Close() + tmpCpnn.Close() } - go common.CopyBuffer(tmpCpnn, conn,tmpCpnn.connId) - _, err = common.CopyBuffer(conn, tmpCpnn,tmpCpnn.connId) - logs.Warn(err, tmpCpnn.connId) - conn.Close() - tmpCpnn.Close() - logs.Warn("close from out nps ", tmpCpnn.connId) } }() @@ -77,12 +94,12 @@ func server() { var err error l, err := net.Listen("tcp", "127.0.0.1:9999") if err != nil { - log.Fatalln(err) + logs.Warn(err) } go func() { conn1, err = l.Accept() if err != nil { - log.Fatalln(err) + logs.Warn(err) } }() return @@ -92,12 +109,12 @@ func client() { var err error conn2, err = net.Dial("tcp", "127.0.0.1:9999") if err != nil { - log.Fatalln(err) + logs.Warn(err) } } func TestNewConn(t *testing.T) { - buf := pool.GetBufPoolCopy() + buf := common.GetBufPoolCopy() logs.Warn(len(buf), cap(buf)) //b := pool.GetBufPoolCopy() //b[0] = 1 diff --git a/lib/mux/queue.go b/lib/mux/queue.go index 6a14a8d..4388fb6 100644 --- a/lib/mux/queue.go +++ b/lib/mux/queue.go @@ -2,7 +2,7 @@ package mux import ( "errors" - "github.com/cnlh/nps/lib/pool" + "github.com/cnlh/nps/lib/common" "sync" ) @@ -63,7 +63,7 @@ func (entry *sliceEntry) Clear() bool { return false } for i := 0; i < entry.Size(); i++ { - pool.CopyBuff.Put(entry.element[i].val) + common.CopyBuff.Put(entry.element[i].val) entry.element[i] = nil } entry.element = nil diff --git a/server/proxy/p2p.go b/server/proxy/p2p.go index 44cdea3..7c1d270 100644 --- a/server/proxy/p2p.go +++ b/server/proxy/p2p.go @@ -2,7 +2,6 @@ package proxy import ( "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/pool" "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "net" "strings" @@ -36,7 +35,7 @@ func (s *P2PServer) Start() error { return err } for { - buf := pool.BufPoolUdp.Get().([]byte) + buf := common.BufPoolUdp.Get().([]byte) n, addr, err := s.listener.ReadFromUDP(buf) if err != nil { if strings.Contains(err.Error(), "use of closed network connection") { diff --git a/server/proxy/udp.go b/server/proxy/udp.go index 62358a4..2f88155 100755 --- a/server/proxy/udp.go +++ b/server/proxy/udp.go @@ -5,7 +5,6 @@ import ( "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/file" - "github.com/cnlh/nps/lib/pool" "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "net" "strings" @@ -33,7 +32,7 @@ func (s *UdpModeServer) Start() error { if err != nil { return err } - buf := pool.BufPoolUdp.Get().([]byte) + buf := common.BufPoolUdp.Get().([]byte) for { n, addr, err := s.listener.ReadFromUDP(buf) if err != nil { @@ -59,8 +58,8 @@ func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) { return } else { s.task.Flow.Add(int64(len(data)), 0) - buf := pool.BufPoolUdp.Get().([]byte) - defer pool.BufPoolUdp.Put(buf) + buf := common.BufPoolUdp.Get().([]byte) + defer common.BufPoolUdp.Put(buf) target.Write(data) s.task.Flow.Add(int64(len(data)), 0) if n, err := target.Read(buf); err != nil { From 51a3787708bf735d24b239f2b56f44af2f2e0ee7 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Sun, 1 Sep 2019 22:52:48 +0800 Subject: [PATCH 17/58] remove mux write queue, add connection close once --- lib/mux/conn.go | 46 +++++++++++++++-------------- lib/mux/mux.go | 77 ++++++++++++++++++++++++++++--------------------- 2 files changed, 69 insertions(+), 54 deletions(-) diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 7430454..09cac16 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -6,6 +6,7 @@ import ( "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "io" "net" + "sync" "time" ) @@ -27,9 +28,10 @@ type conn struct { isClose bool readWait bool sendClose bool // MUX_CONN_CLOSE already send - writeClose bool // close conn Write + closeFlag bool // close conn flag hasWrite int mux *Mux + once sync.Once } func NewConn(connId int32, mux *Mux) *conn { @@ -41,6 +43,7 @@ func NewConn(connId int32, mux *Mux) *conn { readQueue: NewQueue(), connId: connId, mux: mux, + once: sync.Once{}, } return c } @@ -72,18 +75,14 @@ func (s *conn) Read(buf []byte) (n int, err error) { logs.Warn("conn close by read pop err", s.connId, err) s.Close() return 0, io.EOF + } else if node.val == nil { + s.sendClose = true + logs.Warn("conn close by read ", s.connId) + s.Close() } else { - if node.val == nil { - //close - s.sendClose = true - logs.Warn("conn close by read ", s.connId) - s.Close() - return 0, io.EOF - } else { - s.readBuffer = node.val - s.endRead = node.l - s.startRead = 0 - } + s.readBuffer = node.val + s.endRead = node.l + s.startRead = 0 } } if len(buf) < s.endRead-s.startRead { @@ -101,7 +100,7 @@ func (s *conn) Write(buf []byte) (n int, err error) { if s.isClose { return 0, errors.New("the conn has closed") } - if s.writeClose { + if s.closeFlag { s.sendClose = true logs.Warn("conn close by write ", s.connId) s.Close() @@ -131,11 +130,11 @@ func (s *conn) write(buf []byte, ch chan struct{}) { l := len(buf) for { if l-start > common.PoolSizeCopy { - logs.Warn("conn write > poolsizecopy") + //logs.Warn("conn write > poolsizecopy") s.mux.sendInfo(common.MUX_NEW_MSG, s.connId, buf[start:start+common.PoolSizeCopy]) start += common.PoolSizeCopy } else { - logs.Warn("conn write <= poolsizecopy, start, len", start, l) + //logs.Warn("conn write <= poolsizecopy, start, len", start, l) s.mux.sendInfo(common.MUX_NEW_MSG, s.connId, buf[start:l]) break } @@ -144,20 +143,25 @@ func (s *conn) write(buf []byte, ch chan struct{}) { } func (s *conn) Close() (err error) { + s.once.Do(s.closeProcess) + return +} + +func (s *conn) closeProcess() { if s.isClose { - return errors.New("the conn has closed") + logs.Warn("has closed ", s.connId) + return } s.isClose = true + s.readWait = false s.mux.connMap.Delete(s.connId) common.CopyBuff.Put(s.readBuffer) - if s.readWait { - s.readCh <- struct{}{} - } + close(s.readCh) s.readQueue.Clear() if !s.mux.IsClose { if !s.sendClose { - logs.Warn("conn send close") - go s.mux.sendInfo(common.MUX_CONN_CLOSE, s.connId, nil) + logs.Warn("conn send close", s.connId) + s.mux.sendInfo(common.MUX_CONN_CLOSE, s.connId, nil) } } return diff --git a/lib/mux/mux.go b/lib/mux/mux.go index c40427d..1b90c60 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -41,7 +41,7 @@ func NewMux(c net.Conn, connType string) *Mux { go m.readSession() //ping go m.ping() - go m.writeSession() + //go m.writeSession() return m } @@ -68,7 +68,7 @@ func (s *Mux) NewConn() (*conn, error) { func (s *Mux) Accept() (net.Conn, error) { if s.IsClose { - return nil, errors.New("accpet error,the conn has closed") + return nil, errors.New("accpet error,the mux has closed") } conn := <-s.newConnCh if conn == nil { @@ -91,31 +91,29 @@ func (s *Mux) sendInfo(flag uint8, id int32, content []byte) { buf := common.BuffPool.Get() //defer pool.BuffPool.Put(buf) pack := common.MuxPack.Get() + defer common.MuxPack.Put(pack) err = pack.NewPac(flag, id, content) if err != nil { - s.Close() logs.Warn("new pack err", err) common.BuffPool.Put(buf) return } err = pack.Pack(buf) if err != nil { - s.Close() logs.Warn("pack err", err) common.BuffPool.Put(buf) return } - s.writeQueue <- buf - common.MuxPack.Put(pack) - //_, err = buf.WriteTo(s.conn) - //if err != nil { - // s.Close() - // logs.Warn("write err, close mux", err) - //} - //if flag == common.MUX_CONN_CLOSE { - //} - //if flag == common.MUX_NEW_MSG { - //} + if pack.Flag == common.MUX_NEW_CONN { + logs.Warn("sendinfo mux new conn, insert to write queue", pack.Id) + } + //s.writeQueue <- buf + _, err = buf.WriteTo(s.conn) + if err != nil { + s.Close() + logs.Warn("write err, close mux", err) + } + common.BuffPool.Put(buf) return } @@ -127,7 +125,7 @@ func (s *Mux) writeSession() { n, err := buf.WriteTo(s.conn) common.BuffPool.Put(buf) if err != nil || int(n) != l { - logs.Warn("close from write to ", err, n, l) + logs.Warn("close from write session fail ", err, n, l) s.Close() break } @@ -163,8 +161,8 @@ func (s *Mux) ping() { func (s *Mux) readSession() { go func() { + pack := common.MuxPack.Get() for { - pack := common.MuxPack.Get() if pack.UnPack(s.conn) != nil { break } @@ -173,10 +171,13 @@ func (s *Mux) readSession() { //logs.Warn(pack.Flag, pack.Id, pack.Length, string(pack.Content[:10])) } } + if pack.Flag == common.MUX_NEW_CONN { + logs.Warn("unpack mux new conn", pack.Id) + } s.pingOk = 0 switch pack.Flag { case common.MUX_NEW_CONN: //new conn - logs.Warn("mux new conn", pack.Id) + logs.Warn("rec mux new conn", pack.Id) conn := NewConn(pack.Id, s) s.connMap.Set(pack.Id, conn) //it has been set before send ok s.newConnCh <- conn @@ -194,38 +195,48 @@ func (s *Mux) readSession() { switch pack.Flag { case common.MUX_NEW_MSG: //new msg from remote conn //insert wait queue - logs.Warn("mux new msg ", pack.Id) - conn.readQueue.Push(NewBufNode(pack.Content, int(pack.Length))) + buf := common.CopyBuff.Get() + buf = pack.Content + logs.Warn("rec mux new msg ", pack.Id, string(buf[0:15])) + conn.readQueue.Push(NewBufNode(buf, int(pack.Length))) //judge len if >xxx ,send stop if conn.readWait { conn.readWait = false conn.readCh <- struct{}{} } + continue case common.MUX_NEW_CONN_OK: //conn ok - logs.Warn("mux new conn ok ", pack.Id) + logs.Warn("rec mux new conn ok ", pack.Id) conn.connStatusOkCh <- struct{}{} + continue case common.MUX_NEW_CONN_Fail: - logs.Warn("mux new conn fail", pack.Id) + logs.Warn("rec mux new conn fail", pack.Id) conn.connStatusFailCh <- struct{}{} + continue case common.MUX_CONN_CLOSE: //close the connection - logs.Warn("mux conn close", pack.Id) + logs.Warn("rec mux conn close", pack.Id) s.connMap.Delete(pack.Id) - conn.writeClose = true - conn.readQueue.Push(NewBufNode(nil, 0)) - if conn.readWait { - logs.Warn("close read wait", pack.Id) - conn.readWait = false - conn.readCh <- struct{}{} + conn.closeFlag = true + conn.sendClose = true + if !conn.isClose { + conn.readQueue.Push(NewBufNode(nil, 0)) + if conn.readWait { + logs.Warn("mux conn close read wait", pack.Id) + conn.readWait = false + conn.readCh <- struct{}{} + logs.Warn("mux conn close read wait pass", pack.Id) + } } logs.Warn("receive mux conn close, finish", conn.connId) + continue } - } else if pack.Flag == common.MUX_NEW_MSG { - common.CopyBuff.Put(pack.Content) } else if pack.Flag == common.MUX_CONN_CLOSE { - logs.Warn("mux conn close no id ", pack.Id) + logs.Warn("rec mux conn close no id ", pack.Id) + continue } - common.MuxPack.Put(pack) } + common.MuxPack.Put(pack) + logs.Warn("read session put pack ", pack.Id) s.Close() }() select { From 3413ceb7c21a343ced1c45295b20361d9eb18fcf Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Mon, 2 Sep 2019 00:18:52 +0800 Subject: [PATCH 18/58] add write queue again --- lib/mux/conn.go | 5 ----- lib/mux/mux.go | 16 ++++++++-------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 09cac16..494fd4e 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -148,12 +148,7 @@ func (s *conn) Close() (err error) { } func (s *conn) closeProcess() { - if s.isClose { - logs.Warn("has closed ", s.connId) - return - } s.isClose = true - s.readWait = false s.mux.connMap.Delete(s.connId) common.CopyBuff.Put(s.readBuffer) close(s.readCh) diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 1b90c60..8673c24 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -41,7 +41,7 @@ func NewMux(c net.Conn, connType string) *Mux { go m.readSession() //ping go m.ping() - //go m.writeSession() + go m.writeSession() return m } @@ -107,13 +107,13 @@ func (s *Mux) sendInfo(flag uint8, id int32, content []byte) { if pack.Flag == common.MUX_NEW_CONN { logs.Warn("sendinfo mux new conn, insert to write queue", pack.Id) } - //s.writeQueue <- buf - _, err = buf.WriteTo(s.conn) - if err != nil { - s.Close() - logs.Warn("write err, close mux", err) - } - common.BuffPool.Put(buf) + s.writeQueue <- buf + //_, err = buf.WriteTo(s.conn) + //if err != nil { + // s.Close() + // logs.Warn("write err, close mux", err) + //} + //common.BuffPool.Put(buf) return } From 89df38422c3d5c33ef2d14f5dfa7892b7bf9892c Mon Sep 17 00:00:00 2001 From: he liu Date: Mon, 2 Sep 2019 16:18:03 +0800 Subject: [PATCH 19/58] Update bridge.go --- bridge/bridge.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridge/bridge.go b/bridge/bridge.go index 3247dd8..3f2c3a8 100755 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -296,7 +296,7 @@ func (s *Bridge) register(c *conn.Conn) { func (s *Bridge) SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (target net.Conn, err error) { //if the proxy type is local if link.LocalProxy { - target, err = net.Dial(link.ConnType, link.Host) + target, err = net.Dial("tcp", link.Host) return } if v, ok := s.Client.Load(clientId); ok { From 9d3df6be7e0e623819463df0d4eb2940b9319d96 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Sun, 8 Sep 2019 23:49:16 +0800 Subject: [PATCH 20/58] add mux slide window --- lib/common/netpackager.go | 20 +- lib/common/pool.go | 60 ++++-- lib/common/util.go | 109 ++--------- lib/mux/conn.go | 398 ++++++++++++++++++++++++++++++-------- lib/mux/mux.go | 90 +++++---- lib/mux/mux_test.go | 39 ++-- 6 files changed, 474 insertions(+), 242 deletions(-) diff --git a/lib/common/netpackager.go b/lib/common/netpackager.go index 6d67f44..f2ddaec 100644 --- a/lib/common/netpackager.go +++ b/lib/common/netpackager.go @@ -150,8 +150,9 @@ func (Self *ConnPackager) UnPack(reader io.Reader) (err error) { } type MuxPackager struct { - Flag uint8 - Id int32 + Flag uint8 + Id int32 + Window uint16 BasePackager } @@ -161,6 +162,15 @@ func (Self *MuxPackager) NewPac(flag uint8, id int32, content ...interface{}) (e if flag == MUX_NEW_MSG { err = Self.BasePackager.NewPac(content...) } + if flag == MUX_MSG_SEND_OK { + // MUX_MSG_SEND_OK only allows one data + switch content[0].(type) { + case int: + Self.Window = uint16(content[0].(int)) + case uint16: + Self.Window = content[0].(uint16) + } + } return } @@ -176,6 +186,9 @@ func (Self *MuxPackager) Pack(writer io.Writer) (err error) { if Self.Flag == MUX_NEW_MSG { err = Self.BasePackager.Pack(writer) } + if Self.Flag == MUX_MSG_SEND_OK { + err = binary.Write(writer, binary.LittleEndian, Self.Window) + } return } @@ -192,5 +205,8 @@ func (Self *MuxPackager) UnPack(reader io.Reader) (err error) { if Self.Flag == MUX_NEW_MSG { err = Self.BasePackager.UnPack(reader) } + if Self.Flag == MUX_MSG_SEND_OK { + err = binary.Read(reader, binary.LittleEndian, &Self.Window) + } return } diff --git a/lib/common/pool.go b/lib/common/pool.go index 205378d..98da5d3 100644 --- a/lib/common/pool.go +++ b/lib/common/pool.go @@ -9,6 +9,7 @@ const PoolSize = 64 * 1024 const PoolSizeSmall = 100 const PoolSizeUdp = 1472 const PoolSizeCopy = 32 << 10 +const PoolSizeWindow = 1<<16 - 1 var BufPool = sync.Pool{ New: func() interface{} { @@ -59,11 +60,11 @@ func PutBufPoolMax(buf []byte) { } } -type CopyBufferPool struct { +type copyBufferPool struct { pool sync.Pool } -func (Self *CopyBufferPool) New() { +func (Self *copyBufferPool) New() { Self.pool = sync.Pool{ New: func() interface{} { return make([]byte, PoolSizeCopy, PoolSizeCopy) @@ -71,24 +72,49 @@ func (Self *CopyBufferPool) New() { } } -func (Self *CopyBufferPool) Get() []byte { +func (Self *copyBufferPool) Get() []byte { buf := Self.pool.Get().([]byte) return buf[:PoolSizeCopy] // just like make a new slice, but data may not be 0 } -func (Self *CopyBufferPool) Put(x []byte) { +func (Self *copyBufferPool) Put(x []byte) { if len(x) == PoolSizeCopy { Self.pool.Put(x) } else { - x = nil // buf is not full, maybe truncated by gc in pool, not allowed + x = nil // buf is not full, not allowed, New method returns a full buf } } -type BufferPool struct { +type windowBufferPool struct { pool sync.Pool } -func (Self *BufferPool) New() { +func (Self *windowBufferPool) New() { + Self.pool = sync.Pool{ + New: func() interface{} { + return make([]byte, 0, PoolSizeWindow) + }, + } +} + +func (Self *windowBufferPool) Get() (buf []byte) { + buf = Self.pool.Get().([]byte) + return buf[:0] +} + +func (Self *windowBufferPool) Put(x []byte) { + if cap(x) == PoolSizeWindow { + Self.pool.Put(x[:PoolSizeWindow]) // make buf to full + } else { + x = nil + } +} + +type bufferPool struct { + pool sync.Pool +} + +func (Self *bufferPool) New() { Self.pool = sync.Pool{ New: func() interface{} { return new(bytes.Buffer) @@ -96,20 +122,20 @@ func (Self *BufferPool) New() { } } -func (Self *BufferPool) Get() *bytes.Buffer { +func (Self *bufferPool) Get() *bytes.Buffer { return Self.pool.Get().(*bytes.Buffer) } -func (Self *BufferPool) Put(x *bytes.Buffer) { +func (Self *bufferPool) Put(x *bytes.Buffer) { x.Reset() Self.pool.Put(x) } -type MuxPackagerPool struct { +type muxPackagerPool struct { pool sync.Pool } -func (Self *MuxPackagerPool) New() { +func (Self *muxPackagerPool) New() { Self.pool = sync.Pool{ New: func() interface{} { pack := MuxPackager{} @@ -118,27 +144,29 @@ func (Self *MuxPackagerPool) New() { } } -func (Self *MuxPackagerPool) Get() *MuxPackager { +func (Self *muxPackagerPool) Get() *MuxPackager { pack := Self.pool.Get().(*MuxPackager) buf := CopyBuff.Get() pack.Content = buf return pack } -func (Self *MuxPackagerPool) Put(pack *MuxPackager) { +func (Self *muxPackagerPool) Put(pack *MuxPackager) { CopyBuff.Put(pack.Content) Self.pool.Put(pack) } var once = sync.Once{} -var BuffPool = BufferPool{} -var CopyBuff = CopyBufferPool{} -var MuxPack = MuxPackagerPool{} +var BuffPool = bufferPool{} +var CopyBuff = copyBufferPool{} +var MuxPack = muxPackagerPool{} +var WindowBuff = windowBufferPool{} func newPool() { BuffPool.New() CopyBuff.New() MuxPack.New() + WindowBuff.New() } func init() { diff --git a/lib/common/util.go b/lib/common/util.go index 3b4369f..60b01dc 100755 --- a/lib/common/util.go +++ b/lib/common/util.go @@ -4,9 +4,7 @@ import ( "bytes" "encoding/base64" "encoding/binary" - "errors" "github.com/cnlh/nps/lib/crypt" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "html/template" "io" "io/ioutil" @@ -264,96 +262,31 @@ func GetPortByAddr(addr string) int { return p } -type ConnCopy struct { - dst net.Conn - src net.Conn - buf []byte - connId int32 -} - -func (Self *ConnCopy) New(dst net.Conn, src net.Conn, connId int32) { - Self.dst = dst - Self.src = src - Self.buf = CopyBuff.Get() - Self.connId = connId -} - -func (Self *ConnCopy) copyBufferOnce() (written int64, err error) { - nr, er := Self.src.Read(Self.buf) - if nr > 0 { - //logs.Warn("write", Self.connId, nr, string(buf[0:10])) - nw, ew := Self.dst.Write(Self.buf[0:nr]) - if nw > 0 { - written = int64(nw) - } - if ew != nil { - //logs.Warn("write err ew id nw", ew, Self.connId, nw) - err = ew - return - } - if nr != nw { - err = io.ErrShortWrite - return - } - if nw == 0 { - err = errors.New("io: write on closed pipe") - //logs.Warn("write buffer", err) - return - } - } - if nr == 0 && er == nil { - err = errors.New("io: read on closed pipe") - //logs.Warn("read buffer", err) - return - } - if er != nil { - err = er - return - } - return -} - -func (Self *ConnCopy) copyBuffer() (written int64, err error) { - var write int64 - write, err = Self.copyBufferOnce() // first copy, if written is zero and err is io.EOF - // means conn already closed, so need to close all the conn - written += write - if err == io.EOF && written == 0 { - err = errors.New("io: read on closed pipe") - return - } else if err == io.EOF && written > 0 { - err = nil - return - } +func CopyBuffer(dst io.Writer, src io.Reader) (written int64, err error) { + buf := CopyBuff.Get() + defer CopyBuff.Put(buf) for { - write, err = Self.copyBufferOnce() - written += write - if err != nil { - if err == io.EOF { - err = nil + nr, er := src.Read(buf) + if nr > 0 { + nw, ew := dst.Write(buf[0:nr]) + if nw > 0 { + written += int64(nw) } - return + if ew != nil { + err = ew + break + } + if nr != nw { + err = io.ErrShortWrite + break + } + } + if er != nil { + err = er + break } } -} - -func (Self *ConnCopy) CopyConn() (written int64, err error) { - defer CopyBuff.Put(Self.buf) - if Self.dst != nil && Self.src != nil { - written, err = Self.copyBuffer() - } else { - return 0, errors.New("copy conn nil src or dst") - } - if err != nil { // copyBuffer do not return io.EOF ,close all conn - logs.Warn("close by copy conn ", Self.connId, err) - if Self.dst != nil { - Self.dst.Close() - } - if Self.src != nil { - Self.src.Close() - } - } - return + return written, err } //send this ip forget to get a local udp port diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 494fd4e..08b0db0 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -17,34 +17,37 @@ type conn struct { connStatusFailCh chan struct{} readTimeOut time.Time writeTimeOut time.Time - readBuffer []byte - startRead int //now read position - endRead int //now end read - readFlag bool - readCh chan struct{} - readQueue *sliceEntry - stopWrite bool - connId int32 - isClose bool - readWait bool - sendClose bool // MUX_CONN_CLOSE already send - closeFlag bool // close conn flag - hasWrite int - mux *Mux - once sync.Once + //readBuffer []byte + //startRead int //now read position + //endRead int //now end read + //readFlag bool + //readCh chan struct{} + //readQueue *sliceEntry + //stopWrite bool + connId int32 + isClose bool + //readWait bool + closeFlag bool // close conn flag + hasWrite int + receiveWindow *window + sendWindow *window + mux *Mux + once sync.Once } func NewConn(connId int32, mux *Mux) *conn { c := &conn{ - readCh: make(chan struct{}), getStatusCh: make(chan struct{}), connStatusOkCh: make(chan struct{}), connStatusFailCh: make(chan struct{}), - readQueue: NewQueue(), connId: connId, + receiveWindow: new(window), + sendWindow: new(window), mux: mux, once: sync.Once{}, } + c.receiveWindow.NewReceive() + c.sendWindow.NewSend() return c } @@ -52,94 +55,99 @@ func (s *conn) Read(buf []byte) (n int, err error) { if s.isClose || buf == nil { return 0, errors.New("the conn has closed") } - if s.endRead-s.startRead == 0 { //read finish or start - if s.readQueue.Size() == 0 { - s.readWait = true - if t := s.readTimeOut.Sub(time.Now()); t > 0 { - timer := time.NewTimer(t) - defer timer.Stop() - select { - case <-timer.C: - s.readWait = false - return 0, errors.New("read timeout") - case <-s.readCh: - } - } else { - <-s.readCh - } + nCh := make(chan int) + errCh := make(chan error) + defer close(nCh) + defer close(errCh) + // waiting for takeout from receive window finish or timeout + go s.readWindow(buf, nCh, errCh) + if t := s.readTimeOut.Sub(time.Now()); t > 0 { + timer := time.NewTimer(t) + defer timer.Stop() + select { + case <-timer.C: + return 0, errors.New("read timeout") + case n = <-nCh: + err = <-errCh } - if s.isClose { //If the connection is closed instead of continuing command - return 0, errors.New("the conn has closed") - } - if node, err := s.readQueue.Pop(); err != nil { - logs.Warn("conn close by read pop err", s.connId, err) - s.Close() - return 0, io.EOF - } else if node.val == nil { - s.sendClose = true - logs.Warn("conn close by read ", s.connId) - s.Close() - } else { - s.readBuffer = node.val - s.endRead = node.l - s.startRead = 0 - } - } - if len(buf) < s.endRead-s.startRead { - n = copy(buf, s.readBuffer[s.startRead:s.startRead+len(buf)]) - s.startRead += n } else { - n = copy(buf, s.readBuffer[s.startRead:s.endRead]) - s.startRead += n - common.CopyBuff.Put(s.readBuffer) + n = <-nCh + err = <-errCh } + logs.Warn("read window finish conn read n err buf", n, err, string(buf[:15])) return } +func (s *conn) readWindow(buf []byte, nCh chan int, errCh chan error) { + n, err := s.receiveWindow.Read(buf) + //logs.Warn("readwindow goroutine status n err buf", n, err, string(buf[:15])) + if s.receiveWindow.WindowFull { + if s.receiveWindow.Size() > 0 { + // window.Read may be invoked before window.Write, and WindowFull flag change to true + // so make sure that receiveWindow is free some space + s.receiveWindow.WindowFull = false + logs.Warn("defer send mux msg send ok size", s.receiveWindow.Size()) + s.mux.sendInfo(common.MUX_MSG_SEND_OK, s.connId, s.receiveWindow.Size()) + // acknowledge other side, have empty some receive window space + } + } + nCh <- n + errCh <- err +} + func (s *conn) Write(buf []byte) (n int, err error) { if s.isClose { return 0, errors.New("the conn has closed") } if s.closeFlag { - s.sendClose = true logs.Warn("conn close by write ", s.connId) - s.Close() + //s.Close() return 0, errors.New("io: write on closed conn") } - ch := make(chan struct{}) - go s.write(buf, ch) + + nCh := make(chan int) + errCh := make(chan error) + defer close(nCh) + defer close(errCh) + s.sendWindow.SetSendBuf(buf) // set the buf to send window + go s.write(nCh, errCh) + // waiting for send to other side or timeout if t := s.writeTimeOut.Sub(time.Now()); t > 0 { timer := time.NewTimer(t) defer timer.Stop() select { case <-timer.C: return 0, errors.New("write timeout") - case <-ch: + case n = <-nCh: + err = <-errCh } } else { - <-ch + n = <-nCh + err = <-errCh } - close(ch) - //if s.isClose { - // return 0, io.ErrClosedPipe - //} - return len(buf), nil + return } -func (s *conn) write(buf []byte, ch chan struct{}) { - start := 0 - l := len(buf) +func (s *conn) write(nCh chan int, errCh chan error) { + var n int + var err error for { - if l-start > common.PoolSizeCopy { - //logs.Warn("conn write > poolsizecopy") - s.mux.sendInfo(common.MUX_NEW_MSG, s.connId, buf[start:start+common.PoolSizeCopy]) - start += common.PoolSizeCopy - } else { - //logs.Warn("conn write <= poolsizecopy, start, len", start, l) - s.mux.sendInfo(common.MUX_NEW_MSG, s.connId, buf[start:l]) + buf, err := s.sendWindow.WriteTo() + // get the usable window size buf from send window + if buf == nil && err == io.EOF { + // send window is drain, break the loop + err = nil break } + if err != nil { + break + } + n += len(buf) + //logs.Warn("send window buf len", len(buf)) + s.mux.sendInfo(common.MUX_NEW_MSG, s.connId, buf) + // send to other side, not send nil data to other side } - ch <- struct{}{} + nCh <- n + errCh <- err } func (s *conn) Close() (err error) { @@ -150,15 +158,14 @@ func (s *conn) Close() (err error) { func (s *conn) closeProcess() { s.isClose = true s.mux.connMap.Delete(s.connId) - common.CopyBuff.Put(s.readBuffer) - close(s.readCh) - s.readQueue.Clear() if !s.mux.IsClose { - if !s.sendClose { - logs.Warn("conn send close", s.connId) - s.mux.sendInfo(common.MUX_CONN_CLOSE, s.connId, nil) - } + logs.Warn("conn send close", s.connId) + // if server or user close the conn while reading, will get a io.EOF + // and this Close method will be invoke, send this signal to close other side + s.mux.sendInfo(common.MUX_CONN_CLOSE, s.connId, nil) } + s.sendWindow.CloseWindow() + s.receiveWindow.CloseWindow() return } @@ -185,3 +192,226 @@ func (s *conn) SetWriteDeadline(t time.Time) error { s.writeTimeOut = t return nil } + +type window struct { + windowBuff []byte + off uint16 + readOp chan struct{} + readWait bool + WindowFull bool + usableReceiveWindow chan uint16 + WriteWg sync.WaitGroup + closeOp bool + closeOpCh chan struct{} + WriteEndOp chan struct{} + mutex sync.Mutex +} + +func (Self *window) NewReceive() { + // initial a window for receive + Self.windowBuff = common.WindowBuff.Get() + Self.readOp = make(chan struct{}) + Self.WriteEndOp = make(chan struct{}) + Self.closeOpCh = make(chan struct{}, 2) +} + +func (Self *window) NewSend() { + // initial a window for send + Self.usableReceiveWindow = make(chan uint16) + Self.closeOpCh = make(chan struct{}, 2) +} + +func (Self *window) SetSendBuf(buf []byte) { + // send window buff from conn write method, set it to send window + Self.mutex.Lock() + Self.windowBuff = buf + Self.off = 0 + Self.mutex.Unlock() +} + +func (Self *window) fullSlide() { + // slide by allocate + newBuf := common.WindowBuff.Get() + copy(newBuf[0:Self.len()], Self.windowBuff[Self.off:]) + Self.off = 0 + common.WindowBuff.Put(Self.windowBuff) + Self.windowBuff = newBuf + return +} + +func (Self *window) liteSlide() { + // slide by re slice + Self.windowBuff = Self.windowBuff[Self.off:] + Self.off = 0 + return +} + +func (Self *window) Size() (n int) { + // receive Window remaining + n = common.PoolSizeWindow - Self.len() + return +} + +func (Self *window) len() (n int) { + n = len(Self.windowBuff[Self.off:]) + return +} + +func (Self *window) cap() (n int) { + n = cap(Self.windowBuff[Self.off:]) + return +} + +func (Self *window) grow(n int) { + Self.windowBuff = Self.windowBuff[:Self.len()+n] +} + +func (Self *window) Write(p []byte) (n int, err error) { + if Self.closeOp { + logs.Warn("window write closed len p", len(p)) + return 0, errors.New("conn.receiveWindow: write on closed window") + } + if len(p) > Self.Size() { + return 0, errors.New("conn.receiveWindow: write too large") + } + if Self.readWait { + defer Self.allowRead() + } + //logs.Warn("window write p string", len(p), string(p[:15])) + Self.mutex.Lock() + // slide the offset + if len(p) > Self.cap()-Self.len() { + // not enough space, need to allocate + Self.fullSlide() + //logs.Warn("window write full slide len cap", Self.len(), Self.cap()) + } else { + // have enough space, re slice + Self.liteSlide() + //logs.Warn("window write lite slide len cap", Self.len(), Self.cap()) + } + length := Self.len() // length before grow + Self.grow(len(p)) // grow for copy + n = copy(Self.windowBuff[length:], p) // must copy data before allow Read + //logs.Warn("window write copy n len cap buf", n, Self.len(), Self.cap(), string(Self.windowBuff[Self.len()-n:Self.len()+15-n])) + Self.mutex.Unlock() + return n, nil +} + +func (Self *window) allowRead() (closed bool) { + //logs.Warn("length 0 read op") + Self.readWait = false + if Self.closeOp { + close(Self.readOp) + return true + } + select { + case <-Self.closeOpCh: + close(Self.readOp) + return true + case Self.readOp <- struct{}{}: + //logs.Warn("length 0 read op finish") + return false + } +} + +func (Self *window) Read(p []byte) (n int, err error) { + //logs.Warn("starting window read method len ", Self.len()) + if Self.closeOp { + return 0, io.EOF // Write method receive close signal, returns eof + } + if Self.len() == 0 { + // window is empty, waiting for Write method send a success readOp signal + // or get timeout or close + Self.readWait = true + ticker := time.NewTicker(2 * time.Minute) + defer ticker.Stop() + select { + case _, ok := <-Self.readOp: + //logs.Warn("read window read op len cap", Self.len(), Self.cap()) + if !ok { + return 0, errors.New("conn.receiveWindow: window closed") + } + case <-Self.WriteEndOp: + return 0, io.EOF // receive eof signal, returns eof + case <-ticker.C: + return 0, errors.New("conn.receiveWindow: read time out") + case <-Self.closeOpCh: + close(Self.readOp) + return 0, io.EOF // receive close signal, returns eof + } + } + //logs.Warn("window read start len window buff", Self.len(), string(Self.windowBuff[Self.off:Self.off+15])) + Self.mutex.Lock() + n = copy(p, Self.windowBuff[Self.off:]) + Self.off += uint16(n) + p = p[:n] + //logs.Warn("window read finish n len p p", n, len(p), string(p[:15])) + Self.mutex.Unlock() + return +} + +func (Self *window) WriteTo() (p []byte, err error) { + if Self.closeOp { + logs.Warn("window write to closed") + return nil, errors.New("conn.writeWindow: window closed") + } + if Self.len() == 0 { + return nil, io.EOF + // send window buff is drain, return eof and get another one + } + var windowSize uint16 + var ok bool +waiting: + ticker := time.NewTicker(2 * time.Minute) + defer ticker.Stop() + // waiting for receive usable window size, or timeout + select { + case windowSize, ok = <-Self.usableReceiveWindow: + if !ok { + return nil, errors.New("conn.writeWindow: window closed") + } + case <-ticker.C: + return nil, errors.New("conn.writeWindow: write to time out") + } + if windowSize == 0 { + goto waiting // waiting for another usable window size + } + Self.mutex.Lock() + if windowSize > uint16(Self.len()) { + // usable window size is bigger than window buff size, send the full buff + //logs.Warn("window size overflow windowSize len()", windowSize, Self.len()) + windowSize = uint16(Self.len()) + } + //logs.Warn("window buff off windowSize", Self.off, windowSize) + p = Self.windowBuff[Self.off : windowSize+Self.off] + Self.off += windowSize + Self.mutex.Unlock() + return +} + +func (Self *window) SetAllowSize(value uint16) (closed bool) { + defer func() { + if recover() != nil { + closed = true + } + }() + if Self.closeOp { + close(Self.usableReceiveWindow) + return true + } + select { + case Self.usableReceiveWindow <- value: + return false + case <-Self.closeOpCh: + close(Self.usableReceiveWindow) + return true + } +} + +func (Self *window) CloseWindow() { + Self.closeOp = true + Self.closeOpCh <- struct{}{} + Self.closeOpCh <- struct{}{} + close(Self.closeOpCh) + return +} diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 8673c24..9310c64 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -81,10 +81,10 @@ func (s *Mux) Addr() net.Addr { return s.conn.LocalAddr() } -func (s *Mux) sendInfo(flag uint8, id int32, content []byte) { +func (s *Mux) sendInfo(flag uint8, id int32, data interface{}) { var err error if flag == common.MUX_NEW_MSG { - if len(content) == 0 { + if len(data.([]byte)) == 0 { logs.Warn("send info content is nil") } } @@ -92,7 +92,7 @@ func (s *Mux) sendInfo(flag uint8, id int32, content []byte) { //defer pool.BuffPool.Put(buf) pack := common.MuxPack.Get() defer common.MuxPack.Put(pack) - err = pack.NewPac(flag, id, content) + err = pack.NewPac(flag, id, data) if err != nil { logs.Warn("new pack err", err) common.BuffPool.Put(buf) @@ -163,6 +163,7 @@ func (s *Mux) readSession() { go func() { pack := common.MuxPack.Get() for { + pack = common.MuxPack.Get() if pack.UnPack(s.conn) != nil { break } @@ -172,17 +173,18 @@ func (s *Mux) readSession() { } } if pack.Flag == common.MUX_NEW_CONN { - logs.Warn("unpack mux new conn", pack.Id) + logs.Warn("unpack mux new connection", pack.Id) } s.pingOk = 0 switch pack.Flag { - case common.MUX_NEW_CONN: //new conn - logs.Warn("rec mux new conn", pack.Id) + case common.MUX_NEW_CONN: //new connection + logs.Warn("rec mux new connection", pack.Id) conn := NewConn(pack.Id, s) s.connMap.Set(pack.Id, conn) //it has been set before send ok s.newConnCh <- conn + go conn.sendWindow.SetAllowSize(512) // set the initial receive window s.sendInfo(common.MUX_NEW_CONN_OK, pack.Id, nil) - logs.Warn("send mux new conn ok", pack.Id) + logs.Warn("send mux new connection ok", pack.Id) continue case common.MUX_PING_FLAG: //ping //logs.Warn("send mux ping return") @@ -191,49 +193,65 @@ func (s *Mux) readSession() { case common.MUX_PING_RETURN: continue } - if conn, ok := s.connMap.Get(pack.Id); ok && !conn.isClose { + if connection, ok := s.connMap.Get(pack.Id); ok && !connection.isClose { switch pack.Flag { - case common.MUX_NEW_MSG: //new msg from remote conn + case common.MUX_NEW_MSG: //new msg from remote connection //insert wait queue - buf := common.CopyBuff.Get() - buf = pack.Content - logs.Warn("rec mux new msg ", pack.Id, string(buf[0:15])) - conn.readQueue.Push(NewBufNode(buf, int(pack.Length))) - //judge len if >xxx ,send stop - if conn.readWait { - conn.readWait = false - conn.readCh <- struct{}{} + if connection.isClose { + logs.Warn("rec mux new msg closed", pack.Id, string(pack.Content[0:15])) + continue } + connection.receiveWindow.WriteWg.Add(1) + logs.Warn("rec mux new msg ", pack.Id, string(pack.Content[0:15])) + go func(connection *conn, content []byte) { // do not block read session + _, err := connection.receiveWindow.Write(content) + if err != nil { + logs.Warn("mux new msg err close", err) + s.Close() + } + size := connection.receiveWindow.Size() + if size == 0 { + connection.receiveWindow.WindowFull = true + } + s.sendInfo(common.MUX_MSG_SEND_OK, connection.connId, size) + logs.Warn("send mux new msg ok", pack.Id, size) + connection.receiveWindow.WriteWg.Done() + }(connection, pack.Content) continue - case common.MUX_NEW_CONN_OK: //conn ok - logs.Warn("rec mux new conn ok ", pack.Id) - conn.connStatusOkCh <- struct{}{} + case common.MUX_NEW_CONN_OK: //connection ok + logs.Warn("rec mux new connection ok ", pack.Id) + connection.connStatusOkCh <- struct{}{} + go connection.sendWindow.SetAllowSize(512) + // set the initial receive window both side continue case common.MUX_NEW_CONN_Fail: - logs.Warn("rec mux new conn fail", pack.Id) - conn.connStatusFailCh <- struct{}{} + logs.Warn("rec mux new connection fail", pack.Id) + connection.connStatusFailCh <- struct{}{} + continue + case common.MUX_MSG_SEND_OK: + if connection.isClose { + logs.Warn("rec mux msg send ok id window closed!", pack.Id, pack.Window) + continue + } + logs.Warn("rec mux msg send ok id window", pack.Id, pack.Window) + go connection.sendWindow.SetAllowSize(pack.Window) continue case common.MUX_CONN_CLOSE: //close the connection - logs.Warn("rec mux conn close", pack.Id) + logs.Warn("rec mux connection close", pack.Id) s.connMap.Delete(pack.Id) - conn.closeFlag = true - conn.sendClose = true - if !conn.isClose { - conn.readQueue.Push(NewBufNode(nil, 0)) - if conn.readWait { - logs.Warn("mux conn close read wait", pack.Id) - conn.readWait = false - conn.readCh <- struct{}{} - logs.Warn("mux conn close read wait pass", pack.Id) - } - } - logs.Warn("receive mux conn close, finish", conn.connId) + connection.closeFlag = true + go func(connection *conn) { + connection.receiveWindow.WriteWg.Wait() + connection.receiveWindow.WriteEndOp <- struct{}{} // close signal to receive window + logs.Warn("receive mux connection close, finish", connection.connId) + }(connection) continue } } else if pack.Flag == common.MUX_CONN_CLOSE { - logs.Warn("rec mux conn close no id ", pack.Id) + logs.Warn("rec mux connection close no id ", pack.Id) continue } + common.MuxPack.Put(pack) } common.MuxPack.Put(pack) logs.Warn("read session put pack ", pack.Id) diff --git a/lib/mux/mux_test.go b/lib/mux/mux_test.go index 728dfa3..7c75c10 100644 --- a/lib/mux/mux_test.go +++ b/lib/mux/mux_test.go @@ -37,14 +37,17 @@ func TestNewMux(t *testing.T) { logs.Warn(err) continue } - var npcToServer common.ConnCopy - npcToServer.New(c2, c, 0) - go npcToServer.CopyConn() - var serverToNpc common.ConnCopy - serverToNpc.New(c, c2, 10000) - _, err = serverToNpc.CopyConn() - if err == nil { - logs.Warn("close npc") + go func() { + _, err = common.CopyBuffer(c2, c) + if err != nil { + logs.Warn("close npc by copy from nps", err) + c2.Close() + c.Close() + } + }() + _, err = common.CopyBuffer(c, c2) + if err != nil { + logs.Warn("close npc by copy from server", err) c2.Close() c.Close() } @@ -71,14 +74,18 @@ func TestNewMux(t *testing.T) { continue } logs.Warn("nps new conn success ", tmpCpnn.connId) - var userToNps common.ConnCopy - userToNps.New(tmpCpnn, conn, tmpCpnn.connId) - go userToNps.CopyConn() - var npsToUser common.ConnCopy - npsToUser.New(conn, tmpCpnn, tmpCpnn.connId+10000) - _, err = npsToUser.CopyConn() - if err == nil { - logs.Warn("close from out nps ", tmpCpnn.connId) + go func() { + _, err := common.CopyBuffer(tmpCpnn, conn) + if err != nil { + logs.Warn("close nps by copy from user", tmpCpnn.connId) + conn.Close() + tmpCpnn.Close() + } + }() + //time.Sleep(time.Second) + _, err = common.CopyBuffer(conn, tmpCpnn) + if err != nil { + logs.Warn("close nps by copy from npc ", tmpCpnn.connId) conn.Close() tmpCpnn.Close() } From fce53fa308256781794aa875f1e822968097ec50 Mon Sep 17 00:00:00 2001 From: zhangwei Date: Tue, 10 Sep 2019 23:14:05 +0800 Subject: [PATCH 21/58] new feature multi user auth with socks5 --- conf/multiuser.conf | 0 go.mod | 9 +++------ go.sum | 24 ++++++++---------------- lib/config/config.go | 26 ++++++++++++++++++++++++++ lib/file/obj.go | 10 ++++++---- npc.conf | 21 +++++++++++++++++++++ server/proxy/socks5.go | 19 +++++++++++++++++-- 7 files changed, 81 insertions(+), 28 deletions(-) create mode 100644 conf/multiuser.conf create mode 100644 npc.conf diff --git a/conf/multiuser.conf b/conf/multiuser.conf new file mode 100644 index 0000000..e69de29 diff --git a/go.mod b/go.mod index 1f6b753..e8111a1 100644 --- a/go.mod +++ b/go.mod @@ -5,23 +5,20 @@ go 1.12 require ( github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/astaxie/beego v1.12.0 - github.com/belogik/goes v0.0.0-20151229125003-e54d722c3aff // indirect github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d github.com/go-ole/go-ole v1.2.4 // indirect github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db github.com/klauspost/cpuid v1.2.1 // indirect - github.com/klauspost/reedsolomon v1.9.2 - github.com/onsi/gomega v1.5.0 // indirect + github.com/klauspost/reedsolomon v1.9.2 // indirect github.com/pkg/errors v0.8.0 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect github.com/shirou/gopsutil v2.18.12+incompatible github.com/stretchr/testify v1.3.0 // indirect github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect - github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b - github.com/tjfoc/gmsm v1.0.1 + github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b // indirect + github.com/tjfoc/gmsm v1.0.1 // indirect github.com/xtaci/kcp-go v5.4.4+incompatible github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect - golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa // indirect ) diff --git a/go.sum b/go.sum index 29de132..a0396f9 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,9 @@ github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/astaxie/beego v1.12.0 h1:MRhVoeeye5N+Flul5PoVfD9CslfdoH+xqC/xvSQ5u2Y= -github.com/astaxie/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ= github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU= -github.com/belogik/goes v0.0.0-20151229125003-e54d722c3aff/go.mod h1:PhH1ZhyCzHKt4uAasyx+ljRCgoezetRNf59CUtwUkqY= github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d h1:As4937T5NVbJ/DmZT9z33pyLEprMd6CUSfhbmMY57Io= @@ -15,34 +13,31 @@ github.com/couchbase/go-couchbase v0.0.0-20181122212707-3e9b6e1258bb/go.mod h1:T github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk= github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/exfly/beego v1.12.0-export-init h1:VQNYKdXhAwZGUaFmQv8Aj921O3rQJZRIF8xeGrhsjrI= github.com/exfly/beego v1.12.0-export-init/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= -github.com/exfly/beego v1.12.0 h1:OXwIwngaAx35Mga+jLiZmArusBxj8/H0jYXzGDAdwOg= -github.com/exfly/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/reedsolomon v1.9.2 h1:E9CMS2Pqbv+C7tsrYad4YC9MfhnMVWhMRsTi7U0UB18= github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo= github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= @@ -53,6 +48,7 @@ github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1Dp github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU= @@ -64,19 +60,15 @@ github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/ github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= github.com/xtaci/kcp-go v5.4.4+incompatible h1:QIJ0a0Q0N1G20yLHL2+fpdzyy2v/Cb3PI+xiwx/KK9c= github.com/xtaci/kcp-go v5.4.4+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= +github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI= golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/lib/config/config.go b/lib/config/config.go index c35afb7..d66618f 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -239,12 +239,38 @@ func dealTunnel(s string) *file.Tunnel { t.LocalPath = item[1] case "strip_pre": t.StripPre = item[1] + case "multi_user": + // TODO 解析多账号配置文件 + t.Client.Cnf.MultiUser = true + if b, err := common.ReadAllFromFile(item[1]); err != nil { + panic(err) + } else { + if content, err := common.ParseStr(string(b)); err != nil { + panic(err) + } else { + t.Client.Cnf.MultiUserMap = dealMultiUser(content) + } + } } } return t } +func dealMultiUser(s string) map[string]string { + multiUserMap := make(map[string]string) + for _, v := range splitStr(s) { + item := strings.Split(v, "=") + if len(item) == 0 { + continue + } else if len(item) == 1 { + item = append(item, "") + } + multiUserMap[strings.TrimSpace(item[0])] = item[1] + } + return multiUserMap +} + func delLocalService(s string) *LocalServer { l := new(LocalServer) for _, v := range splitStr(s) { diff --git a/lib/file/obj.go b/lib/file/obj.go index d3a1fbe..2215968 100644 --- a/lib/file/obj.go +++ b/lib/file/obj.go @@ -25,10 +25,12 @@ func (s *Flow) Add(in, out int64) { } type Config struct { - U string - P string - Compress bool - Crypt bool + U string + P string + Compress bool + Crypt bool + MultiUser bool // enable multi user authentication. + MultiUserMap map[string]string // multi user and pwd } type Client struct { diff --git a/npc.conf b/npc.conf new file mode 100644 index 0000000..63a8a37 --- /dev/null +++ b/npc.conf @@ -0,0 +1,21 @@ +[common] +server_addr=proxy.njcp.info:55000 +conn_type=tcp +vkey=%EEKn6q386JmCQC^ +auto_reconnection=true +max_conn=1000 +flow_limit=1000 +rate_limit=1000 +basic_username=bobanNanJing +basic_password=N^#xf407W%ZfOg$u +web_username=12 +web_password=12 +crypt=true +compress=true +username=bobanNanJing +password=0Ho@^#U&y571%cK* + + +[socks5] +mode=socks5 +server_port=19009 \ No newline at end of file diff --git a/server/proxy/socks5.go b/server/proxy/socks5.go index 2fe72c1..d6c6ec6 100755 --- a/server/proxy/socks5.go +++ b/server/proxy/socks5.go @@ -199,7 +199,7 @@ func (s *Sock5ModeServer) handleConn(c net.Conn) { c.Close() return } - if s.task.Client.Cnf.U != "" && s.task.Client.Cnf.P != "" { + if (s.task.Client.Cnf.U != "" && s.task.Client.Cnf.P != "") || (s.task.Client.Cnf.MultiUser && len(s.task.Client.Cnf.MultiUserMap) > 0) { buf[1] = UserPassAuth c.Write(buf) if err := s.Auth(c); err != nil { @@ -236,7 +236,22 @@ func (s *Sock5ModeServer) Auth(c net.Conn) error { if _, err := io.ReadAtLeast(c, pass, passLen); err != nil { return err } - if string(user) == s.task.Client.Cnf.U && string(pass) == s.task.Client.Cnf.P { + + var U, P string + if s.task.Client.Cnf.MultiUser { + // enable multi user auth + U = string(user) + var ok bool + P, ok = s.task.Client.Cnf.MultiUserMap[U] + if !ok { + return errors.New("验证不通过") + } + } else { + U = s.task.Client.Cnf.U + P = s.task.Client.Cnf.P + } + + if string(user) == U && string(pass) == P { if _, err := c.Write([]byte{userAuthVersion, authSuccess}); err != nil { return err } From 5e55b761cf29118937d7d403dcff9a40bdcba474 Mon Sep 17 00:00:00 2001 From: zhangwei Date: Tue, 10 Sep 2019 23:15:38 +0800 Subject: [PATCH 22/58] new feature multi user auth with socks5 --- lib/config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/config.go b/lib/config/config.go index d66618f..9ab4b6c 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -240,7 +240,7 @@ func dealTunnel(s string) *file.Tunnel { case "strip_pre": t.StripPre = item[1] case "multi_user": - // TODO 解析多账号配置文件 + // TODO add test with multi user config file t.Client.Cnf.MultiUser = true if b, err := common.ReadAllFromFile(item[1]); err != nil { panic(err) From 1c1be202b7e387c0cf74dd294640054ef5fa8596 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Wed, 11 Sep 2019 20:19:14 +0800 Subject: [PATCH 23/58] test for user close problem --- lib/mux/conn.go | 3 ++- lib/mux/mux.go | 20 ++++++++++++-------- lib/mux/mux_test.go | 28 +++++++++++++++++++--------- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 08b0db0..8f9f3ec 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -52,6 +52,7 @@ func NewConn(connId int32, mux *Mux) *conn { } func (s *conn) Read(buf []byte) (n int, err error) { + logs.Warn("starting conn read", s.connId) if s.isClose || buf == nil { return 0, errors.New("the conn has closed") } @@ -315,7 +316,7 @@ func (Self *window) allowRead() (closed bool) { } func (Self *window) Read(p []byte) (n int, err error) { - //logs.Warn("starting window read method len ", Self.len()) + logs.Warn("starting window read method len ", Self.len()) if Self.closeOp { return 0, io.EOF // Write method receive close signal, returns eof } diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 9310c64..5ad43c4 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -179,12 +179,14 @@ func (s *Mux) readSession() { switch pack.Flag { case common.MUX_NEW_CONN: //new connection logs.Warn("rec mux new connection", pack.Id) - conn := NewConn(pack.Id, s) - s.connMap.Set(pack.Id, conn) //it has been set before send ok - s.newConnCh <- conn - go conn.sendWindow.SetAllowSize(512) // set the initial receive window - s.sendInfo(common.MUX_NEW_CONN_OK, pack.Id, nil) - logs.Warn("send mux new connection ok", pack.Id) + connection := NewConn(pack.Id, s) + s.connMap.Set(pack.Id, connection) //it has been set before send ok + go func(connection *conn) { + connection.sendWindow.SetAllowSize(512) // set the initial receive window + }(connection) + s.newConnCh <- connection + s.sendInfo(common.MUX_NEW_CONN_OK, connection.connId, nil) + logs.Warn("send mux new connection ok", connection.connId) continue case common.MUX_PING_FLAG: //ping //logs.Warn("send mux ping return") @@ -202,7 +204,7 @@ func (s *Mux) readSession() { continue } connection.receiveWindow.WriteWg.Add(1) - logs.Warn("rec mux new msg ", pack.Id, string(pack.Content[0:15])) + logs.Warn("rec mux new msg ", connection.connId, string(pack.Content[0:15])) go func(connection *conn, content []byte) { // do not block read session _, err := connection.receiveWindow.Write(content) if err != nil { @@ -214,7 +216,7 @@ func (s *Mux) readSession() { connection.receiveWindow.WindowFull = true } s.sendInfo(common.MUX_MSG_SEND_OK, connection.connId, size) - logs.Warn("send mux new msg ok", pack.Id, size) + logs.Warn("send mux new msg ok", connection.connId, size) connection.receiveWindow.WriteWg.Done() }(connection, pack.Content) continue @@ -241,7 +243,9 @@ func (s *Mux) readSession() { s.connMap.Delete(pack.Id) connection.closeFlag = true go func(connection *conn) { + logs.Warn("receive mux connection close, wg waiting", connection.connId) connection.receiveWindow.WriteWg.Wait() + logs.Warn("receive mux connection close, wg waited", connection.connId) connection.receiveWindow.WriteEndOp <- struct{}{} // close signal to receive window logs.Warn("receive mux connection close, finish", connection.connId) }(connection) diff --git a/lib/mux/mux_test.go b/lib/mux/mux_test.go index 7c75c10..91e0fc6 100644 --- a/lib/mux/mux_test.go +++ b/lib/mux/mux_test.go @@ -6,6 +6,7 @@ import ( "net" "net/http" _ "net/http/pprof" + "sync" "testing" "time" ) @@ -37,20 +38,29 @@ func TestNewMux(t *testing.T) { logs.Warn(err) continue } + wg := sync.WaitGroup{} + wg.Add(1) go func() { _, err = common.CopyBuffer(c2, c) if err != nil { - logs.Warn("close npc by copy from nps", err) c2.Close() c.Close() + logs.Warn("close npc by copy from nps", err) } + wg.Done() }() - _, err = common.CopyBuffer(c, c2) - if err != nil { - logs.Warn("close npc by copy from server", err) - c2.Close() - c.Close() - } + wg.Add(1) + go func() { + _, err = common.CopyBuffer(c, c2) + if err != nil { + c2.Close() + c.Close() + logs.Warn("close npc by copy from server", err) + } + wg.Done() + }() + logs.Warn("npc wait") + wg.Wait() } }() @@ -77,17 +87,17 @@ func TestNewMux(t *testing.T) { go func() { _, err := common.CopyBuffer(tmpCpnn, conn) if err != nil { - logs.Warn("close nps by copy from user", tmpCpnn.connId) conn.Close() tmpCpnn.Close() + logs.Warn("close nps by copy from user", tmpCpnn.connId) } }() //time.Sleep(time.Second) _, err = common.CopyBuffer(conn, tmpCpnn) if err != nil { - logs.Warn("close nps by copy from npc ", tmpCpnn.connId) conn.Close() tmpCpnn.Close() + logs.Warn("close nps by copy from npc ", tmpCpnn.connId) } } }() From a05995fba5286fba6ccd77ce7a2e170016a1e487 Mon Sep 17 00:00:00 2001 From: zhangwei Date: Thu, 12 Sep 2019 08:22:12 +0800 Subject: [PATCH 24/58] new feature multi user auth with socks5 --- bridge/bridge.go | 1 + lib/config/config.go | 5 ++--- lib/file/obj.go | 15 +++++++++------ server/proxy/socks5.go | 6 +++--- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/bridge/bridge.go b/bridge/bridge.go index 3247dd8..0b613ab 100755 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -488,6 +488,7 @@ loop: tl.Password = t.Password tl.LocalPath = t.LocalPath tl.StripPre = t.StripPre + tl.MultiUser = t.MultiUser if !client.HasTunnel(tl) { if err := file.GetDb().NewTask(tl); err != nil { logs.Notice("Add task error ", err.Error()) diff --git a/lib/config/config.go b/lib/config/config.go index 9ab4b6c..47290be 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -240,15 +240,14 @@ func dealTunnel(s string) *file.Tunnel { case "strip_pre": t.StripPre = item[1] case "multi_user": - // TODO add test with multi user config file - t.Client.Cnf.MultiUser = true + t.MultiUser = new(file.MultiUser) if b, err := common.ReadAllFromFile(item[1]); err != nil { panic(err) } else { if content, err := common.ParseStr(string(b)); err != nil { panic(err) } else { - t.Client.Cnf.MultiUserMap = dealMultiUser(content) + t.MultiUser.UserMap = dealMultiUser(content) } } } diff --git a/lib/file/obj.go b/lib/file/obj.go index 2215968..424b727 100644 --- a/lib/file/obj.go +++ b/lib/file/obj.go @@ -25,12 +25,10 @@ func (s *Flow) Add(in, out int64) { } type Config struct { - U string - P string - Compress bool - Crypt bool - MultiUser bool // enable multi user authentication. - MultiUserMap map[string]string // multi user and pwd + U string + P string + Compress bool + Crypt bool } type Client struct { @@ -142,6 +140,7 @@ type Tunnel struct { LocalPath string StripPre string Target *Target + MultiUser *MultiUser Health sync.RWMutex } @@ -186,6 +185,10 @@ type Target struct { sync.RWMutex } +type MultiUser struct { + UserMap map[string]string // multi user and pwd +} + func (s *Target) GetRandomTarget() (string, error) { if s.TargetArr == nil { s.TargetArr = strings.Split(s.TargetStr, "\n") diff --git a/server/proxy/socks5.go b/server/proxy/socks5.go index d6c6ec6..a195693 100755 --- a/server/proxy/socks5.go +++ b/server/proxy/socks5.go @@ -199,7 +199,7 @@ func (s *Sock5ModeServer) handleConn(c net.Conn) { c.Close() return } - if (s.task.Client.Cnf.U != "" && s.task.Client.Cnf.P != "") || (s.task.Client.Cnf.MultiUser && len(s.task.Client.Cnf.MultiUserMap) > 0) { + if (s.task.Client.Cnf.U != "" && s.task.Client.Cnf.P != "") || (s.task.MultiUser != nil && len(s.task.MultiUser.UserMap) > 0) { buf[1] = UserPassAuth c.Write(buf) if err := s.Auth(c); err != nil { @@ -238,11 +238,11 @@ func (s *Sock5ModeServer) Auth(c net.Conn) error { } var U, P string - if s.task.Client.Cnf.MultiUser { + if s.task.MultiUser != nil { // enable multi user auth U = string(user) var ok bool - P, ok = s.task.Client.Cnf.MultiUserMap[U] + P, ok = s.task.MultiUser.UserMap[U] if !ok { return errors.New("验证不通过") } From 11d185ad59c70b07f96234fb7ec945bd31b1ae6a Mon Sep 17 00:00:00 2001 From: zhangwei Date: Thu, 12 Sep 2019 22:54:53 +0800 Subject: [PATCH 25/58] new feature multi user auth with socks5 --- bridge/bridge.go | 2 +- lib/config/config.go | 6 +++--- lib/file/obj.go | 38 +++++++++++++++++++------------------- server/proxy/socks5.go | 6 +++--- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/bridge/bridge.go b/bridge/bridge.go index 0b613ab..2340e56 100755 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -488,7 +488,7 @@ loop: tl.Password = t.Password tl.LocalPath = t.LocalPath tl.StripPre = t.StripPre - tl.MultiUser = t.MultiUser + tl.MultiAccount = t.MultiAccount if !client.HasTunnel(tl) { if err := file.GetDb().NewTask(tl); err != nil { logs.Notice("Add task error ", err.Error()) diff --git a/lib/config/config.go b/lib/config/config.go index 47290be..89a6bfd 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -239,15 +239,15 @@ func dealTunnel(s string) *file.Tunnel { t.LocalPath = item[1] case "strip_pre": t.StripPre = item[1] - case "multi_user": - t.MultiUser = new(file.MultiUser) + case "multi_account": + t.MultiAccount = &file.MultiAccount{} if b, err := common.ReadAllFromFile(item[1]); err != nil { panic(err) } else { if content, err := common.ParseStr(string(b)); err != nil { panic(err) } else { - t.MultiUser.UserMap = dealMultiUser(content) + t.MultiAccount.AccountMap = dealMultiUser(content) } } } diff --git a/lib/file/obj.go b/lib/file/obj.go index 424b727..15dea37 100644 --- a/lib/file/obj.go +++ b/lib/file/obj.go @@ -124,23 +124,23 @@ func (s *Client) HasHost(h *Host) bool { } type Tunnel struct { - Id int - Port int - ServerIp string - Mode string - Status bool - RunStatus bool - Client *Client - Ports string - Flow *Flow - Password string - Remark string - TargetAddr string - NoStore bool - LocalPath string - StripPre string - Target *Target - MultiUser *MultiUser + Id int + Port int + ServerIp string + Mode string + Status bool + RunStatus bool + Client *Client + Ports string + Flow *Flow + Password string + Remark string + TargetAddr string + NoStore bool + LocalPath string + StripPre string + Target *Target + MultiAccount *MultiAccount Health sync.RWMutex } @@ -185,8 +185,8 @@ type Target struct { sync.RWMutex } -type MultiUser struct { - UserMap map[string]string // multi user and pwd +type MultiAccount struct { + AccountMap map[string]string // multi account and pwd } func (s *Target) GetRandomTarget() (string, error) { diff --git a/server/proxy/socks5.go b/server/proxy/socks5.go index a195693..d79be72 100755 --- a/server/proxy/socks5.go +++ b/server/proxy/socks5.go @@ -199,7 +199,7 @@ func (s *Sock5ModeServer) handleConn(c net.Conn) { c.Close() return } - if (s.task.Client.Cnf.U != "" && s.task.Client.Cnf.P != "") || (s.task.MultiUser != nil && len(s.task.MultiUser.UserMap) > 0) { + if (s.task.Client.Cnf.U != "" && s.task.Client.Cnf.P != "") || (s.task.MultiAccount != nil && len(s.task.MultiAccount.AccountMap) > 0) { buf[1] = UserPassAuth c.Write(buf) if err := s.Auth(c); err != nil { @@ -238,11 +238,11 @@ func (s *Sock5ModeServer) Auth(c net.Conn) error { } var U, P string - if s.task.MultiUser != nil { + if s.task.MultiAccount != nil { // enable multi user auth U = string(user) var ok bool - P, ok = s.task.MultiUser.UserMap[U] + P, ok = s.task.MultiAccount.AccountMap[U] if !ok { return errors.New("验证不通过") } From 6157b1a5281ceb4abbb1f597923413abfaf6bb43 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Sun, 15 Sep 2019 15:02:10 +0800 Subject: [PATCH 26/58] fix block problems --- lib/mux/conn.go | 120 +++++++++++++++++++++++------------------------- lib/mux/mux.go | 44 +++++++++--------- 2 files changed, 80 insertions(+), 84 deletions(-) diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 8f9f3ec..be73e5c 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -17,22 +17,15 @@ type conn struct { connStatusFailCh chan struct{} readTimeOut time.Time writeTimeOut time.Time - //readBuffer []byte - //startRead int //now read position - //endRead int //now end read - //readFlag bool - //readCh chan struct{} - //readQueue *sliceEntry - //stopWrite bool - connId int32 - isClose bool - //readWait bool - closeFlag bool // close conn flag - hasWrite int - receiveWindow *window - sendWindow *window - mux *Mux - once sync.Once + connId int32 + isClose bool + closeFlag bool // close conn flag + receiveWindow *window + sendWindow *window + readCh waitingCh + writeCh waitingCh + mux *Mux + once sync.Once } func NewConn(connId int32, mux *Mux) *conn { @@ -48,34 +41,32 @@ func NewConn(connId int32, mux *Mux) *conn { } c.receiveWindow.NewReceive() c.sendWindow.NewSend() + c.readCh.new() + c.writeCh.new() return c } func (s *conn) Read(buf []byte) (n int, err error) { - logs.Warn("starting conn read", s.connId) + //logs.Warn("starting conn read", s.connId) if s.isClose || buf == nil { return 0, errors.New("the conn has closed") } - nCh := make(chan int) - errCh := make(chan error) - defer close(nCh) - defer close(errCh) // waiting for takeout from receive window finish or timeout - go s.readWindow(buf, nCh, errCh) + go s.readWindow(buf, s.readCh.nCh, s.readCh.errCh) if t := s.readTimeOut.Sub(time.Now()); t > 0 { timer := time.NewTimer(t) defer timer.Stop() select { case <-timer.C: return 0, errors.New("read timeout") - case n = <-nCh: - err = <-errCh + case n = <-s.readCh.nCh: + err = <-s.readCh.errCh } } else { - n = <-nCh - err = <-errCh + n = <-s.readCh.nCh + err = <-s.readCh.errCh } - logs.Warn("read window finish conn read n err buf", n, err, string(buf[:15])) + //logs.Warn("read window finish conn read n err buf", n, err, string(buf[:15])) return } @@ -97,21 +88,19 @@ func (s *conn) readWindow(buf []byte, nCh chan int, errCh chan error) { } func (s *conn) Write(buf []byte) (n int, err error) { + //logs.Warn("write starting", s.connId) + //defer logs.Warn("write end ", s.connId) if s.isClose { return 0, errors.New("the conn has closed") } if s.closeFlag { - logs.Warn("conn close by write ", s.connId) + //logs.Warn("conn close by write ", s.connId) //s.Close() return 0, errors.New("io: write on closed conn") } - - nCh := make(chan int) - errCh := make(chan error) - defer close(nCh) - defer close(errCh) s.sendWindow.SetSendBuf(buf) // set the buf to send window - go s.write(nCh, errCh) + //logs.Warn("write set send buf success") + go s.write(s.writeCh.nCh, s.writeCh.errCh) // waiting for send to other side or timeout if t := s.writeTimeOut.Sub(time.Now()); t > 0 { timer := time.NewTimer(t) @@ -119,12 +108,12 @@ func (s *conn) Write(buf []byte) (n int, err error) { select { case <-timer.C: return 0, errors.New("write timeout") - case n = <-nCh: - err = <-errCh + case n = <-s.writeCh.nCh: + err = <-s.writeCh.errCh } } else { - n = <-nCh - err = <-errCh + n = <-s.writeCh.nCh + err = <-s.writeCh.errCh } return } @@ -160,7 +149,7 @@ func (s *conn) closeProcess() { s.isClose = true s.mux.connMap.Delete(s.connId) if !s.mux.IsClose { - logs.Warn("conn send close", s.connId) + //logs.Warn("conn send close", s.connId) // if server or user close the conn while reading, will get a io.EOF // and this Close method will be invoke, send this signal to close other side s.mux.sendInfo(common.MUX_CONN_CLOSE, s.connId, nil) @@ -198,7 +187,6 @@ type window struct { windowBuff []byte off uint16 readOp chan struct{} - readWait bool WindowFull bool usableReceiveWindow chan uint16 WriteWg sync.WaitGroup @@ -213,13 +201,13 @@ func (Self *window) NewReceive() { Self.windowBuff = common.WindowBuff.Get() Self.readOp = make(chan struct{}) Self.WriteEndOp = make(chan struct{}) - Self.closeOpCh = make(chan struct{}, 2) + Self.closeOpCh = make(chan struct{}, 3) } func (Self *window) NewSend() { // initial a window for send Self.usableReceiveWindow = make(chan uint16) - Self.closeOpCh = make(chan struct{}, 2) + Self.closeOpCh = make(chan struct{}, 3) } func (Self *window) SetSendBuf(buf []byte) { @@ -269,38 +257,32 @@ func (Self *window) grow(n int) { func (Self *window) Write(p []byte) (n int, err error) { if Self.closeOp { - logs.Warn("window write closed len p", len(p)) return 0, errors.New("conn.receiveWindow: write on closed window") } if len(p) > Self.Size() { return 0, errors.New("conn.receiveWindow: write too large") } - if Self.readWait { - defer Self.allowRead() - } - //logs.Warn("window write p string", len(p), string(p[:15])) Self.mutex.Lock() // slide the offset if len(p) > Self.cap()-Self.len() { // not enough space, need to allocate Self.fullSlide() - //logs.Warn("window write full slide len cap", Self.len(), Self.cap()) } else { // have enough space, re slice Self.liteSlide() - //logs.Warn("window write lite slide len cap", Self.len(), Self.cap()) } length := Self.len() // length before grow Self.grow(len(p)) // grow for copy n = copy(Self.windowBuff[length:], p) // must copy data before allow Read - //logs.Warn("window write copy n len cap buf", n, Self.len(), Self.cap(), string(Self.windowBuff[Self.len()-n:Self.len()+15-n])) + if length == 0 { + // allow continue read + defer Self.allowRead() + } Self.mutex.Unlock() return n, nil } func (Self *window) allowRead() (closed bool) { - //logs.Warn("length 0 read op") - Self.readWait = false if Self.closeOp { close(Self.readOp) return true @@ -310,25 +292,25 @@ func (Self *window) allowRead() (closed bool) { close(Self.readOp) return true case Self.readOp <- struct{}{}: - //logs.Warn("length 0 read op finish") return false } } func (Self *window) Read(p []byte) (n int, err error) { - logs.Warn("starting window read method len ", Self.len()) if Self.closeOp { return 0, io.EOF // Write method receive close signal, returns eof } - if Self.len() == 0 { + Self.mutex.Lock() + length := Self.len() // protect the length data, it invokes + // before Write lock and after Write unlock + Self.mutex.Unlock() + if length == 0 { // window is empty, waiting for Write method send a success readOp signal // or get timeout or close - Self.readWait = true ticker := time.NewTicker(2 * time.Minute) defer ticker.Stop() select { case _, ok := <-Self.readOp: - //logs.Warn("read window read op len cap", Self.len(), Self.cap()) if !ok { return 0, errors.New("conn.receiveWindow: window closed") } @@ -341,19 +323,17 @@ func (Self *window) Read(p []byte) (n int, err error) { return 0, io.EOF // receive close signal, returns eof } } - //logs.Warn("window read start len window buff", Self.len(), string(Self.windowBuff[Self.off:Self.off+15])) Self.mutex.Lock() n = copy(p, Self.windowBuff[Self.off:]) Self.off += uint16(n) p = p[:n] - //logs.Warn("window read finish n len p p", n, len(p), string(p[:15])) Self.mutex.Unlock() return } func (Self *window) WriteTo() (p []byte, err error) { if Self.closeOp { - logs.Warn("window write to closed") + //logs.Warn("window write to closed") return nil, errors.New("conn.writeWindow: window closed") } if Self.len() == 0 { @@ -373,6 +353,8 @@ waiting: } case <-ticker.C: return nil, errors.New("conn.writeWindow: write to time out") + case <-Self.closeOpCh: + return nil, errors.New("conn.writeWindow: window closed") } if windowSize == 0 { goto waiting // waiting for another usable window size @@ -380,10 +362,8 @@ waiting: Self.mutex.Lock() if windowSize > uint16(Self.len()) { // usable window size is bigger than window buff size, send the full buff - //logs.Warn("window size overflow windowSize len()", windowSize, Self.len()) windowSize = uint16(Self.len()) } - //logs.Warn("window buff off windowSize", Self.off, windowSize) p = Self.windowBuff[Self.off : windowSize+Self.off] Self.off += windowSize Self.mutex.Unlock() @@ -413,6 +393,22 @@ func (Self *window) CloseWindow() { Self.closeOp = true Self.closeOpCh <- struct{}{} Self.closeOpCh <- struct{}{} + Self.closeOpCh <- struct{}{} close(Self.closeOpCh) return } + +type waitingCh struct { + nCh chan int + errCh chan error +} + +func (Self *waitingCh) new() { + Self.nCh = make(chan int) + Self.errCh = make(chan error) +} + +func (Self *waitingCh) close() { + close(Self.nCh) + close(Self.errCh) +} diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 5ad43c4..dd3dee2 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -53,7 +53,7 @@ func (s *Mux) NewConn() (*conn, error) { //it must be set before send s.connMap.Set(conn.connId, conn) s.sendInfo(common.MUX_NEW_CONN, conn.connId, nil) - logs.Warn("send mux new conn ", conn.connId) + //logs.Warn("send mux new conn ", conn.connId) //set a timer timeout 30 second timer := time.NewTimer(time.Minute * 2) defer timer.Stop() @@ -85,7 +85,7 @@ func (s *Mux) sendInfo(flag uint8, id int32, data interface{}) { var err error if flag == common.MUX_NEW_MSG { if len(data.([]byte)) == 0 { - logs.Warn("send info content is nil") + //logs.Warn("send info content is nil") } } buf := common.BuffPool.Get() @@ -94,18 +94,18 @@ func (s *Mux) sendInfo(flag uint8, id int32, data interface{}) { defer common.MuxPack.Put(pack) err = pack.NewPac(flag, id, data) if err != nil { - logs.Warn("new pack err", err) + //logs.Warn("new pack err", err) common.BuffPool.Put(buf) return } err = pack.Pack(buf) if err != nil { - logs.Warn("pack err", err) + //logs.Warn("pack err", err) common.BuffPool.Put(buf) return } if pack.Flag == common.MUX_NEW_CONN { - logs.Warn("sendinfo mux new conn, insert to write queue", pack.Id) + //logs.Warn("sendinfo mux new conn, insert to write queue", pack.Id) } s.writeQueue <- buf //_, err = buf.WriteTo(s.conn) @@ -125,7 +125,7 @@ func (s *Mux) writeSession() { n, err := buf.WriteTo(s.conn) common.BuffPool.Put(buf) if err != nil || int(n) != l { - logs.Warn("close from write session fail ", err, n, l) + //logs.Warn("close from write session fail ", err, n, l) s.Close() break } @@ -173,12 +173,12 @@ func (s *Mux) readSession() { } } if pack.Flag == common.MUX_NEW_CONN { - logs.Warn("unpack mux new connection", pack.Id) + //logs.Warn("unpack mux new connection", pack.Id) } s.pingOk = 0 switch pack.Flag { case common.MUX_NEW_CONN: //new connection - logs.Warn("rec mux new connection", pack.Id) + //logs.Warn("rec mux new connection", pack.Id) connection := NewConn(pack.Id, s) s.connMap.Set(pack.Id, connection) //it has been set before send ok go func(connection *conn) { @@ -186,7 +186,7 @@ func (s *Mux) readSession() { }(connection) s.newConnCh <- connection s.sendInfo(common.MUX_NEW_CONN_OK, connection.connId, nil) - logs.Warn("send mux new connection ok", connection.connId) + //logs.Warn("send mux new connection ok", connection.connId) continue case common.MUX_PING_FLAG: //ping //logs.Warn("send mux ping return") @@ -204,61 +204,61 @@ func (s *Mux) readSession() { continue } connection.receiveWindow.WriteWg.Add(1) - logs.Warn("rec mux new msg ", connection.connId, string(pack.Content[0:15])) + //logs.Warn("rec mux new msg ", connection.connId, string(pack.Content[0:15])) go func(connection *conn, content []byte) { // do not block read session _, err := connection.receiveWindow.Write(content) if err != nil { logs.Warn("mux new msg err close", err) - s.Close() + connection.Close() } size := connection.receiveWindow.Size() if size == 0 { connection.receiveWindow.WindowFull = true } s.sendInfo(common.MUX_MSG_SEND_OK, connection.connId, size) - logs.Warn("send mux new msg ok", connection.connId, size) + //logs.Warn("send mux new msg ok", connection.connId, size) connection.receiveWindow.WriteWg.Done() }(connection, pack.Content) continue case common.MUX_NEW_CONN_OK: //connection ok - logs.Warn("rec mux new connection ok ", pack.Id) + //logs.Warn("rec mux new connection ok ", pack.Id) connection.connStatusOkCh <- struct{}{} go connection.sendWindow.SetAllowSize(512) // set the initial receive window both side continue case common.MUX_NEW_CONN_Fail: - logs.Warn("rec mux new connection fail", pack.Id) + //logs.Warn("rec mux new connection fail", pack.Id) connection.connStatusFailCh <- struct{}{} continue case common.MUX_MSG_SEND_OK: if connection.isClose { - logs.Warn("rec mux msg send ok id window closed!", pack.Id, pack.Window) + //logs.Warn("rec mux msg send ok id window closed!", pack.Id, pack.Window) continue } - logs.Warn("rec mux msg send ok id window", pack.Id, pack.Window) + //logs.Warn("rec mux msg send ok id window", pack.Id, pack.Window) go connection.sendWindow.SetAllowSize(pack.Window) continue case common.MUX_CONN_CLOSE: //close the connection - logs.Warn("rec mux connection close", pack.Id) + //logs.Warn("rec mux connection close", pack.Id) s.connMap.Delete(pack.Id) connection.closeFlag = true go func(connection *conn) { - logs.Warn("receive mux connection close, wg waiting", connection.connId) + //logs.Warn("receive mux connection close, wg waiting", connection.connId) connection.receiveWindow.WriteWg.Wait() - logs.Warn("receive mux connection close, wg waited", connection.connId) + //logs.Warn("receive mux connection close, wg waited", connection.connId) connection.receiveWindow.WriteEndOp <- struct{}{} // close signal to receive window - logs.Warn("receive mux connection close, finish", connection.connId) + //logs.Warn("receive mux connection close, finish", connection.connId) }(connection) continue } } else if pack.Flag == common.MUX_CONN_CLOSE { - logs.Warn("rec mux connection close no id ", pack.Id) + //logs.Warn("rec mux connection close no id ", pack.Id) continue } common.MuxPack.Put(pack) } common.MuxPack.Put(pack) - logs.Warn("read session put pack ", pack.Id) + //logs.Warn("read session put pack ", pack.Id) s.Close() }() select { From d4a6560d9a1463c143e455be734e3755f5dc29b2 Mon Sep 17 00:00:00 2001 From: zhangwei Date: Sun, 15 Sep 2019 20:35:21 +0800 Subject: [PATCH 27/58] new feature multi user auth with socks5 --- README.md | 2 ++ conf/multi_account.conf | 2 ++ conf/multiuser.conf | 0 conf/npc.conf | 1 + 4 files changed, 5 insertions(+) create mode 100644 conf/multi_account.conf delete mode 100644 conf/multiuser.conf diff --git a/README.md b/README.md index 1dd7f77..f46d48a 100644 --- a/README.md +++ b/README.md @@ -538,11 +538,13 @@ vkey=123 [socks5] mode=socks5 server_port=9004 +multi_account=multi_account.conf ``` 项 | 含义 ---|--- mode | socks5 server_port | 在服务端的代理端口 +multi_account | socks5多账号配置文件(可选) ##### 私密代理模式 ```ini diff --git a/conf/multi_account.conf b/conf/multi_account.conf new file mode 100644 index 0000000..e3cd792 --- /dev/null +++ b/conf/multi_account.conf @@ -0,0 +1,2 @@ +# key -> user | value -> pwd +npc=npc.pwd \ No newline at end of file diff --git a/conf/multiuser.conf b/conf/multiuser.conf deleted file mode 100644 index e69de29..0000000 diff --git a/conf/npc.conf b/conf/npc.conf index d4a31a8..03a684e 100644 --- a/conf/npc.conf +++ b/conf/npc.conf @@ -40,6 +40,7 @@ server_port=10000 [socks5] mode=socks5 server_port=19009 +multi_account=multi_account.conf # 多账户配置文件,配置及代表启动多账户 [file] mode=file From 1bf4cf23478b43ee151a0408411cfb01211755bb Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Tue, 17 Sep 2019 19:05:04 +0800 Subject: [PATCH 28/58] fix conn write block, add priority queue support --- lib/mux/conn.go | 15 ++++- lib/mux/mux.go | 103 +++++++++++++++++++++------------- lib/mux/queue.go | 143 ++++++++++++++++++++++++++--------------------- 3 files changed, 156 insertions(+), 105 deletions(-) diff --git a/lib/mux/conn.go b/lib/mux/conn.go index be73e5c..81f876f 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -187,6 +187,7 @@ type window struct { windowBuff []byte off uint16 readOp chan struct{} + readWait bool WindowFull bool usableReceiveWindow chan uint16 WriteWg sync.WaitGroup @@ -274,7 +275,11 @@ func (Self *window) Write(p []byte) (n int, err error) { length := Self.len() // length before grow Self.grow(len(p)) // grow for copy n = copy(Self.windowBuff[length:], p) // must copy data before allow Read - if length == 0 { + if Self.readWait { + // if there condition is length == 0 and + // Read method just take away all the windowBuff, + // this method will block until windowBuff is empty again + // allow continue read defer Self.allowRead() } @@ -287,6 +292,9 @@ func (Self *window) allowRead() (closed bool) { close(Self.readOp) return true } + Self.mutex.Lock() + Self.readWait = false + Self.mutex.Unlock() select { case <-Self.closeOpCh: close(Self.readOp) @@ -303,10 +311,11 @@ func (Self *window) Read(p []byte) (n int, err error) { Self.mutex.Lock() length := Self.len() // protect the length data, it invokes // before Write lock and after Write unlock - Self.mutex.Unlock() if length == 0 { // window is empty, waiting for Write method send a success readOp signal // or get timeout or close + Self.readWait = true + Self.mutex.Unlock() ticker := time.NewTicker(2 * time.Minute) defer ticker.Stop() select { @@ -322,6 +331,8 @@ func (Self *window) Read(p []byte) (n int, err error) { close(Self.readOp) return 0, io.EOF // receive close signal, returns eof } + } else { + Self.mutex.Unlock() } Self.mutex.Lock() n = copy(p, Self.windowBuff[Self.off:]) diff --git a/lib/mux/mux.go b/lib/mux/mux.go index dd3dee2..f4bc6fa 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -22,21 +22,23 @@ type Mux struct { IsClose bool pingOk int connType string - writeQueue chan *bytes.Buffer + writeQueue Queue + bufCh chan *bytes.Buffer sync.Mutex } func NewMux(c net.Conn, connType string) *Mux { m := &Mux{ - conn: c, - connMap: NewConnMap(), - id: 0, - closeChan: make(chan struct{}), - newConnCh: make(chan *conn), - IsClose: false, - connType: connType, - writeQueue: make(chan *bytes.Buffer, 20), + conn: c, + connMap: NewConnMap(), + id: 0, + closeChan: make(chan struct{}), + newConnCh: make(chan *conn), + IsClose: false, + connType: connType, + bufCh: make(chan *bytes.Buffer), } + m.writeQueue.New() //read session by flag go m.readSession() //ping @@ -88,26 +90,27 @@ func (s *Mux) sendInfo(flag uint8, id int32, data interface{}) { //logs.Warn("send info content is nil") } } - buf := common.BuffPool.Get() + //buf := common.BuffPool.Get() //defer pool.BuffPool.Put(buf) pack := common.MuxPack.Get() - defer common.MuxPack.Put(pack) + err = pack.NewPac(flag, id, data) if err != nil { //logs.Warn("new pack err", err) - common.BuffPool.Put(buf) + common.MuxPack.Put(pack) return } - err = pack.Pack(buf) - if err != nil { - //logs.Warn("pack err", err) - common.BuffPool.Put(buf) - return - } - if pack.Flag == common.MUX_NEW_CONN { - //logs.Warn("sendinfo mux new conn, insert to write queue", pack.Id) - } - s.writeQueue <- buf + s.writeQueue.Push(pack) + //err = pack.Pack(buf) + //if err != nil { + // //logs.Warn("pack err", err) + // common.BuffPool.Put(buf) + // return + //} + //if pack.Flag == common.MUX_NEW_CONN { + // //logs.Warn("sendinfo mux new conn, insert to write queue", pack.Id) + //} + //s.writeQueue <- buf //_, err = buf.WriteTo(s.conn) //if err != nil { // s.Close() @@ -118,20 +121,47 @@ func (s *Mux) sendInfo(flag uint8, id int32, data interface{}) { } func (s *Mux) writeSession() { - go func() { - for { - buf := <-s.writeQueue - l := buf.Len() - n, err := buf.WriteTo(s.conn) - common.BuffPool.Put(buf) + go s.packBuf() + go s.writeBuf() + <-s.closeChan +} + +func (s *Mux) packBuf() { + for { + pack := s.writeQueue.Pop() + buffer := common.BuffPool.Get() + err := pack.Pack(buffer) + common.MuxPack.Put(pack) + if err != nil { + logs.Warn("pack err", err) + common.BuffPool.Put(buffer) + break + } + select { + case s.bufCh <- buffer: + case <-s.closeChan: + break + } + + } +} + +func (s *Mux) writeBuf() { + for { + select { + case buffer := <-s.bufCh: + l := buffer.Len() + n, err := buffer.WriteTo(s.conn) + common.BuffPool.Put(buffer) if err != nil || int(n) != l { - //logs.Warn("close from write session fail ", err, n, l) + logs.Warn("close from write session fail ", err, n, l) s.Close() break } + case <-s.closeChan: + break } - }() - <-s.closeChan + } } func (s *Mux) ping() { @@ -273,14 +303,11 @@ func (s *Mux) Close() error { } s.IsClose = true s.connMap.Close() - select { - case s.closeChan <- struct{}{}: - } - select { - case s.closeChan <- struct{}{}: - } s.closeChan <- struct{}{} - close(s.writeQueue) + s.closeChan <- struct{}{} + s.closeChan <- struct{}{} + s.closeChan <- struct{}{} + s.closeChan <- struct{}{} close(s.newConnCh) return s.conn.Close() } diff --git a/lib/mux/queue.go b/lib/mux/queue.go index 4388fb6..081b2c9 100644 --- a/lib/mux/queue.go +++ b/lib/mux/queue.go @@ -1,82 +1,95 @@ package mux import ( - "errors" + "container/list" "github.com/cnlh/nps/lib/common" "sync" ) -type Element *bufNode - -type bufNode struct { - val []byte //buf value - l int //length +type Queue struct { + list *list.List + readOp chan struct{} + cleanOp chan struct{} + popWait bool + mutex sync.Mutex } -func NewBufNode(buf []byte, l int) *bufNode { - return &bufNode{ - val: buf, - l: l, +func (Self *Queue) New() { + Self.list = list.New() + Self.readOp = make(chan struct{}) + Self.cleanOp = make(chan struct{}, 2) +} + +func (Self *Queue) Push(packager *common.MuxPackager) { + Self.mutex.Lock() + if Self.popWait { + defer Self.allowPop() } -} - -type Queue interface { - Push(e Element) //向队列中添加元素 - Pop() Element //移除队列中最前面的元素 - Clear() bool //清空队列 - Size() int //获取队列的元素个数 - IsEmpty() bool //判断队列是否是空 -} - -type sliceEntry struct { - element []Element - sync.Mutex -} - -func NewQueue() *sliceEntry { - return &sliceEntry{} -} - -//向队列中添加元素 -func (entry *sliceEntry) Push(e Element) { - entry.Lock() - defer entry.Unlock() - entry.element = append(entry.element, e) -} - -//移除队列中最前面的额元素 -func (entry *sliceEntry) Pop() (Element, error) { - if entry.IsEmpty() { - return nil, errors.New("queue is empty!") + if packager.Flag == common.MUX_CONN_CLOSE { + Self.insert(packager) // the close package may need priority, + // prevent wait too long to close + } else { + Self.list.PushBack(packager) } - entry.Lock() - defer entry.Unlock() - firstElement := entry.element[0] - entry.element = entry.element[1:] - return firstElement, nil + Self.mutex.Unlock() + return } -func (entry *sliceEntry) Clear() bool { - entry.Lock() - defer entry.Unlock() - if entry.IsEmpty() { +func (Self *Queue) allowPop() (closed bool) { + Self.mutex.Lock() + Self.popWait = false + Self.mutex.Unlock() + select { + case Self.readOp <- struct{}{}: return false - } - for i := 0; i < entry.Size(); i++ { - common.CopyBuff.Put(entry.element[i].val) - entry.element[i] = nil - } - entry.element = nil - return true -} - -func (entry *sliceEntry) Size() int { - return len(entry.element) -} - -func (entry *sliceEntry) IsEmpty() bool { - if len(entry.element) == 0 { + case <-Self.cleanOp: return true } - return false +} + +func (Self *Queue) insert(packager *common.MuxPackager) { + element := Self.list.Back() + for { + if element == nil { // Queue dose not have any of msg package with this close package id + Self.list.PushFront(packager) // insert close package to first + break + } + if element.Value.(*common.MuxPackager).Flag == common.MUX_NEW_MSG && + element.Value.(*common.MuxPackager).Id == packager.Id { + Self.list.InsertAfter(packager, element) // Queue has some msg package + // with this close package id, insert close package after last msg package + break + } + element = element.Prev() + } +} + +func (Self *Queue) Pop() (packager *common.MuxPackager) { + Self.mutex.Lock() + element := Self.list.Front() + if element != nil { + packager = element.Value.(*common.MuxPackager) + Self.list.Remove(element) + Self.mutex.Unlock() + return + } + Self.popWait = true // Queue is empty, notice Push method + Self.mutex.Unlock() + select { + case <-Self.readOp: + return Self.Pop() + case <-Self.cleanOp: + return nil + } +} + +func (Self *Queue) Len() (n int) { + n = Self.list.Len() + return +} + +func (Self *Queue) Clean() { + Self.cleanOp <- struct{}{} + Self.cleanOp <- struct{}{} + close(Self.cleanOp) } From af8d4a8c12fccf95329e85fda92ce391cb753656 Mon Sep 17 00:00:00 2001 From: he2 Date: Thu, 19 Sep 2019 09:17:32 +0800 Subject: [PATCH 29/58] fix: close health check tcp connection --- client/health.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/client/health.go b/client/health.go index ff2338f..12e35d9 100644 --- a/client/health.go +++ b/client/health.go @@ -2,15 +2,16 @@ package client import ( "container/heap" + "net" + "net/http" + "strings" + "time" + "github.com/cnlh/nps/lib/conn" "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/lib/sheap" "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "github.com/pkg/errors" - "net" - "net/http" - "strings" - "time" ) var isStart bool @@ -70,7 +71,11 @@ func check(t *file.Health) { var rs *http.Response for _, v := range arr { if t.HealthCheckType == "tcp" { - _, err = net.DialTimeout("tcp", v, time.Duration(t.HealthCheckTimeout)*time.Second); + var c net.Conn + c, err = net.DialTimeout("tcp", v, time.Duration(t.HealthCheckTimeout)*time.Second) + if err == nil { + c.Close() + } } else { client := &http.Client{} client.Timeout = time.Duration(t.HealthCheckTimeout) * time.Second From ee50a67f030e96c85a9eed33b9f95962b65e0b2d Mon Sep 17 00:00:00 2001 From: zhangwei Date: Thu, 19 Sep 2019 21:16:47 +0800 Subject: [PATCH 30/58] new feature multi user auth with socks5 --- conf/npc.conf | 2 +- go.mod | 9 ++++++--- go.sum | 26 +++++++++++++++++--------- npc.conf | 21 --------------------- 4 files changed, 24 insertions(+), 34 deletions(-) delete mode 100644 npc.conf diff --git a/conf/npc.conf b/conf/npc.conf index 03a684e..b3dccdb 100644 --- a/conf/npc.conf +++ b/conf/npc.conf @@ -40,7 +40,7 @@ server_port=10000 [socks5] mode=socks5 server_port=19009 -multi_account=multi_account.conf # 多账户配置文件,配置及代表启动多账户 +multi_account=multi_account.conf [file] mode=file diff --git a/go.mod b/go.mod index e8111a1..1f6b753 100644 --- a/go.mod +++ b/go.mod @@ -5,20 +5,23 @@ go 1.12 require ( github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/astaxie/beego v1.12.0 + github.com/belogik/goes v0.0.0-20151229125003-e54d722c3aff // indirect github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d github.com/go-ole/go-ole v1.2.4 // indirect github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db github.com/klauspost/cpuid v1.2.1 // indirect - github.com/klauspost/reedsolomon v1.9.2 // indirect + github.com/klauspost/reedsolomon v1.9.2 + github.com/onsi/gomega v1.5.0 // indirect github.com/pkg/errors v0.8.0 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect github.com/shirou/gopsutil v2.18.12+incompatible github.com/stretchr/testify v1.3.0 // indirect github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect - github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b // indirect - github.com/tjfoc/gmsm v1.0.1 // indirect + github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b + github.com/tjfoc/gmsm v1.0.1 github.com/xtaci/kcp-go v5.4.4+incompatible github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect + golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa // indirect ) diff --git a/go.sum b/go.sum index a0396f9..d57b283 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,11 @@ github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM= -github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/astaxie/beego v1.12.0 h1:MRhVoeeye5N+Flul5PoVfD9CslfdoH+xqC/xvSQ5u2Y= +github.com/astaxie/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ= github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU= +github.com/belogik/goes v0.0.0-20151229125003-e54d722c3aff/go.mod h1:PhH1ZhyCzHKt4uAasyx+ljRCgoezetRNf59CUtwUkqY= github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d h1:As4937T5NVbJ/DmZT9z33pyLEprMd6CUSfhbmMY57Io= @@ -13,31 +15,34 @@ github.com/couchbase/go-couchbase v0.0.0-20181122212707-3e9b6e1258bb/go.mod h1:T github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk= github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/exfly/beego v1.12.0-export-init h1:VQNYKdXhAwZGUaFmQv8Aj921O3rQJZRIF8xeGrhsjrI= github.com/exfly/beego v1.12.0-export-init/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= -github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= +github.com/exfly/beego v1.12.0 h1:OXwIwngaAx35Mga+jLiZmArusBxj8/H0jYXzGDAdwOg= +github.com/exfly/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/reedsolomon v1.9.2 h1:E9CMS2Pqbv+C7tsrYad4YC9MfhnMVWhMRsTi7U0UB18= github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo= github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= @@ -48,7 +53,6 @@ github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1Dp github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU= @@ -60,15 +64,19 @@ github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/ github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= github.com/xtaci/kcp-go v5.4.4+incompatible h1:QIJ0a0Q0N1G20yLHL2+fpdzyy2v/Cb3PI+xiwx/KK9c= github.com/xtaci/kcp-go v5.4.4+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= -github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI= golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= \ No newline at end of file diff --git a/npc.conf b/npc.conf deleted file mode 100644 index 63a8a37..0000000 --- a/npc.conf +++ /dev/null @@ -1,21 +0,0 @@ -[common] -server_addr=proxy.njcp.info:55000 -conn_type=tcp -vkey=%EEKn6q386JmCQC^ -auto_reconnection=true -max_conn=1000 -flow_limit=1000 -rate_limit=1000 -basic_username=bobanNanJing -basic_password=N^#xf407W%ZfOg$u -web_username=12 -web_password=12 -crypt=true -compress=true -username=bobanNanJing -password=0Ho@^#U&y571%cK* - - -[socks5] -mode=socks5 -server_port=19009 \ No newline at end of file From f0201c103926ad7c4054fcfac510df5eecd70c65 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Sun, 22 Sep 2019 22:08:51 +0800 Subject: [PATCH 31/58] change slide window --- lib/mux/conn.go | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 81f876f..b1141ee 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -66,7 +66,7 @@ func (s *conn) Read(buf []byte) (n int, err error) { n = <-s.readCh.nCh err = <-s.readCh.errCh } - //logs.Warn("read window finish conn read n err buf", n, err, string(buf[:15])) + //logs.Warn("read window finish conn read n err buf", n, err, string(buf[:15]), s.connId) return } @@ -115,6 +115,7 @@ func (s *conn) Write(buf []byte) (n int, err error) { n = <-s.writeCh.nCh err = <-s.writeCh.errCh } + //logs.Warn("write window finish n err buf id", n, err, string(buf[:15]), s.connId) return } func (s *conn) write(nCh chan int, errCh chan error) { @@ -334,11 +335,22 @@ func (Self *window) Read(p []byte) (n int, err error) { } else { Self.mutex.Unlock() } - Self.mutex.Lock() - n = copy(p, Self.windowBuff[Self.off:]) - Self.off += uint16(n) + minCopy := 512 + for { + Self.mutex.Lock() + if len(p) == n || Self.len() == 0 { + Self.mutex.Unlock() + break + } + if n+minCopy > len(p) { + minCopy = len(p) - n + } + i := copy(p[n:n+minCopy], Self.windowBuff[Self.off:]) + Self.off += uint16(i) + n += i + Self.mutex.Unlock() + } p = p[:n] - Self.mutex.Unlock() return } From a28d7319d8b2e8746cf5b094b858a52c3a6590fb Mon Sep 17 00:00:00 2001 From: zhangwei Date: Mon, 23 Sep 2019 16:33:42 +0800 Subject: [PATCH 32/58] optimizing readme for socks5 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f46d48a..d1b95af 100644 --- a/README.md +++ b/README.md @@ -544,7 +544,7 @@ multi_account=multi_account.conf ---|--- mode | socks5 server_port | 在服务端的代理端口 -multi_account | socks5多账号配置文件(可选) +multi_account | socks5多账号配置文件(可选),配置后使用basic_username和basic_password无法通过认证 ##### 私密代理模式 ```ini From 847f0ce1d495b642b531f61816c54b2c1bbded6a Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Mon, 23 Sep 2019 23:09:58 +0800 Subject: [PATCH 33/58] fix window write loss --- lib/mux/conn.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/mux/conn.go b/lib/mux/conn.go index b1141ee..3f824cc 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -223,10 +223,10 @@ func (Self *window) SetSendBuf(buf []byte) { func (Self *window) fullSlide() { // slide by allocate newBuf := common.WindowBuff.Get() - copy(newBuf[0:Self.len()], Self.windowBuff[Self.off:]) - Self.off = 0 + Self.liteSlide() + n := copy(newBuf[:Self.len()], Self.windowBuff) common.WindowBuff.Put(Self.windowBuff) - Self.windowBuff = newBuf + Self.windowBuff = newBuf[:n] return } From a61ff2d2008a7fbb8599cf1a6ab6b0a20c6548a4 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Tue, 24 Sep 2019 22:29:31 +0800 Subject: [PATCH 34/58] merge --- go.mod | 7 ++-- go.sum | 8 +++++ lib/common/netpackager.go | 3 -- lib/mux/conn.go | 1 - lib/mux/mux.go | 3 +- lib/mux/mux_test.go | 74 ++++++++++++++++++++------------------- 6 files changed, 51 insertions(+), 45 deletions(-) diff --git a/go.mod b/go.mod index 1f6b753..8a19eaf 100644 --- a/go.mod +++ b/go.mod @@ -10,18 +10,17 @@ require ( github.com/go-ole/go-ole v1.2.4 // indirect github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db github.com/klauspost/cpuid v1.2.1 // indirect - github.com/klauspost/reedsolomon v1.9.2 + github.com/klauspost/reedsolomon v1.9.2 // indirect github.com/onsi/gomega v1.5.0 // indirect github.com/pkg/errors v0.8.0 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect github.com/shirou/gopsutil v2.18.12+incompatible github.com/stretchr/testify v1.3.0 // indirect github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect - github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b - github.com/tjfoc/gmsm v1.0.1 + github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b // indirect + github.com/tjfoc/gmsm v1.0.1 // indirect github.com/xtaci/kcp-go v5.4.4+incompatible github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect - golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa // indirect ) diff --git a/go.sum b/go.sum index 29de132..f3a17f4 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,6 @@ github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/astaxie/beego v1.12.0 h1:MRhVoeeye5N+Flul5PoVfD9CslfdoH+xqC/xvSQ5u2Y= github.com/astaxie/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= @@ -15,14 +16,17 @@ github.com/couchbase/go-couchbase v0.0.0-20181122212707-3e9b6e1258bb/go.mod h1:T github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk= github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/exfly/beego v1.12.0-export-init h1:VQNYKdXhAwZGUaFmQv8Aj921O3rQJZRIF8xeGrhsjrI= github.com/exfly/beego v1.12.0-export-init/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= github.com/exfly/beego v1.12.0 h1:OXwIwngaAx35Mga+jLiZmArusBxj8/H0jYXzGDAdwOg= github.com/exfly/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -43,6 +47,7 @@ github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo= github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= @@ -53,6 +58,7 @@ github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1Dp github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU= @@ -64,6 +70,7 @@ github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/ github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= github.com/xtaci/kcp-go v5.4.4+incompatible h1:QIJ0a0Q0N1G20yLHL2+fpdzyy2v/Cb3PI+xiwx/KK9c= github.com/xtaci/kcp-go v5.4.4+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= +github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI= golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -75,6 +82,7 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= diff --git a/lib/common/netpackager.go b/lib/common/netpackager.go index f2ddaec..1129940 100644 --- a/lib/common/netpackager.go +++ b/lib/common/netpackager.go @@ -5,7 +5,6 @@ import ( "encoding/binary" "encoding/json" "errors" - "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs" "io" "strings" ) @@ -50,7 +49,6 @@ func (Self *BasePackager) appendByte(data []byte) (err error) { copy(Self.Content[m:n], data) return nil } else { - logs.Warn(len(data), len(Self.Content), cap(Self.Content)) return errors.New("pack content too large") } } @@ -74,7 +72,6 @@ func (Self *BasePackager) UnPack(reader io.Reader) (err error) { return } if int(Self.Length) > cap(Self.Content) { - logs.Warn("unpack", cap(Self.Content)) err = errors.New("unpack err, content length too large") } Self.Content = Self.Content[:int(Self.Length)] diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 23ba78d..bf9e0d6 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -70,7 +70,6 @@ func (s *conn) Read(buf []byte) (n int, err error) { func (s *conn) readWindow(buf []byte, nCh chan int, errCh chan error) { n, err := s.receiveWindow.Read(buf) - //logs.Warn("readwindow goroutine status n err buf", n, err, string(buf[:15])) if s.receiveWindow.WindowFull { if s.receiveWindow.Size() > 0 { // window.Read may be invoked before window.Write, and WindowFull flag change to true diff --git a/lib/mux/mux.go b/lib/mux/mux.go index f955233..a662ad0 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -9,6 +9,7 @@ import ( "sync/atomic" "time" + "github.com/astaxie/beego/logs" "github.com/cnlh/nps/lib/common" ) @@ -173,7 +174,7 @@ func (s *Mux) readSession() { s.pingOk = 0 switch pack.Flag { case common.MUX_NEW_CONN: //new connection - connection := NewConn(pack.Id, s) + connection := NewConn(pack.Id, s) s.connMap.Set(pack.Id, connection) //it has been set before send ok go func(connection *conn) { connection.sendWindow.SetAllowSize(512) // set the initial receive window diff --git a/lib/mux/mux_test.go b/lib/mux/mux_test.go index 5f5c990..c7b10e0 100644 --- a/lib/mux/mux_test.go +++ b/lib/mux/mux_test.go @@ -1,7 +1,6 @@ package mux import ( - "log" "net" "net/http" _ "net/http/pprof" @@ -11,7 +10,6 @@ import ( "github.com/astaxie/beego/logs" "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/pool" ) var conn1 net.Conn @@ -41,29 +39,31 @@ func TestNewMux(t *testing.T) { logs.Warn(err) continue } - wg := sync.WaitGroup{} - wg.Add(1) - go func() { - _, err = common.CopyBuffer(c2, c) - if err != nil { - c2.Close() - c.Close() - logs.Warn("close npc by copy from nps", err) - } - wg.Done() - }() - wg.Add(1) - go func() { - _, err = common.CopyBuffer(c, c2) - if err != nil { - c2.Close() - c.Close() - logs.Warn("close npc by copy from server", err) - } - wg.Done() - }() - logs.Warn("npc wait") - wg.Wait() + go func(c2 net.Conn, c net.Conn) { + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + _, err = common.CopyBuffer(c2, c) + if err != nil { + c2.Close() + c.Close() + logs.Warn("close npc by copy from nps", err) + } + wg.Done() + }() + wg.Add(1) + go func() { + _, err = common.CopyBuffer(c, c2) + if err != nil { + c2.Close() + c.Close() + logs.Warn("close npc by copy from server", err) + } + wg.Done() + }() + logs.Warn("npc wait") + wg.Wait() + }(c2, c) } }() @@ -87,21 +87,23 @@ func TestNewMux(t *testing.T) { continue } logs.Warn("nps new conn success ", tmpCpnn.connId) - go func() { - _, err := common.CopyBuffer(tmpCpnn, conn) + go func(tmpCpnn net.Conn, conn net.Conn) { + go func() { + _, err := common.CopyBuffer(tmpCpnn, conn) + if err != nil { + conn.Close() + tmpCpnn.Close() + logs.Warn("close nps by copy from user") + } + }() + //time.Sleep(time.Second) + _, err = common.CopyBuffer(conn, tmpCpnn) if err != nil { conn.Close() tmpCpnn.Close() - logs.Warn("close nps by copy from user", tmpCpnn.connId) + logs.Warn("close nps by copy from npc ") } - }() - //time.Sleep(time.Second) - _, err = common.CopyBuffer(conn, tmpCpnn) - if err != nil { - conn.Close() - tmpCpnn.Close() - logs.Warn("close nps by copy from npc ", tmpCpnn.connId) - } + }(tmpCpnn, conn) } }() From 8bcf5313f4d59175c835cb5dfe84d29dbe82c01d Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Wed, 25 Sep 2019 00:13:34 +0800 Subject: [PATCH 35/58] merge --- lib/conn/conn.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/conn/conn.go b/lib/conn/conn.go index 30e4cd6..7946c0d 100755 --- a/lib/conn/conn.go +++ b/lib/conn/conn.go @@ -6,13 +6,6 @@ import ( "encoding/binary" "encoding/json" "errors" - "github.com/cnlh/nps/lib/common" - "github.com/cnlh/nps/lib/crypt" - "github.com/cnlh/nps/lib/file" - "github.com/cnlh/nps/lib/mux" - "github.com/cnlh/nps/lib/pool" - "github.com/cnlh/nps/lib/rate" - "github.com/cnlh/nps/vender/github.com/xtaci/kcp" "io" "net" "net/http" From b3ed822c72c9ec31f873151edd4d16333046651a Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Mon, 7 Oct 2019 23:04:54 +0800 Subject: [PATCH 36/58] change slide window design --- lib/common/const.go | 4 +- lib/common/netpackager.go | 37 +- lib/mux/conn.go | 703 ++++++++++++++++++++++---------------- lib/mux/mux.go | 118 ++++--- lib/mux/queue.go | 148 ++++++-- 5 files changed, 623 insertions(+), 387 deletions(-) diff --git a/lib/common/const.go b/lib/common/const.go index d77f16b..95364a2 100644 --- a/lib/common/const.go +++ b/lib/common/const.go @@ -42,9 +42,11 @@ const ( MUX_NEW_CONN_OK MUX_NEW_CONN_Fail MUX_NEW_MSG + MUX_NEW_MSG_PART MUX_MSG_SEND_OK MUX_NEW_CONN MUX_CONN_CLOSE MUX_PING_RETURN - MUX_PING int32 = -1 + MUX_PING int32 = -1 + MAXIMUM_SEGMENT_SIZE = 4096 - 16 - 32 - 32 - 8 ) diff --git a/lib/common/netpackager.go b/lib/common/netpackager.go index 1129940..ec2cb69 100644 --- a/lib/common/netpackager.go +++ b/lib/common/netpackager.go @@ -15,7 +15,7 @@ type NetPackager interface { } type BasePackager struct { - Length uint32 + Length uint16 Content []byte } @@ -101,7 +101,7 @@ func (Self *BasePackager) Unmarshal(content interface{}) (err error) { } func (Self *BasePackager) setLength() { - Self.Length = uint32(len(Self.Content)) + Self.Length = uint16(len(Self.Content)) return } @@ -147,25 +147,32 @@ func (Self *ConnPackager) UnPack(reader io.Reader) (err error) { } type MuxPackager struct { - Flag uint8 - Id int32 - Window uint16 + Flag uint8 + Id int32 + Window uint32 + ReadLength uint32 BasePackager } func (Self *MuxPackager) NewPac(flag uint8, id int32, content ...interface{}) (err error) { Self.Flag = flag Self.Id = id - if flag == MUX_NEW_MSG { + if flag == MUX_NEW_MSG || flag == MUX_NEW_MSG_PART || flag == MUX_PING_FLAG { err = Self.BasePackager.NewPac(content...) } if flag == MUX_MSG_SEND_OK { // MUX_MSG_SEND_OK only allows one data switch content[0].(type) { case int: - Self.Window = uint16(content[0].(int)) - case uint16: - Self.Window = content[0].(uint16) + Self.Window = uint32(content[0].(int)) + case uint32: + Self.Window = content[0].(uint32) + } + switch content[1].(type) { + case int: + Self.ReadLength = uint32(content[1].(int)) + case uint32: + Self.ReadLength = content[1].(uint32) } } return @@ -180,11 +187,15 @@ func (Self *MuxPackager) Pack(writer io.Writer) (err error) { if err != nil { return } - if Self.Flag == MUX_NEW_MSG { + if Self.Flag == MUX_NEW_MSG || Self.Flag == MUX_NEW_MSG_PART || Self.Flag == MUX_PING_FLAG { err = Self.BasePackager.Pack(writer) } if Self.Flag == MUX_MSG_SEND_OK { err = binary.Write(writer, binary.LittleEndian, Self.Window) + if err != nil { + return + } + err = binary.Write(writer, binary.LittleEndian, Self.ReadLength) } return } @@ -199,11 +210,15 @@ func (Self *MuxPackager) UnPack(reader io.Reader) (err error) { if err != nil { return } - if Self.Flag == MUX_NEW_MSG { + if Self.Flag == MUX_NEW_MSG || Self.Flag == MUX_NEW_MSG_PART || Self.Flag == MUX_PING_FLAG { err = Self.BasePackager.UnPack(reader) } if Self.Flag == MUX_MSG_SEND_OK { err = binary.Read(reader, binary.LittleEndian, &Self.Window) + if err != nil { + return + } + err = binary.Read(reader, binary.LittleEndian, &Self.ReadLength) } return } diff --git a/lib/mux/conn.go b/lib/mux/conn.go index bf9e0d6..f4d5396 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -2,7 +2,9 @@ package mux import ( "errors" + "github.com/astaxie/beego/logs" "io" + "math" "net" "sync" "time" @@ -15,16 +17,11 @@ type conn struct { getStatusCh chan struct{} connStatusOkCh chan struct{} connStatusFailCh chan struct{} - readTimeOut time.Time - writeTimeOut time.Time connId int32 isClose bool closeFlag bool // close conn flag - receiveWindow *window - sendWindow *window - readCh waitingCh - writeCh waitingCh - mux *Mux + receiveWindow *ReceiveWindow + sendWindow *SendWindow once sync.Once } @@ -34,15 +31,12 @@ func NewConn(connId int32, mux *Mux) *conn { connStatusOkCh: make(chan struct{}), connStatusFailCh: make(chan struct{}), connId: connId, - receiveWindow: new(window), - sendWindow: new(window), - mux: mux, + receiveWindow: new(ReceiveWindow), + sendWindow: new(SendWindow), once: sync.Once{}, } - c.receiveWindow.NewReceive() - c.sendWindow.NewSend() - c.readCh.new() - c.writeCh.new() + c.receiveWindow.New(mux) + c.sendWindow.New(mux) return c } @@ -50,39 +44,14 @@ func (s *conn) Read(buf []byte) (n int, err error) { if s.isClose || buf == nil { return 0, errors.New("the conn has closed") } + if len(buf) == 0 { + return 0, nil + } // waiting for takeout from receive window finish or timeout - go s.readWindow(buf, s.readCh.nCh, s.readCh.errCh) - if t := s.readTimeOut.Sub(time.Now()); t > 0 { - timer := time.NewTimer(t) - defer timer.Stop() - select { - case <-timer.C: - return 0, errors.New("read timeout") - case n = <-s.readCh.nCh: - err = <-s.readCh.errCh - } - } else { - n = <-s.readCh.nCh - err = <-s.readCh.errCh - } + n, err = s.receiveWindow.Read(buf, s.connId) return } -func (s *conn) readWindow(buf []byte, nCh chan int, errCh chan error) { - n, err := s.receiveWindow.Read(buf) - if s.receiveWindow.WindowFull { - if s.receiveWindow.Size() > 0 { - // window.Read may be invoked before window.Write, and WindowFull flag change to true - // so make sure that receiveWindow is free some space - s.receiveWindow.WindowFull = false - s.mux.sendInfo(common.MUX_MSG_SEND_OK, s.connId, s.receiveWindow.Size()) - // acknowledge other side, have empty some receive window space - } - } - nCh <- n - errCh <- err -} - func (s *conn) Write(buf []byte) (n int, err error) { if s.isClose { return 0, errors.New("the conn has closed") @@ -91,45 +60,13 @@ func (s *conn) Write(buf []byte) (n int, err error) { //s.Close() return 0, errors.New("io: write on closed conn") } - s.sendWindow.SetSendBuf(buf) // set the buf to send window - go s.write(s.writeCh.nCh, s.writeCh.errCh) - // waiting for send to other side or timeout - if t := s.writeTimeOut.Sub(time.Now()); t > 0 { - timer := time.NewTimer(t) - defer timer.Stop() - select { - case <-timer.C: - return 0, errors.New("write timeout") - case n = <-s.writeCh.nCh: - err = <-s.writeCh.errCh - } - } else { - n = <-s.writeCh.nCh - err = <-s.writeCh.errCh + if len(buf) == 0 { + return 0, nil } + //logs.Warn("write buf", len(buf)) + n, err = s.sendWindow.WriteFull(buf, s.connId) return } -func (s *conn) write(nCh chan int, errCh chan error) { - var n int - var err error - for { - buf, err := s.sendWindow.WriteTo() - // get the usable window size buf from send window - if buf == nil && err == io.EOF { - // send window is drain, break the loop - err = nil - break - } - if err != nil { - break - } - n += len(buf) - s.mux.sendInfo(common.MUX_NEW_MSG, s.connId, buf) - // send to other side, not send nil data to other side - } - nCh <- n - errCh <- err -} func (s *conn) Close() (err error) { s.once.Do(s.closeProcess) @@ -138,11 +75,11 @@ func (s *conn) Close() (err error) { func (s *conn) closeProcess() { s.isClose = true - s.mux.connMap.Delete(s.connId) - if !s.mux.IsClose { + s.receiveWindow.mux.connMap.Delete(s.connId) + if !s.receiveWindow.mux.IsClose { // if server or user close the conn while reading, will get a io.EOF // and this Close method will be invoke, send this signal to close other side - s.mux.sendInfo(common.MUX_CONN_CLOSE, s.connId, nil) + s.receiveWindow.mux.sendInfo(common.MUX_CONN_CLOSE, s.connId, nil) } s.sendWindow.CloseWindow() s.receiveWindow.CloseWindow() @@ -150,276 +87,440 @@ func (s *conn) closeProcess() { } func (s *conn) LocalAddr() net.Addr { - return s.mux.conn.LocalAddr() + return s.receiveWindow.mux.conn.LocalAddr() } func (s *conn) RemoteAddr() net.Addr { - return s.mux.conn.RemoteAddr() + return s.receiveWindow.mux.conn.RemoteAddr() } func (s *conn) SetDeadline(t time.Time) error { - s.readTimeOut = t - s.writeTimeOut = t + _ = s.SetReadDeadline(t) + _ = s.SetWriteDeadline(t) return nil } func (s *conn) SetReadDeadline(t time.Time) error { - s.readTimeOut = t + s.receiveWindow.SetTimeOut(t) return nil } func (s *conn) SetWriteDeadline(t time.Time) error { - s.writeTimeOut = t + s.sendWindow.SetTimeOut(t) return nil } type window struct { - windowBuff []byte - off uint16 - readOp chan struct{} - readWait bool - WindowFull bool - usableReceiveWindow chan uint16 - WriteWg sync.WaitGroup - closeOp bool - closeOpCh chan struct{} - WriteEndOp chan struct{} - mutex sync.Mutex + off uint32 + maxSize uint32 + closeOp bool + closeOpCh chan struct{} + mux *Mux } -func (Self *window) NewReceive() { +func (Self *window) New() { + Self.closeOpCh = make(chan struct{}, 2) +} + +func (Self *window) CloseWindow() { + if !Self.closeOp { + Self.closeOp = true + Self.closeOpCh <- struct{}{} + Self.closeOpCh <- struct{}{} + } +} + +type ReceiveWindow struct { + bufQueue FIFOQueue + element *ListElement + readLength uint32 + readOp chan struct{} + readWait bool + windowFull bool + count int8 + bw *bandwidth + once sync.Once + window +} + +func (Self *ReceiveWindow) New(mux *Mux) { // initial a window for receive - Self.windowBuff = common.WindowBuff.Get() Self.readOp = make(chan struct{}) - Self.WriteEndOp = make(chan struct{}) - Self.closeOpCh = make(chan struct{}, 3) + Self.bufQueue.New() + Self.bw = new(bandwidth) + Self.element = new(ListElement) + Self.maxSize = 8192 + Self.mux = mux + Self.window.New() } -func (Self *window) NewSend() { - // initial a window for send - Self.usableReceiveWindow = make(chan uint16) - Self.closeOpCh = make(chan struct{}, 3) +func (Self *ReceiveWindow) RemainingSize() (n uint32) { + // receive window remaining + if Self.maxSize >= Self.bufQueue.Len() { + n = Self.maxSize - Self.bufQueue.Len() + } + // if maxSize is small than bufQueue length, return 0 + return } -func (Self *window) SetSendBuf(buf []byte) { +func (Self *ReceiveWindow) ReadSize() (n uint32) { + // acknowledge the size already read + Self.bufQueue.mutex.Lock() + n = Self.readLength + Self.readLength = 0 + Self.bufQueue.mutex.Unlock() + Self.count += 1 + return +} + +func (Self *ReceiveWindow) CalcSize() { + // calculating maximum receive window size + if Self.count == 0 { + logs.Warn("ping, bw", Self.mux.latency, Self.bw.Get()) + n := uint32(2 * Self.mux.latency * Self.bw.Get()) + if n < 8192 { + n = 8192 + } + if n < Self.bufQueue.Len() { + n = Self.bufQueue.Len() + } + // set the minimal size + logs.Warn("n", n) + Self.maxSize = n + Self.count = -5 + } +} + +func (Self *ReceiveWindow) Write(buf []byte, l uint16, part bool, id int32) (err error) { + if Self.closeOp { + return errors.New("conn.receiveWindow: write on closed window") + } + element := ListElement{} + err = element.New(buf, l, part) + //logs.Warn("push the buf", len(buf), l, (&element).l) + if err != nil { + return + } + Self.bufQueue.Push(&element) // must push data before allow read + //logs.Warn("read session calc size ", Self.maxSize) + // calculating the receive window size + Self.CalcSize() + logs.Warn("read session calc size finish", Self.maxSize) + if Self.RemainingSize() == 0 { + Self.windowFull = true + //logs.Warn("window full true", Self.windowFull) + } + Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.maxSize, Self.ReadSize()) + return nil +} + +func (Self *ReceiveWindow) Read(p []byte, id int32) (n int, err error) { + if Self.closeOp { + return 0, io.EOF // receive close signal, returns eof + } + pOff := 0 + l := 0 + //logs.Warn("receive window read off, element.l", Self.off, Self.element.l) +copyData: + Self.bw.StartRead() + if Self.off == uint32(Self.element.l) { + // on the first Read method invoked, Self.off and Self.element.l + // both zero value + Self.element, err = Self.bufQueue.Pop() + // if the queue is empty, Pop method will wait until one element push + // into the queue successful, or timeout. + // timer start on timeout parameter is set up , + // reset to 60s if timeout and data still available + Self.off = 0 + if err != nil { + return // queue receive stop or time out, break the loop and return + } + //logs.Warn("pop element", Self.element.l, Self.element.part) + } + l = copy(p[pOff:], Self.element.buf[Self.off:]) + Self.bw.SetCopySize(l) + pOff += l + Self.off += uint32(l) + Self.bufQueue.mutex.Lock() + Self.readLength += uint32(l) + //logs.Warn("window read length buf len", Self.readLength, Self.bufQueue.Len()) + Self.bufQueue.mutex.Unlock() + n += l + l = 0 + Self.bw.EndRead() + Self.sendStatus(id) + if pOff < len(p) && Self.element.part { + // element is a part of the segments, trying to fill up buf p + goto copyData + } + return // buf p is full or all of segments in buf, return +} + +func (Self *ReceiveWindow) sendStatus(id int32) { + if Self.windowFull || Self.bufQueue.Len() == 0 { + // window is full before read or empty now + Self.windowFull = false + Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.maxSize, Self.ReadSize()) + // acknowledge other side, have empty some receive window space + //} + } +} + +func (Self *ReceiveWindow) SetTimeOut(t time.Time) { + // waiting for FIFO queue Pop method + Self.bufQueue.SetTimeOut(t) +} + +func (Self *ReceiveWindow) Stop() { + // queue has no more data to push, so unblock pop method + Self.once.Do(Self.bufQueue.Stop) +} + +func (Self *ReceiveWindow) CloseWindow() { + Self.window.CloseWindow() + Self.Stop() +} + +type SendWindow struct { + buf []byte + sentLength uint32 + setSizeCh chan struct{} + setSizeWait bool + unSlide uint32 + timeout time.Time + window + mutex sync.Mutex +} + +func (Self *SendWindow) New(mux *Mux) { + Self.setSizeCh = make(chan struct{}) + Self.maxSize = 4096 + Self.mux = mux + Self.window.New() +} + +func (Self *SendWindow) SetSendBuf(buf []byte) { // send window buff from conn write method, set it to send window Self.mutex.Lock() - Self.windowBuff = buf + Self.buf = buf Self.off = 0 Self.mutex.Unlock() } -func (Self *window) fullSlide() { - // slide by allocate - newBuf := common.WindowBuff.Get() - Self.liteSlide() - n := copy(newBuf[:Self.len()], Self.windowBuff) - common.WindowBuff.Put(Self.windowBuff) - Self.windowBuff = newBuf[:n] +func (Self *SendWindow) RemainingSize() (n uint32) { + if Self.maxSize >= Self.sentLength { + n = Self.maxSize - Self.sentLength + } return } -func (Self *window) liteSlide() { - // slide by re slice - Self.windowBuff = Self.windowBuff[Self.off:] - Self.off = 0 - return -} - -func (Self *window) Size() (n int) { - // receive Window remaining - n = common.PoolSizeWindow - Self.len() - return -} - -func (Self *window) len() (n int) { - n = len(Self.windowBuff[Self.off:]) - return -} - -func (Self *window) cap() (n int) { - n = cap(Self.windowBuff[Self.off:]) - return -} - -func (Self *window) grow(n int) { - Self.windowBuff = Self.windowBuff[:Self.len()+n] -} - -func (Self *window) Write(p []byte) (n int, err error) { - if Self.closeOp { - return 0, errors.New("conn.receiveWindow: write on closed window") - } - if len(p) > Self.Size() { - return 0, errors.New("conn.receiveWindow: write too large") - } - Self.mutex.Lock() - // slide the offset - if len(p) > Self.cap()-Self.len() { - // not enough space, need to allocate - Self.fullSlide() - } else { - // have enough space, re slice - Self.liteSlide() - } - length := Self.len() // length before grow - Self.grow(len(p)) // grow for copy - n = copy(Self.windowBuff[length:], p) // must copy data before allow Read - if Self.readWait { - // if there condition is length == 0 and - // Read method just take away all the windowBuff, - // this method will block until windowBuff is empty again - - // allow continue read - defer Self.allowRead() - } - Self.mutex.Unlock() - return n, nil -} - -func (Self *window) allowRead() (closed bool) { - if Self.closeOp { - close(Self.readOp) - return true - } - Self.mutex.Lock() - Self.readWait = false - Self.mutex.Unlock() - select { - case <-Self.closeOpCh: - close(Self.readOp) - return true - case Self.readOp <- struct{}{}: - return false - } -} - -func (Self *window) Read(p []byte) (n int, err error) { - if Self.closeOp { - return 0, io.EOF // Write method receive close signal, returns eof - } - Self.mutex.Lock() - length := Self.len() // protect the length data, it invokes - // before Write lock and after Write unlock - if length == 0 { - // window is empty, waiting for Write method send a success readOp signal - // or get timeout or close - Self.readWait = true - Self.mutex.Unlock() - ticker := time.NewTicker(2 * time.Minute) - defer ticker.Stop() - select { - case _, ok := <-Self.readOp: - if !ok { - return 0, errors.New("conn.receiveWindow: window closed") - } - case <-Self.WriteEndOp: - return 0, io.EOF // receive eof signal, returns eof - case <-ticker.C: - return 0, errors.New("conn.receiveWindow: read time out") - case <-Self.closeOpCh: - close(Self.readOp) - return 0, io.EOF // receive close signal, returns eof - } - } else { - Self.mutex.Unlock() - } - minCopy := 512 - for { - Self.mutex.Lock() - if len(p) == n || Self.len() == 0 { - Self.mutex.Unlock() - break - } - if n+minCopy > len(p) { - minCopy = len(p) - n - } - i := copy(p[n:n+minCopy], Self.windowBuff[Self.off:]) - Self.off += uint16(i) - n += i - Self.mutex.Unlock() - } - p = p[:n] - return -} - -func (Self *window) WriteTo() (p []byte, err error) { - if Self.closeOp { - return nil, errors.New("conn.writeWindow: window closed") - } - if Self.len() == 0 { - return nil, io.EOF - // send window buff is drain, return eof and get another one - } - var windowSize uint16 - var ok bool -waiting: - ticker := time.NewTicker(2 * time.Minute) - defer ticker.Stop() - // waiting for receive usable window size, or timeout - select { - case windowSize, ok = <-Self.usableReceiveWindow: - if !ok { - return nil, errors.New("conn.writeWindow: window closed") - } - case <-ticker.C: - return nil, errors.New("conn.writeWindow: write to time out") - case <-Self.closeOpCh: - return nil, errors.New("conn.writeWindow: window closed") - } - if windowSize == 0 { - goto waiting // waiting for another usable window size - } - Self.mutex.Lock() - if windowSize > uint16(Self.len()) { - // usable window size is bigger than window buff size, send the full buff - windowSize = uint16(Self.len()) - } - p = Self.windowBuff[Self.off : windowSize+Self.off] - Self.off += windowSize - Self.mutex.Unlock() - return -} - -func (Self *window) SetAllowSize(value uint16) (closed bool) { +func (Self *SendWindow) SetSize(windowSize, readLength uint32) (closed bool) { defer func() { if recover() != nil { closed = true } }() if Self.closeOp { - close(Self.usableReceiveWindow) + close(Self.setSizeCh) return true } - select { - case Self.usableReceiveWindow <- value: - return false - case <-Self.closeOpCh: - close(Self.usableReceiveWindow) - return true + if readLength == 0 && Self.maxSize == windowSize { + logs.Warn("waiting for another window size") + return false // waiting for receive another usable window size } + logs.Warn("set send window size to ", windowSize, readLength) + Self.mutex.Lock() + Self.slide(windowSize, readLength) + if Self.setSizeWait { + // send window into the wait status, need notice the channel + //logs.Warn("send window remaining size is 0 , wait") + if Self.RemainingSize() == 0 { + //logs.Warn("waiting for another window size after slide") + // keep the wait status + Self.mutex.Unlock() + return false + } + Self.setSizeWait = false + Self.mutex.Unlock() + //logs.Warn("send window remaining size is 0 starting wait") + select { + case Self.setSizeCh <- struct{}{}: + //logs.Warn("send window remaining size is 0 finish") + return false + case <-Self.closeOpCh: + close(Self.setSizeCh) + return true + } + } + // send window not into the wait status, so just do slide + Self.mutex.Unlock() + return false } -func (Self *window) CloseWindow() { - Self.closeOp = true - Self.closeOpCh <- struct{}{} - Self.closeOpCh <- struct{}{} - Self.closeOpCh <- struct{}{} - close(Self.closeOpCh) +func (Self *SendWindow) slide(windowSize, readLength uint32) { + Self.sentLength -= readLength + Self.maxSize = windowSize +} + +func (Self *SendWindow) WriteTo() (p []byte, part bool, err error) { + // returns buf segments, return only one segments, need a loop outside + // until err = io.EOF + if Self.closeOp { + return nil, false, errors.New("conn.writeWindow: window closed") + } + if Self.off == uint32(len(Self.buf)) { + return nil, false, io.EOF + // send window buff is drain, return eof and get another one + } + Self.mutex.Lock() + if Self.RemainingSize() == 0 { + Self.setSizeWait = true + Self.mutex.Unlock() + // into the wait status + err = Self.waitReceiveWindow() + if err != nil { + return nil, false, err + } + } else { + Self.mutex.Unlock() + } + Self.mutex.Lock() + var sendSize uint32 + if len(Self.buf[Self.off:]) > common.MAXIMUM_SEGMENT_SIZE { + sendSize = common.MAXIMUM_SEGMENT_SIZE + part = true + } else { + sendSize = uint32(len(Self.buf[Self.off:])) + part = false + } + if Self.RemainingSize() < sendSize { + // usable window size is small than + // window MAXIMUM_SEGMENT_SIZE or send buf left + sendSize = Self.RemainingSize() + part = true + } + //logs.Warn("send size", sendSize) + p = Self.buf[Self.off : sendSize+Self.off] + Self.off += sendSize + Self.sentLength += sendSize + Self.mutex.Unlock() return } -type waitingCh struct { - nCh chan int - errCh chan error +func (Self *SendWindow) waitReceiveWindow() (err error) { + t := Self.timeout.Sub(time.Now()) + if t < 0 { + t = time.Minute + } + timer := time.NewTimer(t) + defer timer.Stop() + // waiting for receive usable window size, or timeout + select { + case _, ok := <-Self.setSizeCh: + if !ok { + return errors.New("conn.writeWindow: window closed") + } + return nil + case <-timer.C: + return errors.New("conn.writeWindow: write to time out") + case <-Self.closeOpCh: + return errors.New("conn.writeWindow: window closed") + } } -func (Self *waitingCh) new() { - Self.nCh = make(chan int) - Self.errCh = make(chan error) +func (Self *SendWindow) WriteFull(buf []byte, id int32) (n int, err error) { + Self.SetSendBuf(buf) // set the buf to send window + var bufSeg []byte + var part bool + for { + bufSeg, part, err = Self.WriteTo() + //logs.Warn("buf seg", len(bufSeg), part, err) + // get the buf segments from send window + if bufSeg == nil && part == false && err == io.EOF { + // send window is drain, break the loop + err = nil + break + } + if err != nil { + break + } + n += len(bufSeg) + if part { + Self.mux.sendInfo(common.MUX_NEW_MSG_PART, id, bufSeg) + } else { + Self.mux.sendInfo(common.MUX_NEW_MSG, id, bufSeg) + //logs.Warn("buf seg sent", len(bufSeg), part, err) + } + // send to other side, not send nil data to other side + } + //logs.Warn("buf seg write success") + return } -func (Self *waitingCh) close() { - close(Self.nCh) - close(Self.errCh) +func (Self *SendWindow) SetTimeOut(t time.Time) { + // waiting for receive a receive window size + Self.timeout = t +} + +type bandwidth struct { + lastReadStart time.Time + readStart time.Time + readEnd time.Time + bufLength int + lastBufLength int + count int8 + readBW float64 + writeBW float64 +} + +func (Self *bandwidth) StartRead() { + Self.lastReadStart, Self.readStart = Self.readStart, time.Now() +} + +func (Self *bandwidth) EndRead() { + if !Self.lastReadStart.IsZero() { + if Self.count == 0 { + Self.calcWriteBandwidth() + } + } + Self.readEnd = time.Now() + if Self.count == 0 { + Self.calcReadBandwidth() + Self.count = -3 + } + Self.count += 1 +} + +func (Self *bandwidth) SetCopySize(n int) { + // must be invoke between StartRead and EndRead + Self.lastBufLength, Self.bufLength = Self.bufLength, n +} + +func (Self *bandwidth) calcReadBandwidth() { + // Bandwidth between nps and npc + readTime := Self.readEnd.Sub(Self.readStart) + Self.readBW = float64(Self.bufLength) / readTime.Seconds() + //logs.Warn("calc read bw", Self.bufLength, readTime.Seconds()) +} + +func (Self *bandwidth) calcWriteBandwidth() { + // Bandwidth between nps and user, npc and application + //logs.Warn("calc write bw") + writeTime := Self.readEnd.Sub(Self.lastReadStart) + Self.writeBW = float64(Self.lastBufLength) / writeTime.Seconds() +} + +func (Self *bandwidth) Get() (bw float64) { + // The zero value, 0 for numeric types + if Self.writeBW == 0 && Self.readBW == 0 { + logs.Warn("bw both 0") + return 100 + } + if Self.writeBW == 0 && Self.readBW != 0 { + return Self.readBW + } + if Self.readBW == 0 && Self.writeBW != 0 { + return Self.writeBW + } + return math.Min(Self.readBW, Self.writeBW) } diff --git a/lib/mux/mux.go b/lib/mux/mux.go index a662ad0..e6a9e67 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -3,6 +3,7 @@ package mux import ( "bytes" "errors" + "io" "math" "net" "sync" @@ -22,8 +23,10 @@ type Mux struct { closeChan chan struct{} IsClose bool pingOk int + latency float64 + pingCh chan []byte connType string - writeQueue Queue + writeQueue PriorityQueue bufCh chan *bytes.Buffer sync.Mutex } @@ -38,13 +41,15 @@ func NewMux(c net.Conn, connType string) *Mux { IsClose: false, connType: connType, bufCh: make(chan *bytes.Buffer), + pingCh: make(chan []byte), } m.writeQueue.New() //read session by flag - go m.readSession() + m.readSession() //ping - go m.ping() - go m.writeSession() + m.ping() + m.pingReturn() + m.writeSession() return m } @@ -83,10 +88,10 @@ func (s *Mux) Addr() net.Addr { return s.conn.LocalAddr() } -func (s *Mux) sendInfo(flag uint8, id int32, data interface{}) { +func (s *Mux) sendInfo(flag uint8, id int32, data ...interface{}) { var err error pack := common.MuxPack.Get() - err = pack.NewPac(flag, id, data) + err = pack.NewPac(flag, id, data...) if err != nil { common.MuxPack.Put(pack) return @@ -98,11 +103,13 @@ func (s *Mux) sendInfo(flag uint8, id int32, data interface{}) { func (s *Mux) writeSession() { go s.packBuf() go s.writeBuf() - <-s.closeChan } func (s *Mux) packBuf() { for { + if s.IsClose { + break + } pack := s.writeQueue.Pop() buffer := common.BuffPool.Get() err := pack.Pack(buffer) @@ -117,12 +124,14 @@ func (s *Mux) packBuf() { case <-s.closeChan: break } - } } func (s *Mux) writeBuf() { for { + if s.IsClose { + break + } select { case buffer := <-s.bufCh: l := buffer.Len() @@ -141,8 +150,15 @@ func (s *Mux) writeBuf() { func (s *Mux) ping() { go func() { - ticker := time.NewTicker(time.Second * 1) + now, _ := time.Now().MarshalText() + s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, now) + // send the ping flag and get the latency first + ticker := time.NewTicker(time.Second * 15) for { + if s.IsClose { + ticker.Stop() + break + } select { case <-ticker.C: } @@ -150,7 +166,8 @@ func (s *Mux) ping() { if (math.MaxInt32 - s.id) < 10000 { s.id = 0 } - s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, nil) + now, _ := time.Now().MarshalText() + s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, now) if s.pingOk > 10 && s.connType == "kcp" { s.Close() break @@ -158,15 +175,32 @@ func (s *Mux) ping() { s.pingOk++ } }() - select { - case <-s.closeChan: - } +} + +func (s *Mux) pingReturn() { + go func() { + var now time.Time + var data []byte + for { + select { + case data = <-s.pingCh: + case <-s.closeChan: + break + } + _ = now.UnmarshalText(data) + s.latency = time.Since(now).Seconds() + s.sendInfo(common.MUX_PING_RETURN, common.MUX_PING, nil) + } + }() } func (s *Mux) readSession() { go func() { pack := common.MuxPack.Get() for { + if s.IsClose { + break + } pack = common.MuxPack.Get() if pack.UnPack(s.conn) != nil { break @@ -176,44 +210,25 @@ func (s *Mux) readSession() { case common.MUX_NEW_CONN: //new connection connection := NewConn(pack.Id, s) s.connMap.Set(pack.Id, connection) //it has been set before send ok - go func(connection *conn) { - connection.sendWindow.SetAllowSize(512) // set the initial receive window - }(connection) s.newConnCh <- connection s.sendInfo(common.MUX_NEW_CONN_OK, connection.connId, nil) continue case common.MUX_PING_FLAG: //ping - go s.sendInfo(common.MUX_PING_RETURN, common.MUX_PING, nil) + s.pingCh <- pack.Content continue case common.MUX_PING_RETURN: continue } if connection, ok := s.connMap.Get(pack.Id); ok && !connection.isClose { switch pack.Flag { - case common.MUX_NEW_MSG: //new msg from remote connection - //insert wait queue - if connection.isClose { - continue + case common.MUX_NEW_MSG, common.MUX_NEW_MSG_PART: //new msg from remote connection + err := s.newMsg(connection, pack) + if err != nil { + connection.Close() } - connection.receiveWindow.WriteWg.Add(1) - go func(connection *conn, content []byte) { // do not block read session - _, err := connection.receiveWindow.Write(content) - if err != nil { - logs.Warn("mux new msg err close", err) - connection.Close() - } - size := connection.receiveWindow.Size() - if size == 0 { - connection.receiveWindow.WindowFull = true - } - s.sendInfo(common.MUX_MSG_SEND_OK, connection.connId, size) - connection.receiveWindow.WriteWg.Done() - }(connection, pack.Content) continue case common.MUX_NEW_CONN_OK: //connection ok connection.connStatusOkCh <- struct{}{} - go connection.sendWindow.SetAllowSize(512) - // set the initial receive window both side continue case common.MUX_NEW_CONN_Fail: connection.connStatusFailCh <- struct{}{} @@ -222,15 +237,12 @@ func (s *Mux) readSession() { if connection.isClose { continue } - go connection.sendWindow.SetAllowSize(pack.Window) + connection.sendWindow.SetSize(pack.Window, pack.ReadLength) continue case common.MUX_CONN_CLOSE: //close the connection s.connMap.Delete(pack.Id) connection.closeFlag = true - go func(connection *conn) { - connection.receiveWindow.WriteWg.Wait() - connection.receiveWindow.WriteEndOp <- struct{}{} // close signal to receive window - }(connection) + connection.receiveWindow.Stop() // close signal to receive window continue } } else if pack.Flag == common.MUX_CONN_CLOSE { @@ -241,9 +253,24 @@ func (s *Mux) readSession() { common.MuxPack.Put(pack) s.Close() }() - select { - case <-s.closeChan: +} + +func (s *Mux) newMsg(connection *conn, pack *common.MuxPackager) (err error) { + if connection.isClose { + err = io.ErrClosedPipe + return } + //logs.Warn("read session receive new msg", pack.Length) + //go func(connection *conn, pack *common.MuxPackager) { // do not block read session + //insert into queue + if pack.Flag == common.MUX_NEW_MSG_PART { + err = connection.receiveWindow.Write(pack.Content, pack.Length, true, pack.Id) + } + if pack.Flag == common.MUX_NEW_MSG { + err = connection.receiveWindow.Write(pack.Content, pack.Length, false, pack.Id) + } + //logs.Warn("read session write success", pack.Length) + return } func (s *Mux) Close() error { @@ -255,9 +282,6 @@ func (s *Mux) Close() error { s.connMap.Close() s.closeChan <- struct{}{} s.closeChan <- struct{}{} - s.closeChan <- struct{}{} - s.closeChan <- struct{}{} - s.closeChan <- struct{}{} close(s.newConnCh) return s.conn.Close() } diff --git a/lib/mux/queue.go b/lib/mux/queue.go index 081b2c9..5a57151 100644 --- a/lib/mux/queue.go +++ b/lib/mux/queue.go @@ -2,25 +2,54 @@ package mux import ( "container/list" + "errors" "github.com/cnlh/nps/lib/common" + "io" "sync" + "time" ) -type Queue struct { - list *list.List +type QueueOp struct { readOp chan struct{} cleanOp chan struct{} popWait bool mutex sync.Mutex } -func (Self *Queue) New() { - Self.list = list.New() +func (Self *QueueOp) New() { Self.readOp = make(chan struct{}) Self.cleanOp = make(chan struct{}, 2) } -func (Self *Queue) Push(packager *common.MuxPackager) { +func (Self *QueueOp) allowPop() (closed bool) { + Self.mutex.Lock() + Self.popWait = false + Self.mutex.Unlock() + select { + case Self.readOp <- struct{}{}: + return false + case <-Self.cleanOp: + return true + } +} + +func (Self *QueueOp) Clean() { + Self.cleanOp <- struct{}{} + Self.cleanOp <- struct{}{} + close(Self.cleanOp) +} + +type PriorityQueue struct { + list *list.List + QueueOp +} + +func (Self *PriorityQueue) New() { + Self.list = list.New() + Self.QueueOp.New() +} + +func (Self *PriorityQueue) Push(packager *common.MuxPackager) { Self.mutex.Lock() if Self.popWait { defer Self.allowPop() @@ -35,28 +64,16 @@ func (Self *Queue) Push(packager *common.MuxPackager) { return } -func (Self *Queue) allowPop() (closed bool) { - Self.mutex.Lock() - Self.popWait = false - Self.mutex.Unlock() - select { - case Self.readOp <- struct{}{}: - return false - case <-Self.cleanOp: - return true - } -} - -func (Self *Queue) insert(packager *common.MuxPackager) { +func (Self *PriorityQueue) insert(packager *common.MuxPackager) { element := Self.list.Back() for { - if element == nil { // Queue dose not have any of msg package with this close package id + if element == nil { // PriorityQueue dose not have any of msg package with this close package id Self.list.PushFront(packager) // insert close package to first break } if element.Value.(*common.MuxPackager).Flag == common.MUX_NEW_MSG && element.Value.(*common.MuxPackager).Id == packager.Id { - Self.list.InsertAfter(packager, element) // Queue has some msg package + Self.list.InsertAfter(packager, element) // PriorityQueue has some msg package // with this close package id, insert close package after last msg package break } @@ -64,7 +81,7 @@ func (Self *Queue) insert(packager *common.MuxPackager) { } } -func (Self *Queue) Pop() (packager *common.MuxPackager) { +func (Self *PriorityQueue) Pop() (packager *common.MuxPackager) { Self.mutex.Lock() element := Self.list.Front() if element != nil { @@ -73,7 +90,7 @@ func (Self *Queue) Pop() (packager *common.MuxPackager) { Self.mutex.Unlock() return } - Self.popWait = true // Queue is empty, notice Push method + Self.popWait = true // PriorityQueue is empty, notice Push method Self.mutex.Unlock() select { case <-Self.readOp: @@ -83,13 +100,90 @@ func (Self *Queue) Pop() (packager *common.MuxPackager) { } } -func (Self *Queue) Len() (n int) { +func (Self *PriorityQueue) Len() (n int) { n = Self.list.Len() return } -func (Self *Queue) Clean() { - Self.cleanOp <- struct{}{} - Self.cleanOp <- struct{}{} - close(Self.cleanOp) +type ListElement struct { + buf []byte + l uint16 + part bool +} + +func (Self *ListElement) New(buf []byte, l uint16, part bool) (err error) { + if uint16(len(buf)) != l { + return errors.New("ListElement: buf length not match") + } + Self.buf = buf + Self.l = l + Self.part = part + return nil +} + +type FIFOQueue struct { + list []*ListElement + length uint32 + stopOp chan struct{} + timeout time.Time + QueueOp +} + +func (Self *FIFOQueue) New() { + Self.QueueOp.New() + Self.stopOp = make(chan struct{}, 1) +} + +func (Self *FIFOQueue) Push(element *ListElement) { + Self.mutex.Lock() + if Self.popWait { + defer Self.allowPop() + } + Self.list = append(Self.list, element) + Self.length += uint32(element.l) + Self.mutex.Unlock() + return +} + +func (Self *FIFOQueue) Pop() (element *ListElement, err error) { + Self.mutex.Lock() + if len(Self.list) == 0 { + Self.popWait = true + Self.mutex.Unlock() + t := Self.timeout.Sub(time.Now()) + if t <= 0 { + t = time.Minute + } + timer := time.NewTimer(t) + defer timer.Stop() + select { + case <-Self.readOp: + Self.mutex.Lock() + case <-Self.cleanOp: + return + case <-Self.stopOp: + err = io.EOF + return + case <-timer.C: + err = errors.New("mux.queue: read time out") + return + } + } + element = Self.list[0] + Self.list = Self.list[1:] + Self.length -= uint32(element.l) + Self.mutex.Unlock() + return +} + +func (Self *FIFOQueue) Len() (n uint32) { + return Self.length +} + +func (Self *FIFOQueue) Stop() { + Self.stopOp <- struct{}{} +} + +func (Self *FIFOQueue) SetTimeOut(t time.Time) { + Self.timeout = t } From d9f9dc6acbbe199ff320df2444d375db6835ac69 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Tue, 8 Oct 2019 13:38:42 +0800 Subject: [PATCH 37/58] change ping calculate, fix window size calculate --- lib/common/netpackager.go | 20 ++++++++++---------- lib/mux/conn.go | 15 +++++++-------- lib/mux/mux.go | 14 +++++++++----- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/lib/common/netpackager.go b/lib/common/netpackager.go index ec2cb69..69ce96a 100644 --- a/lib/common/netpackager.go +++ b/lib/common/netpackager.go @@ -157,11 +157,11 @@ type MuxPackager struct { func (Self *MuxPackager) NewPac(flag uint8, id int32, content ...interface{}) (err error) { Self.Flag = flag Self.Id = id - if flag == MUX_NEW_MSG || flag == MUX_NEW_MSG_PART || flag == MUX_PING_FLAG { + switch flag { + case MUX_NEW_MSG, MUX_NEW_MSG_PART, MUX_PING_FLAG, MUX_PING_RETURN: err = Self.BasePackager.NewPac(content...) - } - if flag == MUX_MSG_SEND_OK { - // MUX_MSG_SEND_OK only allows one data + case MUX_MSG_SEND_OK: + // MUX_MSG_SEND_OK contains two data switch content[0].(type) { case int: Self.Window = uint32(content[0].(int)) @@ -187,10 +187,10 @@ func (Self *MuxPackager) Pack(writer io.Writer) (err error) { if err != nil { return } - if Self.Flag == MUX_NEW_MSG || Self.Flag == MUX_NEW_MSG_PART || Self.Flag == MUX_PING_FLAG { + switch Self.Flag { + case MUX_NEW_MSG, MUX_NEW_MSG_PART, MUX_PING_FLAG, MUX_PING_RETURN: err = Self.BasePackager.Pack(writer) - } - if Self.Flag == MUX_MSG_SEND_OK { + case MUX_MSG_SEND_OK: err = binary.Write(writer, binary.LittleEndian, Self.Window) if err != nil { return @@ -210,10 +210,10 @@ func (Self *MuxPackager) UnPack(reader io.Reader) (err error) { if err != nil { return } - if Self.Flag == MUX_NEW_MSG || Self.Flag == MUX_NEW_MSG_PART || Self.Flag == MUX_PING_FLAG { + switch Self.Flag { + case MUX_NEW_MSG, MUX_NEW_MSG_PART, MUX_PING_FLAG, MUX_PING_RETURN: err = Self.BasePackager.UnPack(reader) - } - if Self.Flag == MUX_MSG_SEND_OK { + case MUX_MSG_SEND_OK: err = binary.Read(reader, binary.LittleEndian, &Self.Window) if err != nil { return diff --git a/lib/mux/conn.go b/lib/mux/conn.go index f4d5396..5dd69ea 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -2,7 +2,6 @@ package mux import ( "errors" - "github.com/astaxie/beego/logs" "io" "math" "net" @@ -169,14 +168,13 @@ func (Self *ReceiveWindow) ReadSize() (n uint32) { n = Self.readLength Self.readLength = 0 Self.bufQueue.mutex.Unlock() - Self.count += 1 return } func (Self *ReceiveWindow) CalcSize() { // calculating maximum receive window size if Self.count == 0 { - logs.Warn("ping, bw", Self.mux.latency, Self.bw.Get()) + //logs.Warn("ping, bw", Self.mux.latency, Self.bw.Get()) n := uint32(2 * Self.mux.latency * Self.bw.Get()) if n < 8192 { n = 8192 @@ -185,10 +183,11 @@ func (Self *ReceiveWindow) CalcSize() { n = Self.bufQueue.Len() } // set the minimal size - logs.Warn("n", n) + //logs.Warn("n", n) Self.maxSize = n Self.count = -5 } + Self.count += 1 } func (Self *ReceiveWindow) Write(buf []byte, l uint16, part bool, id int32) (err error) { @@ -205,7 +204,7 @@ func (Self *ReceiveWindow) Write(buf []byte, l uint16, part bool, id int32) (err //logs.Warn("read session calc size ", Self.maxSize) // calculating the receive window size Self.CalcSize() - logs.Warn("read session calc size finish", Self.maxSize) + //logs.Warn("read session calc size finish", Self.maxSize) if Self.RemainingSize() == 0 { Self.windowFull = true //logs.Warn("window full true", Self.windowFull) @@ -325,10 +324,10 @@ func (Self *SendWindow) SetSize(windowSize, readLength uint32) (closed bool) { return true } if readLength == 0 && Self.maxSize == windowSize { - logs.Warn("waiting for another window size") + //logs.Warn("waiting for another window size") return false // waiting for receive another usable window size } - logs.Warn("set send window size to ", windowSize, readLength) + //logs.Warn("set send window size to ", windowSize, readLength) Self.mutex.Lock() Self.slide(windowSize, readLength) if Self.setSizeWait { @@ -513,7 +512,7 @@ func (Self *bandwidth) calcWriteBandwidth() { func (Self *bandwidth) Get() (bw float64) { // The zero value, 0 for numeric types if Self.writeBW == 0 && Self.readBW == 0 { - logs.Warn("bw both 0") + //logs.Warn("bw both 0") return 100 } if Self.writeBW == 0 && Self.readBW != 0 { diff --git a/lib/mux/mux.go b/lib/mux/mux.go index e6a9e67..9023b82 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -150,7 +150,7 @@ func (s *Mux) writeBuf() { func (s *Mux) ping() { go func() { - now, _ := time.Now().MarshalText() + now, _ := time.Now().UTC().MarshalText() s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, now) // send the ping flag and get the latency first ticker := time.NewTicker(time.Second * 15) @@ -166,7 +166,7 @@ func (s *Mux) ping() { if (math.MaxInt32 - s.id) < 10000 { s.id = 0 } - now, _ := time.Now().MarshalText() + now, _ := time.Now().UTC().MarshalText() s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, now) if s.pingOk > 10 && s.connType == "kcp" { s.Close() @@ -188,8 +188,11 @@ func (s *Mux) pingReturn() { break } _ = now.UnmarshalText(data) - s.latency = time.Since(now).Seconds() - s.sendInfo(common.MUX_PING_RETURN, common.MUX_PING, nil) + s.latency = time.Now().UTC().Sub(now).Seconds() / 2 + //logs.Warn("latency", s.latency) + if s.latency <= 0 { + logs.Warn("latency err", s.latency) + } } }() } @@ -214,9 +217,10 @@ func (s *Mux) readSession() { s.sendInfo(common.MUX_NEW_CONN_OK, connection.connId, nil) continue case common.MUX_PING_FLAG: //ping - s.pingCh <- pack.Content + s.sendInfo(common.MUX_PING_RETURN, common.MUX_PING, pack.Content) continue case common.MUX_PING_RETURN: + s.pingCh <- pack.Content continue } if connection, ok := s.connMap.Get(pack.Id); ok && !connection.isClose { From 4c8d7b0738f492db4904c5f9c976359178dc93e0 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Tue, 8 Oct 2019 21:41:25 +0800 Subject: [PATCH 38/58] reduce memory allocate --- lib/common/const.go | 2 +- lib/common/pool.go | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/common/const.go b/lib/common/const.go index 95364a2..b4eac1a 100644 --- a/lib/common/const.go +++ b/lib/common/const.go @@ -48,5 +48,5 @@ const ( MUX_CONN_CLOSE MUX_PING_RETURN MUX_PING int32 = -1 - MAXIMUM_SEGMENT_SIZE = 4096 - 16 - 32 - 32 - 8 + MAXIMUM_SEGMENT_SIZE = PoolSizeWindow ) diff --git a/lib/common/pool.go b/lib/common/pool.go index 98da5d3..24efc60 100644 --- a/lib/common/pool.go +++ b/lib/common/pool.go @@ -9,7 +9,8 @@ const PoolSize = 64 * 1024 const PoolSizeSmall = 100 const PoolSizeUdp = 1472 const PoolSizeCopy = 32 << 10 -const PoolSizeWindow = 1<<16 - 1 +const PoolSizeBuffer = 4096 +const PoolSizeWindow = PoolSizeBuffer - 16 - 32 - 32 - 8 var BufPool = sync.Pool{ New: func() interface{} { @@ -92,18 +93,18 @@ type windowBufferPool struct { func (Self *windowBufferPool) New() { Self.pool = sync.Pool{ New: func() interface{} { - return make([]byte, 0, PoolSizeWindow) + return make([]byte, PoolSizeWindow, PoolSizeWindow) }, } } func (Self *windowBufferPool) Get() (buf []byte) { buf = Self.pool.Get().([]byte) - return buf[:0] + return buf[:PoolSizeWindow] } func (Self *windowBufferPool) Put(x []byte) { - if cap(x) == PoolSizeWindow { + if len(x) == PoolSizeWindow { Self.pool.Put(x[:PoolSizeWindow]) // make buf to full } else { x = nil @@ -117,7 +118,7 @@ type bufferPool struct { func (Self *bufferPool) New() { Self.pool = sync.Pool{ New: func() interface{} { - return new(bytes.Buffer) + return bytes.NewBuffer(make([]byte, 0, PoolSizeBuffer)) }, } } @@ -146,13 +147,12 @@ func (Self *muxPackagerPool) New() { func (Self *muxPackagerPool) Get() *MuxPackager { pack := Self.pool.Get().(*MuxPackager) - buf := CopyBuff.Get() - pack.Content = buf + pack.Content = WindowBuff.Get() return pack } func (Self *muxPackagerPool) Put(pack *MuxPackager) { - CopyBuff.Put(pack.Content) + WindowBuff.Put(pack.Content) Self.pool.Put(pack) } From 1f8e4410906a8e5a557535078818e22dff7bf35f Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Sat, 12 Oct 2019 22:56:37 +0800 Subject: [PATCH 39/58] multiple changes --- README.md | 11 ++++++++- client/client.go | 5 ++++ client/control.go | 9 +++++-- cmd/nps/nps.go | 2 +- lib/common/const.go | 1 + lib/common/netpackager.go | 9 +++++-- lib/common/pool.go | 11 ++------- lib/common/util.go | 3 +++ lib/install/install.go | 38 +++++++++++++++++++++++++--- lib/mux/conn.go | 8 ++++++ lib/mux/mux.go | 17 +++++++++++-- lib/mux/mux_test.go | 52 +++++++++++++++++++++++++++++++++++++++ lib/mux/queue.go | 39 ++++++++++++++++++++--------- lib/version/version.go | 4 +-- 14 files changed, 176 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 1dd7f77..f56c32a 100644 --- a/README.md +++ b/README.md @@ -197,6 +197,9 @@ nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务 - 在刚才创建的客户端隧道管理中添加一条socks5代理,填写监听的端口(8003),保存。 - 在外网环境的本机配置socks5代理(例如使用proxifier进行全局代理),ip为公网服务器ip(1.1.1.1),端口为填写的监听端口(8003),即可畅享内网了 +**注意** +经过socks5代理,当收到socks5数据包时socket已经是accept状态。表现是扫描端口全open,建立连接后短时间关闭。若想同内网表现一致,建议远程连接一台设备。 + ### http正向代理 **适用范围:** 在外网环境下使用http正向代理访问内网站点 @@ -375,7 +378,13 @@ server { ``` (./nps|nps.exe) install ``` -安装成功后,对于linux,darwin,将会把配置文件和静态文件放置于/etc/nps/,并将可执行文件nps复制到/usr/bin/nps或者/usr/local/bin/nps,安装成功后可在任何位置执行 +安装成功后,对于linux,darwin,将会把配置文件和静态文件放置于/etc/nps/,并将可执行文件nps复制到/usr/bin/nps或者/usr/local/bin/nps,安装成功后可在任何位置执行,同时也会添加systemd配置。 + +``` +sudo systemctl enable|disable|start|stop|restart|status nps +``` +systemd,带有开机自启,自动重启配置,当进程结束后15秒会启动,日志输出至/var/log/nps/nps.log。 +建议采用此方式启动,能够捕获panic信息,便于排查问题。 ``` nps test|start|stop|restart|status diff --git a/client/client.go b/client/client.go index 52da907..5bd0b01 100755 --- a/client/client.go +++ b/client/client.go @@ -49,6 +49,11 @@ retry: time.Sleep(time.Second * 5) goto retry } + if c == nil { + logs.Error("Error data from server, and will be reconnected in five seconds") + time.Sleep(time.Second * 5) + goto retry + } logs.Info("Successful connection with server %s", s.svrAddr) //monitor the connection go s.ping() diff --git a/client/control.go b/client/control.go index 5673f14..3260113 100644 --- a/client/control.go +++ b/client/control.go @@ -223,8 +223,13 @@ func NewConn(tp string, vkey string, server string, connType string, proxyUrl st if _, err := c.Write([]byte(crypt.Md5(version.GetVersion()))); err != nil { return nil, err } - if b, err := c.GetShortContent(32); err != nil || crypt.Md5(version.GetVersion()) != string(b) { - logs.Error("The client does not match the server version. The current version of the client is", version.GetVersion()) + b, err := c.GetShortContent(32) + if err != nil { + logs.Error(err) + return nil, err + } + if crypt.Md5(version.GetVersion()) != string(b) { + logs.Error("The client does not match the server version. The current core version of the client is", version.GetVersion()) return nil, err } if _, err := c.Write([]byte(common.Getverifyval(vkey))); err != nil { diff --git a/cmd/nps/nps.go b/cmd/nps/nps.go index f66fe66..22835a2 100644 --- a/cmd/nps/nps.go +++ b/cmd/nps/nps.go @@ -61,7 +61,7 @@ func main() { logs.Error("Getting bridge_port error", err) os.Exit(0) } - logs.Info("the version of server is %s ,allow client version to be %s", version.VERSION, version.GetVersion()) + logs.Info("the version of server is %s ,allow client core version to be %s", version.VERSION, version.GetVersion()) connection.InitConnectionService() crypt.InitTls(filepath.Join(common.GetRunPath(), "conf", "server.pem"), filepath.Join(common.GetRunPath(), "conf", "server.key")) tool.InitAllowPort() diff --git a/lib/common/const.go b/lib/common/const.go index b4eac1a..f57ce4f 100644 --- a/lib/common/const.go +++ b/lib/common/const.go @@ -49,4 +49,5 @@ const ( MUX_PING_RETURN MUX_PING int32 = -1 MAXIMUM_SEGMENT_SIZE = PoolSizeWindow + MAXIMUM_WINDOW_SIZE = 1<<31 - 1 ) diff --git a/lib/common/netpackager.go b/lib/common/netpackager.go index 69ce96a..567a48f 100644 --- a/lib/common/netpackager.go +++ b/lib/common/netpackager.go @@ -158,8 +158,10 @@ func (Self *MuxPackager) NewPac(flag uint8, id int32, content ...interface{}) (e Self.Flag = flag Self.Id = id switch flag { - case MUX_NEW_MSG, MUX_NEW_MSG_PART, MUX_PING_FLAG, MUX_PING_RETURN: + case MUX_PING_FLAG, MUX_PING_RETURN, MUX_NEW_MSG, MUX_NEW_MSG_PART: + Self.Content = WindowBuff.Get() err = Self.BasePackager.NewPac(content...) + //logs.Warn(Self.Length, string(Self.Content)) case MUX_MSG_SEND_OK: // MUX_MSG_SEND_OK contains two data switch content[0].(type) { @@ -190,6 +192,7 @@ func (Self *MuxPackager) Pack(writer io.Writer) (err error) { switch Self.Flag { case MUX_NEW_MSG, MUX_NEW_MSG_PART, MUX_PING_FLAG, MUX_PING_RETURN: err = Self.BasePackager.Pack(writer) + WindowBuff.Put(Self.Content) case MUX_MSG_SEND_OK: err = binary.Write(writer, binary.LittleEndian, Self.Window) if err != nil { @@ -201,7 +204,6 @@ func (Self *MuxPackager) Pack(writer io.Writer) (err error) { } func (Self *MuxPackager) UnPack(reader io.Reader) (err error) { - Self.BasePackager.clean() // also clean the content err = binary.Read(reader, binary.LittleEndian, &Self.Flag) if err != nil { return @@ -212,7 +214,10 @@ func (Self *MuxPackager) UnPack(reader io.Reader) (err error) { } switch Self.Flag { case MUX_NEW_MSG, MUX_NEW_MSG_PART, MUX_PING_FLAG, MUX_PING_RETURN: + Self.Content = WindowBuff.Get() // need get a window buf from pool + Self.BasePackager.clean() // also clean the content err = Self.BasePackager.UnPack(reader) + //logs.Warn("unpack", Self.Length, string(Self.Content)) case MUX_MSG_SEND_OK: err = binary.Read(reader, binary.LittleEndian, &Self.Window) if err != nil { diff --git a/lib/common/pool.go b/lib/common/pool.go index 24efc60..240f7f9 100644 --- a/lib/common/pool.go +++ b/lib/common/pool.go @@ -104,11 +104,7 @@ func (Self *windowBufferPool) Get() (buf []byte) { } func (Self *windowBufferPool) Put(x []byte) { - if len(x) == PoolSizeWindow { - Self.pool.Put(x[:PoolSizeWindow]) // make buf to full - } else { - x = nil - } + Self.pool.Put(x[:PoolSizeWindow]) // make buf to full } type bufferPool struct { @@ -146,13 +142,10 @@ func (Self *muxPackagerPool) New() { } func (Self *muxPackagerPool) Get() *MuxPackager { - pack := Self.pool.Get().(*MuxPackager) - pack.Content = WindowBuff.Get() - return pack + return Self.pool.Get().(*MuxPackager) } func (Self *muxPackagerPool) Put(pack *MuxPackager) { - WindowBuff.Put(pack.Content) Self.pool.Put(pack) } diff --git a/lib/common/util.go b/lib/common/util.go index dc9afbe..e3dfb4f 100755 --- a/lib/common/util.go +++ b/lib/common/util.go @@ -268,6 +268,9 @@ func CopyBuffer(dst io.Writer, src io.Reader) (written int64, err error) { defer CopyBuff.Put(buf) for { nr, er := src.Read(buf) + //if len(pr)>0 && pr[0] && nr > 50 { + // logs.Warn(string(buf[:50])) + //} if nr > 0 { nw, ew := dst.Write(buf[0:nr]) if nw > 0 { diff --git a/lib/install/install.go b/lib/install/install.go index 56f3cc5..24af9b9 100644 --- a/lib/install/install.go +++ b/lib/install/install.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "io" + "io/ioutil" "log" "os" "path/filepath" @@ -13,6 +14,23 @@ import ( ) func InstallNps() { + unit := `[Unit] +Description=nps - convenient proxy server +Documentation=https://github.com/cnlh/nps/ +After=network-online.target remote-fs.target nss-lookup.target +Wants=network-online.target` + service := `[Service] +Type=simple +KillMode=process +Restart=always +RestartSec=15s +StandardOutput=append:/var/log/nps/nps.log +ExecStartPre=/bin/echo 'Starting nps' +ExecStopPost=/bin/echo 'Stopping nps' +ExecStart=` + install := `[Install] +WantedBy=multi-user.target` + path := common.GetInstallPath() if common.FileExists(path) { log.Fatalf("the path %s has exist, does not support install", path) @@ -35,21 +53,35 @@ func InstallNps() { log.Fatalln(err) } else { os.Chmod("/usr/local/bin/nps", 0755) + service += "/usr/local/bin/nps" log.Println("Executable files have been copied to", "/usr/local/bin/nps") } } else { os.Chmod("/usr/bin/nps", 0755) + service += "/usr/bin/nps" log.Println("Executable files have been copied to", "/usr/bin/nps") } - + systemd := unit + "\n\n" + service + "\n\n" + install + _ = os.Remove("/usr/lib/systemd/system/nps.service") + err := ioutil.WriteFile("/usr/lib/systemd/system/nps.service", []byte(systemd), 0644) + if err != nil { + log.Println("Write systemd service err ", err) + } + _ = os.Mkdir("/var/log/nps", 644) } log.Println("install ok!") log.Println("Static files and configuration files in the current directory will be useless") log.Println("The new configuration file is located in", path, "you can edit them") if !common.IsWindows() { - log.Println("You can start with nps test|start|stop|restart|status anywhere") + log.Println(`You can start with: +sudo systemctl enable|disable|start|stop|restart|status nps +or: +nps test|start|stop|restart|status +anywhere!`) } else { - log.Println("You can copy executable files to any directory and start working with nps.exe test|start|stop|restart|status") + log.Println(`You can copy executable files to any directory and start working with: +nps.exe test|start|stop|restart|status +now!`) } } func MkidrDirAll(path string, v ...string) { diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 5dd69ea..c4b47f3 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -183,6 +183,10 @@ func (Self *ReceiveWindow) CalcSize() { n = Self.bufQueue.Len() } // set the minimal size + if n > common.MAXIMUM_WINDOW_SIZE { + n = common.MAXIMUM_WINDOW_SIZE + } + // set the maximum size //logs.Warn("n", n) Self.maxSize = n Self.count = -5 @@ -248,6 +252,10 @@ copyData: l = 0 Self.bw.EndRead() Self.sendStatus(id) + if Self.off == uint32(Self.element.l) { + //logs.Warn("put the element end ", string(Self.element.buf[:15])) + common.WindowBuff.Put(Self.element.buf) + } if pOff < len(p) && Self.element.part { // element is a part of the segments, trying to fill up buf p goto copyData diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 9023b82..529b7dc 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -25,6 +25,7 @@ type Mux struct { pingOk int latency float64 pingCh chan []byte + pingTimer *time.Timer connType string writeQueue PriorityQueue bufCh chan *bytes.Buffer @@ -42,6 +43,7 @@ func NewMux(c net.Conn, connType string) *Mux { connType: connType, bufCh: make(chan *bytes.Buffer), pingCh: make(chan []byte), + pingTimer: time.NewTimer(15 * time.Second), } m.writeQueue.New() //read session by flag @@ -119,6 +121,7 @@ func (s *Mux) packBuf() { common.BuffPool.Put(buffer) break } + //logs.Warn(buffer.String()) select { case s.bufCh <- buffer: case <-s.closeChan: @@ -153,7 +156,7 @@ func (s *Mux) ping() { now, _ := time.Now().UTC().MarshalText() s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, now) // send the ping flag and get the latency first - ticker := time.NewTicker(time.Second * 15) + ticker := time.NewTicker(time.Second * 5) for { if s.IsClose { ticker.Stop() @@ -168,6 +171,10 @@ func (s *Mux) ping() { } now, _ := time.Now().UTC().MarshalText() s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, now) + if !s.pingTimer.Stop() { + <-s.pingTimer.C + } + s.pingTimer.Reset(15 * time.Second) if s.pingOk > 10 && s.connType == "kcp" { s.Close() break @@ -186,10 +193,15 @@ func (s *Mux) pingReturn() { case data = <-s.pingCh: case <-s.closeChan: break + case <-s.pingTimer.C: + logs.Error("mux: ping time out") + s.Close() + break } _ = now.UnmarshalText(data) s.latency = time.Now().UTC().Sub(now).Seconds() / 2 - //logs.Warn("latency", s.latency) + logs.Warn("latency", s.latency) + common.WindowBuff.Put(data) if s.latency <= 0 { logs.Warn("latency err", s.latency) } @@ -218,6 +230,7 @@ func (s *Mux) readSession() { continue case common.MUX_PING_FLAG: //ping s.sendInfo(common.MUX_PING_RETURN, common.MUX_PING, pack.Content) + common.WindowBuff.Put(pack.Content) continue case common.MUX_PING_RETURN: s.pingCh <- pack.Content diff --git a/lib/mux/mux_test.go b/lib/mux/mux_test.go index c7b10e0..abc4eb4 100644 --- a/lib/mux/mux_test.go +++ b/lib/mux/mux_test.go @@ -1,8 +1,11 @@ package mux import ( + "bufio" + "fmt" "net" "net/http" + "net/http/httputil" _ "net/http/pprof" "sync" "testing" @@ -37,6 +40,7 @@ func TestNewMux(t *testing.T) { c2, err := net.Dial("tcp", "127.0.0.1:80") if err != nil { logs.Warn(err) + c.Close() continue } go func(c2 net.Conn, c net.Conn) { @@ -107,6 +111,9 @@ func TestNewMux(t *testing.T) { } }() + time.Sleep(time.Second * 5) + //go test_request() + for { time.Sleep(time.Second * 5) } @@ -135,6 +142,51 @@ func client() { } } +func test_request() { + conn, _ := net.Dial("tcp", "127.0.0.1:7777") + for { + conn.Write([]byte(`GET /videojs5/video.js HTTP/1.1 +Host: 127.0.0.1:7777 +Connection: keep-alive + + +`)) + r, err := http.ReadResponse(bufio.NewReader(conn), nil) + if err != nil { + logs.Warn("close by read response err", err) + break + } + logs.Warn("read response success", r) + b, err := httputil.DumpResponse(r, true) + if err != nil { + logs.Warn("close by dump response err", err) + break + } + fmt.Println(string(b[:20]), err) + time.Sleep(time.Second) + } +} + +func test_raw() { + conn, _ := net.Dial("tcp", "127.0.0.1:7777") + for { + conn.Write([]byte(`GET /videojs5/test HTTP/1.1 +Host: 127.0.0.1:7777 +Connection: keep-alive + + +`)) + buf := make([]byte, 1000000) + n, err := conn.Read(buf) + if err != nil { + logs.Warn("close by read response err", err) + break + } + logs.Warn(n, string(buf[:50]), "\n--------------\n", string(buf[n-50:n])) + time.Sleep(time.Second) + } +} + func TestNewConn(t *testing.T) { buf := common.GetBufPoolCopy() logs.Warn(len(buf), cap(buf)) diff --git a/lib/mux/queue.go b/lib/mux/queue.go index 5a57151..a835e2a 100644 --- a/lib/mux/queue.go +++ b/lib/mux/queue.go @@ -51,15 +51,23 @@ func (Self *PriorityQueue) New() { func (Self *PriorityQueue) Push(packager *common.MuxPackager) { Self.mutex.Lock() - if Self.popWait { - defer Self.allowPop() - } - if packager.Flag == common.MUX_CONN_CLOSE { - Self.insert(packager) // the close package may need priority, - // prevent wait too long to close - } else { + switch packager.Flag { + case common.MUX_PING_FLAG, common.MUX_PING_RETURN: + Self.list.PushFront(packager) + // the ping package need highest priority + // prevent ping calculation error + case common.MUX_CONN_CLOSE: + Self.insert(packager) + // the close package may need priority too, set second + // prevent wait too long to close conn + default: Self.list.PushBack(packager) } + if Self.popWait { + Self.mutex.Unlock() + Self.allowPop() + return + } Self.mutex.Unlock() return } @@ -68,7 +76,14 @@ func (Self *PriorityQueue) insert(packager *common.MuxPackager) { element := Self.list.Back() for { if element == nil { // PriorityQueue dose not have any of msg package with this close package id - Self.list.PushFront(packager) // insert close package to first + element = Self.list.Front() + if element != nil { + Self.list.InsertAfter(packager, element) + // insert close package to second + } else { + Self.list.PushFront(packager) + // list is empty, push to front + } break } if element.Value.(*common.MuxPackager).Flag == common.MUX_NEW_MSG && @@ -136,11 +151,13 @@ func (Self *FIFOQueue) New() { func (Self *FIFOQueue) Push(element *ListElement) { Self.mutex.Lock() - if Self.popWait { - defer Self.allowPop() - } Self.list = append(Self.list, element) Self.length += uint32(element.l) + if Self.popWait { + Self.mutex.Unlock() + Self.allowPop() + return + } Self.mutex.Unlock() return } diff --git a/lib/version/version.go b/lib/version/version.go index 902b30b..4cc0532 100644 --- a/lib/version/version.go +++ b/lib/version/version.go @@ -1,8 +1,8 @@ package version -const VERSION = "0.23.2" +const VERSION = "0.23.3" // Compulsory minimum version, Minimum downward compatibility to this version func GetVersion() string { - return "0.21.0" + return "0.22.0" } From f5d5f633660d7ffb1325dbcb3a18bd2797431ea2 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Sun, 13 Oct 2019 22:45:40 +0800 Subject: [PATCH 40/58] change slide window bandwidth calculation --- lib/common/netpackager.go | 16 ++-- lib/mux/conn.go | 160 +++++++++++++++++++++----------------- lib/mux/map.go | 4 + lib/mux/mux.go | 67 ++++++++++++++-- 4 files changed, 163 insertions(+), 84 deletions(-) diff --git a/lib/common/netpackager.go b/lib/common/netpackager.go index 567a48f..91eeb98 100644 --- a/lib/common/netpackager.go +++ b/lib/common/netpackager.go @@ -65,8 +65,9 @@ func (Self *BasePackager) Pack(writer io.Writer) (err error) { //Unpack 会导致传入的数字类型转化成float64!! //主要原因是json unmarshal并未传入正确的数据类型 -func (Self *BasePackager) UnPack(reader io.Reader) (err error) { +func (Self *BasePackager) UnPack(reader io.Reader) (n uint16, err error) { Self.clean() + n += 2 // uint16 err = binary.Read(reader, binary.LittleEndian, &Self.Length) if err != nil { return @@ -80,6 +81,7 @@ func (Self *BasePackager) UnPack(reader io.Reader) (err error) { // err = io.ErrUnexpectedEOF //} err = binary.Read(reader, binary.LittleEndian, Self.Content) + n += Self.Length return } @@ -137,12 +139,13 @@ func (Self *ConnPackager) Pack(writer io.Writer) (err error) { return } -func (Self *ConnPackager) UnPack(reader io.Reader) (err error) { +func (Self *ConnPackager) UnPack(reader io.Reader) (n uint16, err error) { err = binary.Read(reader, binary.LittleEndian, &Self.ConnType) if err != nil && err != io.EOF { return } - err = Self.BasePackager.UnPack(reader) + n, err = Self.BasePackager.UnPack(reader) + n += 2 return } @@ -203,7 +206,7 @@ func (Self *MuxPackager) Pack(writer io.Writer) (err error) { return } -func (Self *MuxPackager) UnPack(reader io.Reader) (err error) { +func (Self *MuxPackager) UnPack(reader io.Reader) (n uint16, err error) { err = binary.Read(reader, binary.LittleEndian, &Self.Flag) if err != nil { return @@ -216,14 +219,17 @@ func (Self *MuxPackager) UnPack(reader io.Reader) (err error) { case MUX_NEW_MSG, MUX_NEW_MSG_PART, MUX_PING_FLAG, MUX_PING_RETURN: Self.Content = WindowBuff.Get() // need get a window buf from pool Self.BasePackager.clean() // also clean the content - err = Self.BasePackager.UnPack(reader) + n, err = Self.BasePackager.UnPack(reader) //logs.Warn("unpack", Self.Length, string(Self.Content)) case MUX_MSG_SEND_OK: err = binary.Read(reader, binary.LittleEndian, &Self.Window) if err != nil { return } + n += 4 // uint32 err = binary.Read(reader, binary.LittleEndian, &Self.ReadLength) + n += 4 // uint32 } + n += 5 //uint8 int32 return } diff --git a/lib/mux/conn.go b/lib/mux/conn.go index c4b47f3..2d519cb 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -3,7 +3,6 @@ package mux import ( "errors" "io" - "math" "net" "sync" "time" @@ -137,8 +136,8 @@ type ReceiveWindow struct { readWait bool windowFull bool count int8 - bw *bandwidth - once sync.Once + //bw *bandwidth + once sync.Once window } @@ -146,7 +145,7 @@ func (Self *ReceiveWindow) New(mux *Mux) { // initial a window for receive Self.readOp = make(chan struct{}) Self.bufQueue.New() - Self.bw = new(bandwidth) + //Self.bw = new(bandwidth) Self.element = new(ListElement) Self.maxSize = 8192 Self.mux = mux @@ -175,7 +174,7 @@ func (Self *ReceiveWindow) CalcSize() { // calculating maximum receive window size if Self.count == 0 { //logs.Warn("ping, bw", Self.mux.latency, Self.bw.Get()) - n := uint32(2 * Self.mux.latency * Self.bw.Get()) + n := uint32(2 * Self.mux.latency * Self.mux.bw.Get() * 1.5 / float64(Self.mux.connMap.Size())) if n < 8192 { n = 8192 } @@ -183,13 +182,16 @@ func (Self *ReceiveWindow) CalcSize() { n = Self.bufQueue.Len() } // set the minimal size + if n > 2*Self.maxSize { + n = 2 * Self.maxSize + } if n > common.MAXIMUM_WINDOW_SIZE { n = common.MAXIMUM_WINDOW_SIZE } // set the maximum size //logs.Warn("n", n) Self.maxSize = n - Self.count = -5 + Self.count = -10 } Self.count += 1 } @@ -225,7 +227,7 @@ func (Self *ReceiveWindow) Read(p []byte, id int32) (n int, err error) { l := 0 //logs.Warn("receive window read off, element.l", Self.off, Self.element.l) copyData: - Self.bw.StartRead() + //Self.bw.StartRead() if Self.off == uint32(Self.element.l) { // on the first Read method invoked, Self.off and Self.element.l // both zero value @@ -241,7 +243,7 @@ copyData: //logs.Warn("pop element", Self.element.l, Self.element.part) } l = copy(p[pOff:], Self.element.buf[Self.off:]) - Self.bw.SetCopySize(l) + //Self.bw.SetCopySize(l) pOff += l Self.off += uint32(l) Self.bufQueue.mutex.Lock() @@ -250,7 +252,7 @@ copyData: Self.bufQueue.mutex.Unlock() n += l l = 0 - Self.bw.EndRead() + //Self.bw.EndRead() Self.sendStatus(id) if Self.off == uint32(Self.element.l) { //logs.Warn("put the element end ", string(Self.element.buf[:15])) @@ -469,65 +471,81 @@ func (Self *SendWindow) SetTimeOut(t time.Time) { Self.timeout = t } -type bandwidth struct { - lastReadStart time.Time - readStart time.Time - readEnd time.Time - bufLength int - lastBufLength int - count int8 - readBW float64 - writeBW float64 -} - -func (Self *bandwidth) StartRead() { - Self.lastReadStart, Self.readStart = Self.readStart, time.Now() -} - -func (Self *bandwidth) EndRead() { - if !Self.lastReadStart.IsZero() { - if Self.count == 0 { - Self.calcWriteBandwidth() - } - } - Self.readEnd = time.Now() - if Self.count == 0 { - Self.calcReadBandwidth() - Self.count = -3 - } - Self.count += 1 -} - -func (Self *bandwidth) SetCopySize(n int) { - // must be invoke between StartRead and EndRead - Self.lastBufLength, Self.bufLength = Self.bufLength, n -} - -func (Self *bandwidth) calcReadBandwidth() { - // Bandwidth between nps and npc - readTime := Self.readEnd.Sub(Self.readStart) - Self.readBW = float64(Self.bufLength) / readTime.Seconds() - //logs.Warn("calc read bw", Self.bufLength, readTime.Seconds()) -} - -func (Self *bandwidth) calcWriteBandwidth() { - // Bandwidth between nps and user, npc and application - //logs.Warn("calc write bw") - writeTime := Self.readEnd.Sub(Self.lastReadStart) - Self.writeBW = float64(Self.lastBufLength) / writeTime.Seconds() -} - -func (Self *bandwidth) Get() (bw float64) { - // The zero value, 0 for numeric types - if Self.writeBW == 0 && Self.readBW == 0 { - //logs.Warn("bw both 0") - return 100 - } - if Self.writeBW == 0 && Self.readBW != 0 { - return Self.readBW - } - if Self.readBW == 0 && Self.writeBW != 0 { - return Self.writeBW - } - return math.Min(Self.readBW, Self.writeBW) -} +//type bandwidth struct { +// readStart time.Time +// lastReadStart time.Time +// readEnd time.Time +// lastReadEnd time.Time +// bufLength int +// lastBufLength int +// count int8 +// readBW float64 +// writeBW float64 +// readBandwidth float64 +//} +// +//func (Self *bandwidth) StartRead() { +// Self.lastReadStart, Self.readStart = Self.readStart, time.Now() +// if !Self.lastReadStart.IsZero() { +// if Self.count == -5 { +// Self.calcBandWidth() +// } +// } +//} +// +//func (Self *bandwidth) EndRead() { +// Self.lastReadEnd, Self.readEnd = Self.readEnd, time.Now() +// if Self.count == -5 { +// Self.calcWriteBandwidth() +// } +// if Self.count == 0 { +// Self.calcReadBandwidth() +// Self.count = -6 +// } +// Self.count += 1 +//} +// +//func (Self *bandwidth) SetCopySize(n int) { +// // must be invoke between StartRead and EndRead +// Self.lastBufLength, Self.bufLength = Self.bufLength, n +//} +//// calculating +//// start end start end +//// read read +//// write +// +//func (Self *bandwidth) calcBandWidth() { +// t := Self.readStart.Sub(Self.lastReadStart) +// if Self.lastBufLength >= 32768 { +// Self.readBandwidth = float64(Self.lastBufLength) / t.Seconds() +// } +//} +// +//func (Self *bandwidth) calcReadBandwidth() { +// // Bandwidth between nps and npc +// readTime := Self.readEnd.Sub(Self.readStart) +// Self.readBW = float64(Self.bufLength) / readTime.Seconds() +// //logs.Warn("calc read bw", Self.readBW, Self.bufLength, readTime.Seconds()) +//} +// +//func (Self *bandwidth) calcWriteBandwidth() { +// // Bandwidth between nps and user, npc and application +// writeTime := Self.readStart.Sub(Self.lastReadEnd) +// Self.writeBW = float64(Self.lastBufLength) / writeTime.Seconds() +// //logs.Warn("calc write bw", Self.writeBW, Self.bufLength, writeTime.Seconds()) +//} +// +//func (Self *bandwidth) Get() (bw float64) { +// // The zero value, 0 for numeric types +// if Self.writeBW == 0 && Self.readBW == 0 { +// //logs.Warn("bw both 0") +// return 100 +// } +// if Self.writeBW == 0 && Self.readBW != 0 { +// return Self.readBW +// } +// if Self.readBW == 0 && Self.writeBW != 0 { +// return Self.writeBW +// } +// return Self.readBandwidth +//} diff --git a/lib/mux/map.go b/lib/mux/map.go index 0801201..8f07dee 100644 --- a/lib/mux/map.go +++ b/lib/mux/map.go @@ -20,6 +20,10 @@ func NewConnMap() *connMap { return connMap } +func (s *connMap) Size() (n int) { + return len(s.connMap) +} + func (s *connMap) Get(id int32) (*conn, bool) { s.Lock() defer s.Unlock() diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 529b7dc..42aa8c8 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -24,6 +24,7 @@ type Mux struct { IsClose bool pingOk int latency float64 + bw *bandwidth pingCh chan []byte pingTimer *time.Timer connType string @@ -37,8 +38,9 @@ func NewMux(c net.Conn, connType string) *Mux { conn: c, connMap: NewConnMap(), id: 0, - closeChan: make(chan struct{}), + closeChan: make(chan struct{}, 3), newConnCh: make(chan *conn), + bw: new(bandwidth), IsClose: false, connType: connType, bufCh: make(chan *bytes.Buffer), @@ -91,6 +93,9 @@ func (s *Mux) Addr() net.Addr { } func (s *Mux) sendInfo(flag uint8, id int32, data ...interface{}) { + if s.IsClose { + return + } var err error pack := common.MuxPack.Get() err = pack.NewPac(flag, id, data...) @@ -160,6 +165,9 @@ func (s *Mux) ping() { for { if s.IsClose { ticker.Stop() + if !s.pingTimer.Stop() { + <-s.pingTimer.C + } break } select { @@ -189,6 +197,9 @@ func (s *Mux) pingReturn() { var now time.Time var data []byte for { + if s.IsClose { + break + } select { case data = <-s.pingCh: case <-s.closeChan: @@ -199,12 +210,12 @@ func (s *Mux) pingReturn() { break } _ = now.UnmarshalText(data) - s.latency = time.Now().UTC().Sub(now).Seconds() / 2 - logs.Warn("latency", s.latency) - common.WindowBuff.Put(data) - if s.latency <= 0 { - logs.Warn("latency err", s.latency) + latency := time.Now().UTC().Sub(now).Seconds() / 2 + if latency < 0.5 && latency > 0 { + s.latency = latency } + //logs.Warn("latency", s.latency) + common.WindowBuff.Put(data) } }() } @@ -212,14 +223,18 @@ func (s *Mux) pingReturn() { func (s *Mux) readSession() { go func() { pack := common.MuxPack.Get() + var l uint16 + var err error for { if s.IsClose { break } pack = common.MuxPack.Get() - if pack.UnPack(s.conn) != nil { + s.bw.StartRead() + if l, err = pack.UnPack(s.conn); err != nil { break } + s.bw.SetCopySize(l) s.pingOk = 0 switch pack.Flag { case common.MUX_NEW_CONN: //new connection @@ -239,7 +254,7 @@ func (s *Mux) readSession() { if connection, ok := s.connMap.Get(pack.Id); ok && !connection.isClose { switch pack.Flag { case common.MUX_NEW_MSG, common.MUX_NEW_MSG_PART: //new msg from remote connection - err := s.newMsg(connection, pack) + err = s.newMsg(connection, pack) if err != nil { connection.Close() } @@ -299,6 +314,7 @@ func (s *Mux) Close() error { s.connMap.Close() s.closeChan <- struct{}{} s.closeChan <- struct{}{} + s.closeChan <- struct{}{} close(s.newConnCh) return s.conn.Close() } @@ -311,3 +327,38 @@ func (s *Mux) getId() (id int32) { } return } + +type bandwidth struct { + readStart time.Time + lastReadStart time.Time + bufLength uint16 + readBandwidth float64 +} + +func (Self *bandwidth) StartRead() { + if Self.readStart.IsZero() { + Self.readStart = time.Now() + } + if Self.bufLength >= 16384 { + Self.lastReadStart, Self.readStart = Self.readStart, time.Now() + Self.calcBandWidth() + } +} + +func (Self *bandwidth) SetCopySize(n uint16) { + Self.bufLength += n +} + +func (Self *bandwidth) calcBandWidth() { + t := Self.readStart.Sub(Self.lastReadStart) + Self.readBandwidth = float64(Self.bufLength) / t.Seconds() + Self.bufLength = 0 +} + +func (Self *bandwidth) Get() (bw float64) { + // The zero value, 0 for numeric types + if Self.readBandwidth <= 0 { + Self.readBandwidth = 100 + } + return Self.readBandwidth +} From 18ca5d04ccf2733c818160addb2f6526d483db5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B2=B3?= Date: Mon, 14 Oct 2019 23:44:07 +0800 Subject: [PATCH 41/58] connection trace web server --- lib/mux/web.go | 97 +++++++++++++++++++++++++++++++++++++++++++++ lib/mux/web_test.go | 7 ++++ 2 files changed, 104 insertions(+) create mode 100644 lib/mux/web.go create mode 100644 lib/mux/web_test.go diff --git a/lib/mux/web.go b/lib/mux/web.go new file mode 100644 index 0000000..0ebe8e7 --- /dev/null +++ b/lib/mux/web.go @@ -0,0 +1,97 @@ +package mux + +import ( + "fmt" + "net/http" + "sort" + "strconv" + "time" +) + +type connLog struct { + startTime time.Time + isClose bool + logs []string +} + +var m map[int]*connLog + +var copyMap map[int]*connLog + +func deepCopyMap() { + copyMap = make(map[int]*connLog) + for k, v := range m { + copyMap[k] = &connLog{ + startTime: v.startTime, + isClose: v.isClose, + logs: v.logs, + } + } +} + +//func init() { +// m = make(map[int]*connLog) +// m[0] = &connLog{ +// startTime: time.Now(), +// isClose: false, +// logs: []string{"111", "222", "333"}, +// } +// m[1] = &connLog{ +// startTime: time.Now(), +// isClose: false, +// logs: []string{"111", "222", "333", "444"}, +// } +// m[2] = &connLog{ +// startTime: time.Now(), +// isClose: true, +// logs: []string{"111", "222", "333", "555"}, +// } +//} + +type IntSlice []int + +func (s IntSlice) Len() int { return len(s) } + +func (s IntSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +func (s IntSlice) Less(i, j int) bool { return s[i] < s[j] } + +func NewLogServer() { + http.HandleFunc("/", index) + http.HandleFunc("/detail", detail) + http.HandleFunc("/stash", stash) + fmt.Println(http.ListenAndServe(":8899", nil)) +} + +func stash(w http.ResponseWriter, r *http.Request) { + deepCopyMap() + w.Write([]byte("ok")) +} + +func index(w http.ResponseWriter, r *http.Request) { + var keys []int + for k := range copyMap { + keys = append(keys, k) + } + sort.Sort(IntSlice(keys)) + var s string + for v := range keys { + connL := copyMap[v] + s += "" + strconv.Itoa(v) + "----------" + s += strconv.Itoa(int(time.Now().Unix()-connL.startTime.Unix())) + "s----------" + s += strconv.FormatBool(connL.isClose) + s += "
" + } + w.Write([]byte(s)) +} + +func detail(w http.ResponseWriter, r *http.Request) { + id := r.FormValue("id") + i, _ := strconv.Atoi(id) + v, _ := copyMap[i] + var s string + for _, vv := range v.logs { + s += "

" + vv + "

" + } + w.Write([]byte(s)) +} diff --git a/lib/mux/web_test.go b/lib/mux/web_test.go new file mode 100644 index 0000000..91a0430 --- /dev/null +++ b/lib/mux/web_test.go @@ -0,0 +1,7 @@ +package mux + +import "testing" + +func TestWeb(t *testing.T) { + NewLogServer() +} From d23ed2126dc97eef6648a7839771953bdd615372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B2=B3?= Date: Mon, 14 Oct 2019 23:46:00 +0800 Subject: [PATCH 42/58] change now time --- lib/mux/web.go | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/lib/mux/web.go b/lib/mux/web.go index 0ebe8e7..d654f15 100644 --- a/lib/mux/web.go +++ b/lib/mux/web.go @@ -17,8 +17,10 @@ type connLog struct { var m map[int]*connLog var copyMap map[int]*connLog +var stashTimeNow time.Time func deepCopyMap() { + stashTimeNow = time.Now() copyMap = make(map[int]*connLog) for k, v := range m { copyMap[k] = &connLog{ @@ -29,24 +31,24 @@ func deepCopyMap() { } } -//func init() { -// m = make(map[int]*connLog) -// m[0] = &connLog{ -// startTime: time.Now(), -// isClose: false, -// logs: []string{"111", "222", "333"}, -// } -// m[1] = &connLog{ -// startTime: time.Now(), -// isClose: false, -// logs: []string{"111", "222", "333", "444"}, -// } -// m[2] = &connLog{ -// startTime: time.Now(), -// isClose: true, -// logs: []string{"111", "222", "333", "555"}, -// } -//} +func init() { + m = make(map[int]*connLog) + m[0] = &connLog{ + startTime: time.Now(), + isClose: false, + logs: []string{"111", "222", "333"}, + } + m[1] = &connLog{ + startTime: time.Now(), + isClose: false, + logs: []string{"111", "222", "333", "444"}, + } + m[2] = &connLog{ + startTime: time.Now(), + isClose: true, + logs: []string{"111", "222", "333", "555"}, + } +} type IntSlice []int @@ -78,7 +80,7 @@ func index(w http.ResponseWriter, r *http.Request) { for v := range keys { connL := copyMap[v] s += "" + strconv.Itoa(v) + "----------" - s += strconv.Itoa(int(time.Now().Unix()-connL.startTime.Unix())) + "s----------" + s += strconv.Itoa(int(stashTimeNow.Unix()-connL.startTime.Unix())) + "s----------" s += strconv.FormatBool(connL.isClose) s += "
" } From c2f4510a0f3c91852092263c16a2540e4236a658 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Tue, 15 Oct 2019 16:32:21 +0800 Subject: [PATCH 43/58] add test code --- lib/mux/conn.go | 26 +++++++++- lib/mux/mux.go | 4 +- lib/mux/mux_test.go | 1 + lib/mux/web.go | 119 ++++++++++++++++++++++++++++++++------------ 4 files changed, 115 insertions(+), 35 deletions(-) diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 2d519cb..dc3063c 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -4,6 +4,7 @@ import ( "errors" "io" "net" + "strconv" "sync" "time" @@ -21,9 +22,10 @@ type conn struct { receiveWindow *ReceiveWindow sendWindow *SendWindow once sync.Once + label string } -func NewConn(connId int32, mux *Mux) *conn { +func NewConn(connId int32, mux *Mux, label ...string) *conn { c := &conn{ getStatusCh: make(chan struct{}), connStatusOkCh: make(chan struct{}), @@ -33,8 +35,17 @@ func NewConn(connId int32, mux *Mux) *conn { sendWindow: new(SendWindow), once: sync.Once{}, } + if len(label) > 0 { + c.label = label[0] + } c.receiveWindow.New(mux) c.sendWindow.New(mux) + logm := &connLog{ + startTime: time.Now(), + isClose: false, + logs: []string{c.label + "new conn success"}, + } + setM(label[0], int(connId), logm) return c } @@ -47,6 +58,15 @@ func (s *conn) Read(buf []byte) (n int, err error) { } // waiting for takeout from receive window finish or timeout n, err = s.receiveWindow.Read(buf, s.connId) + var errstr string + if err == nil { + errstr = "err:nil" + } else { + errstr = err.Error() + } + d := getM(s.label, int(s.connId)) + d.logs = append(d.logs, s.label+"read "+strconv.Itoa(n)+" "+errstr) + setM(s.label, int(s.connId), d) return } @@ -81,6 +101,10 @@ func (s *conn) closeProcess() { } s.sendWindow.CloseWindow() s.receiveWindow.CloseWindow() + d := getM(s.label, int(s.connId)) + d.isClose = true + d.logs = append(d.logs, s.label+"close "+time.Now().String()) + setM(s.label, int(s.connId), d) return } diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 42aa8c8..c24c0bc 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -61,7 +61,7 @@ func (s *Mux) NewConn() (*conn, error) { if s.IsClose { return nil, errors.New("the mux has closed") } - conn := NewConn(s.getId(), s) + conn := NewConn(s.getId(), s, "nps ") //it must be set before send s.connMap.Set(conn.connId, conn) s.sendInfo(common.MUX_NEW_CONN, conn.connId, nil) @@ -238,7 +238,7 @@ func (s *Mux) readSession() { s.pingOk = 0 switch pack.Flag { case common.MUX_NEW_CONN: //new connection - connection := NewConn(pack.Id, s) + connection := NewConn(pack.Id, s, "npc ") s.connMap.Set(pack.Id, connection) //it has been set before send ok s.newConnCh <- connection s.sendInfo(common.MUX_NEW_CONN_OK, connection.connId, nil) diff --git a/lib/mux/mux_test.go b/lib/mux/mux_test.go index abc4eb4..1ef71f6 100644 --- a/lib/mux/mux_test.go +++ b/lib/mux/mux_test.go @@ -111,6 +111,7 @@ func TestNewMux(t *testing.T) { } }() + go NewLogServer() time.Sleep(time.Second * 5) //go test_request() diff --git a/lib/mux/web.go b/lib/mux/web.go index d654f15..36b2017 100644 --- a/lib/mux/web.go +++ b/lib/mux/web.go @@ -2,9 +2,12 @@ package mux import ( "fmt" + "github.com/astaxie/beego/logs" "net/http" "sort" "strconv" + "strings" + "sync" "time" ) @@ -14,16 +17,29 @@ type connLog struct { logs []string } -var m map[int]*connLog +var logms map[int]*connLog +var logmc map[int]*connLog -var copyMap map[int]*connLog +var copyMaps map[int]*connLog +var copyMapc map[int]*connLog var stashTimeNow time.Time +var mutex sync.Mutex -func deepCopyMap() { - stashTimeNow = time.Now() - copyMap = make(map[int]*connLog) - for k, v := range m { - copyMap[k] = &connLog{ +func deepCopyMaps() { + copyMaps = make(map[int]*connLog) + for k, v := range logms { + copyMaps[k] = &connLog{ + startTime: v.startTime, + isClose: v.isClose, + logs: v.logs, + } + } +} + +func deepCopyMapc() { + copyMapc = make(map[int]*connLog) + for k, v := range logmc { + copyMapc[k] = &connLog{ startTime: v.startTime, isClose: v.isClose, logs: v.logs, @@ -32,22 +48,8 @@ func deepCopyMap() { } func init() { - m = make(map[int]*connLog) - m[0] = &connLog{ - startTime: time.Now(), - isClose: false, - logs: []string{"111", "222", "333"}, - } - m[1] = &connLog{ - startTime: time.Now(), - isClose: false, - logs: []string{"111", "222", "333", "444"}, - } - m[2] = &connLog{ - startTime: time.Now(), - isClose: true, - logs: []string{"111", "222", "333", "555"}, - } + logms = make(map[int]*connLog) + logmc = make(map[int]*connLog) } type IntSlice []int @@ -66,21 +68,64 @@ func NewLogServer() { } func stash(w http.ResponseWriter, r *http.Request) { - deepCopyMap() + stashTimeNow = time.Now() + deepCopyMaps() + deepCopyMapc() w.Write([]byte("ok")) } +func getM(label string, id int) (cL *connLog) { + label = strings.TrimSpace(label) + mutex.Lock() + defer mutex.Unlock() + if label == "nps" { + cL = logms[id] + } + if label == "npc" { + cL = logmc[id] + } + return +} + +func setM(label string, id int, cL *connLog) { + label = strings.TrimSpace(label) + mutex.Lock() + defer mutex.Unlock() + if label == "nps" { + logms[id] = cL + } + if label == "npc" { + logmc[id] = cL + } +} + func index(w http.ResponseWriter, r *http.Request) { var keys []int - for k := range copyMap { + for k := range copyMaps { keys = append(keys, k) } sort.Sort(IntSlice(keys)) var s string - for v := range keys { - connL := copyMap[v] - s += "" + strconv.Itoa(v) + "----------" - s += strconv.Itoa(int(stashTimeNow.Unix()-connL.startTime.Unix())) + "s----------" + s += "

nps

" + for _, v := range keys { + connL := copyMaps[v] + s += "" + strconv.Itoa(v) + "----------" + s += strconv.Itoa(int(stashTimeNow.Sub(connL.startTime).Milliseconds())) + "ms----------" + s += strconv.FormatBool(connL.isClose) + s += "
" + } + + keys = keys[:0] + s += "

npc

" + for k := range copyMapc { + keys = append(keys, k) + } + sort.Sort(IntSlice(keys)) + + for _, v := range keys { + connL := copyMapc[v] + s += "" + strconv.Itoa(v) + "----------" + s += strconv.Itoa(int(stashTimeNow.Sub(connL.startTime).Milliseconds())) + "ms----------" s += strconv.FormatBool(connL.isClose) s += "
" } @@ -89,11 +134,21 @@ func index(w http.ResponseWriter, r *http.Request) { func detail(w http.ResponseWriter, r *http.Request) { id := r.FormValue("id") + label := r.FormValue("label") + logs.Warn(label) i, _ := strconv.Atoi(id) - v, _ := copyMap[i] + var v *connLog + if label == "nps" { + v, _ = copyMaps[i] + } + if label == "npc" { + v, _ = copyMapc[i] + } var s string - for _, vv := range v.logs { - s += "

" + vv + "

" + if v != nil { + for i, vv := range v.logs { + s += "

" + strconv.Itoa(i+1) + ":" + vv + "

" + } } w.Write([]byte(s)) } From 23b023c562e582d3c52f1ade00168ab5e900dc0c Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Mon, 21 Oct 2019 11:55:29 +0800 Subject: [PATCH 44/58] add lock free queue --- lib/common/util.go | 2 +- lib/mux/conn.go | 16 +- lib/mux/mux.go | 10 +- lib/mux/mux_test.go | 132 +++++++++++---- lib/mux/queue.go | 390 ++++++++++++++++++++++++++++++++++---------- 5 files changed, 419 insertions(+), 131 deletions(-) diff --git a/lib/common/util.go b/lib/common/util.go index e3dfb4f..1f54a6f 100755 --- a/lib/common/util.go +++ b/lib/common/util.go @@ -263,7 +263,7 @@ func GetPortByAddr(addr string) int { return p } -func CopyBuffer(dst io.Writer, src io.Reader) (written int64, err error) { +func CopyBuffer(dst io.Writer, src io.Reader, label ...string) (written int64, err error) { buf := CopyBuff.Get() defer CopyBuff.Put(buf) for { diff --git a/lib/mux/conn.go b/lib/mux/conn.go index dc3063c..3011732 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -2,10 +2,12 @@ package mux import ( "errors" + "github.com/astaxie/beego/logs" "io" "net" "strconv" "sync" + "sync/atomic" "time" "github.com/cnlh/nps/lib/common" @@ -65,7 +67,7 @@ func (s *conn) Read(buf []byte) (n int, err error) { errstr = err.Error() } d := getM(s.label, int(s.connId)) - d.logs = append(d.logs, s.label+"read "+strconv.Itoa(n)+" "+errstr) + d.logs = append(d.logs, s.label+"read "+strconv.Itoa(n)+" "+errstr+" "+string(buf[:100])) setM(s.label, int(s.connId), d) return } @@ -187,11 +189,7 @@ func (Self *ReceiveWindow) RemainingSize() (n uint32) { func (Self *ReceiveWindow) ReadSize() (n uint32) { // acknowledge the size already read - Self.bufQueue.mutex.Lock() - n = Self.readLength - Self.readLength = 0 - Self.bufQueue.mutex.Unlock() - return + return atomic.SwapUint32(&Self.readLength, 0) } func (Self *ReceiveWindow) CalcSize() { @@ -270,10 +268,8 @@ copyData: //Self.bw.SetCopySize(l) pOff += l Self.off += uint32(l) - Self.bufQueue.mutex.Lock() - Self.readLength += uint32(l) + atomic.AddUint32(&Self.readLength, uint32(l)) //logs.Warn("window read length buf len", Self.readLength, Self.bufQueue.Len()) - Self.bufQueue.mutex.Unlock() n += l l = 0 //Self.bw.EndRead() @@ -422,6 +418,7 @@ func (Self *SendWindow) WriteTo() (p []byte, part bool, err error) { if len(Self.buf[Self.off:]) > common.MAXIMUM_SEGMENT_SIZE { sendSize = common.MAXIMUM_SEGMENT_SIZE part = true + logs.Warn("cut buf by mss") } else { sendSize = uint32(len(Self.buf[Self.off:])) part = false @@ -430,6 +427,7 @@ func (Self *SendWindow) WriteTo() (p []byte, part bool, err error) { // usable window size is small than // window MAXIMUM_SEGMENT_SIZE or send buf left sendSize = Self.RemainingSize() + logs.Warn("cut buf by remainingsize", sendSize, len(Self.buf[Self.off:])) part = true } //logs.Warn("send size", sendSize) diff --git a/lib/mux/mux.go b/lib/mux/mux.go index c24c0bc..6f08641 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -34,6 +34,8 @@ type Mux struct { } func NewMux(c net.Conn, connType string) *Mux { + //c.(*net.TCPConn).SetReadBuffer(0) + //c.(*net.TCPConn).SetWriteBuffer(0) m := &Mux{ conn: c, connMap: NewConnMap(), @@ -173,10 +175,6 @@ func (s *Mux) ping() { select { case <-ticker.C: } - //Avoid going beyond the scope - if (math.MaxInt32 - s.id) < 10000 { - s.id = 0 - } now, _ := time.Now().UTC().MarshalText() s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, now) if !s.pingTimer.Stop() { @@ -321,6 +319,10 @@ func (s *Mux) Close() error { //get new connId as unique flag func (s *Mux) getId() (id int32) { + //Avoid going beyond the scope + if (math.MaxInt32 - s.id) < 10000 { + atomic.SwapInt32(&s.id, 0) + } id = atomic.AddInt32(&s.id, 1) if _, ok := s.connMap.Get(id); ok { s.getId() diff --git a/lib/mux/mux_test.go b/lib/mux/mux_test.go index 1ef71f6..43e12e8 100644 --- a/lib/mux/mux_test.go +++ b/lib/mux/mux_test.go @@ -3,13 +3,16 @@ package mux import ( "bufio" "fmt" + "io" "net" "net/http" "net/http/httputil" _ "net/http/pprof" + "strconv" "sync" "testing" "time" + "unsafe" "github.com/astaxie/beego/logs" "github.com/cnlh/nps/lib/common" @@ -30,20 +33,22 @@ func TestNewMux(t *testing.T) { go func() { m2 := NewMux(conn2, "tcp") for { - logs.Warn("npc starting accept") + //logs.Warn("npc starting accept") c, err := m2.Accept() if err != nil { logs.Warn(err) continue } - logs.Warn("npc accept success ") + //logs.Warn("npc accept success ") c2, err := net.Dial("tcp", "127.0.0.1:80") if err != nil { logs.Warn(err) c.Close() continue } - go func(c2 net.Conn, c net.Conn) { + //c2.(*net.TCPConn).SetReadBuffer(0) + //c2.(*net.TCPConn).SetReadBuffer(0) + go func(c2 net.Conn, c *conn) { wg := sync.WaitGroup{} wg.Add(1) go func() { @@ -51,7 +56,7 @@ func TestNewMux(t *testing.T) { if err != nil { c2.Close() c.Close() - logs.Warn("close npc by copy from nps", err) + logs.Warn("close npc by copy from nps", err, c.connId) } wg.Done() }() @@ -61,13 +66,13 @@ func TestNewMux(t *testing.T) { if err != nil { c2.Close() c.Close() - logs.Warn("close npc by copy from server", err) + logs.Warn("close npc by copy from server", err, c.connId) } wg.Done() }() - logs.Warn("npc wait") + //logs.Warn("npc wait") wg.Wait() - }(c2, c) + }(c2, c.(*conn)) } }() @@ -78,42 +83,46 @@ func TestNewMux(t *testing.T) { logs.Warn(err) } for { - logs.Warn("nps starting accept") - conn, err := l.Accept() + //logs.Warn("nps starting accept") + conns, err := l.Accept() if err != nil { logs.Warn(err) continue } - logs.Warn("nps accept success starting new conn") + //conns.(*net.TCPConn).SetReadBuffer(0) + //conns.(*net.TCPConn).SetReadBuffer(0) + //logs.Warn("nps accept success starting new conn") tmpCpnn, err := m1.NewConn() if err != nil { logs.Warn("nps new conn err ", err) continue } logs.Warn("nps new conn success ", tmpCpnn.connId) - go func(tmpCpnn net.Conn, conn net.Conn) { + go func(tmpCpnn *conn, conns net.Conn) { go func() { - _, err := common.CopyBuffer(tmpCpnn, conn) + _, err := common.CopyBuffer(tmpCpnn, conns) if err != nil { - conn.Close() + conns.Close() tmpCpnn.Close() - logs.Warn("close nps by copy from user") + logs.Warn("close nps by copy from user", tmpCpnn.connId, err) } }() //time.Sleep(time.Second) - _, err = common.CopyBuffer(conn, tmpCpnn) + _, err = common.CopyBuffer(conns, tmpCpnn) if err != nil { - conn.Close() + conns.Close() tmpCpnn.Close() - logs.Warn("close nps by copy from npc ") + logs.Warn("close nps by copy from npc ", tmpCpnn.connId, err) } - }(tmpCpnn, conn) + }(tmpCpnn, conns) } }() go NewLogServer() time.Sleep(time.Second * 5) - //go test_request() + //for i:=0;i<1000;i++ { + // go test_raw(i) + //} for { time.Sleep(time.Second * 5) @@ -168,23 +177,40 @@ Connection: keep-alive } } -func test_raw() { - conn, _ := net.Dial("tcp", "127.0.0.1:7777") - for { - conn.Write([]byte(`GET /videojs5/test HTTP/1.1 +func test_raw(k int) { + for i := 0; i < 1; i++ { + ti := time.Now() + conn, _ := net.Dial("tcp", "127.0.0.1:7777") + tid := time.Now() + conn.Write([]byte(`GET / HTTP/1.1 Host: 127.0.0.1:7777 -Connection: keep-alive `)) - buf := make([]byte, 1000000) - n, err := conn.Read(buf) + tiw := time.Now() + buf := make([]byte, 3572) + n, err := io.ReadFull(conn, buf) + //n, err := conn.Read(buf) if err != nil { logs.Warn("close by read response err", err) break } - logs.Warn(n, string(buf[:50]), "\n--------------\n", string(buf[n-50:n])) - time.Sleep(time.Second) + //logs.Warn(n, string(buf[:50]), "\n--------------\n", string(buf[n-50:n])) + //time.Sleep(time.Second) + err = conn.Close() + if err != nil { + logs.Warn("close conn err ", err) + } + now := time.Now() + du := now.Sub(ti).Seconds() + dud := now.Sub(tid).Seconds() + duw := now.Sub(tiw).Seconds() + if du > 1 { + logs.Warn("duration long", du, dud, duw, k, i) + } + if n != 3572 { + logs.Warn("n loss", n, string(buf)) + } } } @@ -199,3 +225,53 @@ func TestNewConn(t *testing.T) { logs.Warn(copy(buf[:3], b), len(buf), cap(buf)) logs.Warn(len(buf), buf[0]) } + +func TestDQueue(t *testing.T) { + logs.EnableFuncCallDepth(true) + logs.SetLogFuncCallDepth(3) + d := new(bufDequeue) + d.vals = make([]unsafe.Pointer, 8) + go func() { + time.Sleep(time.Second) + for i := 0; i < 10; i++ { + logs.Warn(i) + logs.Warn(d.popTail()) + } + }() + go func() { + time.Sleep(time.Second) + for i := 0; i < 10; i++ { + data := "test" + go logs.Warn(i, unsafe.Pointer(&data), d.pushHead(unsafe.Pointer(&data))) + } + }() + time.Sleep(time.Second * 3) +} + +func TestChain(t *testing.T) { + logs.EnableFuncCallDepth(true) + logs.SetLogFuncCallDepth(3) + d := new(bufChain) + d.new(256) + go func() { + time.Sleep(time.Second) + for i := 0; i < 1000; i++ { + unsa, ok := d.popTail() + str := (*string)(unsa) + if ok { + logs.Warn(i, str, *str, ok) + } else { + logs.Warn("nil", i, ok) + } + } + }() + go func() { + time.Sleep(time.Second) + for i := 0; i < 1000; i++ { + data := "test " + strconv.Itoa(i) + logs.Warn(data, unsafe.Pointer(&data)) + go d.pushHead(unsafe.Pointer(&data)) + } + }() + time.Sleep(time.Second * 10) +} diff --git a/lib/mux/queue.go b/lib/mux/queue.go index a835e2a..ef0c904 100644 --- a/lib/mux/queue.go +++ b/lib/mux/queue.go @@ -1,19 +1,19 @@ package mux import ( - "container/list" "errors" "github.com/cnlh/nps/lib/common" "io" - "sync" + "math" + "sync/atomic" "time" + "unsafe" ) type QueueOp struct { readOp chan struct{} cleanOp chan struct{} - popWait bool - mutex sync.Mutex + popWait int32 } func (Self *QueueOp) New() { @@ -22,15 +22,15 @@ func (Self *QueueOp) New() { } func (Self *QueueOp) allowPop() (closed bool) { - Self.mutex.Lock() - Self.popWait = false - Self.mutex.Unlock() - select { - case Self.readOp <- struct{}{}: - return false - case <-Self.cleanOp: - return true + if atomic.CompareAndSwapInt32(&Self.popWait, 1, 0) { + select { + case Self.readOp <- struct{}{}: + return false + case <-Self.cleanOp: + return true + } } + return } func (Self *QueueOp) Clean() { @@ -40,84 +40,72 @@ func (Self *QueueOp) Clean() { } type PriorityQueue struct { - list *list.List QueueOp + highestChain *bufChain + middleChain *bufChain + lowestChain *bufChain + hunger uint8 } func (Self *PriorityQueue) New() { - Self.list = list.New() + Self.highestChain = new(bufChain) + Self.highestChain.new(4) + Self.middleChain = new(bufChain) + Self.middleChain.new(32) + Self.lowestChain = new(bufChain) + Self.lowestChain.new(256) Self.QueueOp.New() } func (Self *PriorityQueue) Push(packager *common.MuxPackager) { - Self.mutex.Lock() switch packager.Flag { case common.MUX_PING_FLAG, common.MUX_PING_RETURN: - Self.list.PushFront(packager) + Self.highestChain.pushHead(unsafe.Pointer(packager)) // the ping package need highest priority // prevent ping calculation error - case common.MUX_CONN_CLOSE: - Self.insert(packager) - // the close package may need priority too, set second - // prevent wait too long to close conn + case common.MUX_NEW_CONN, common.MUX_NEW_CONN_OK, common.MUX_NEW_CONN_Fail: + // the new conn package need some priority too + Self.middleChain.pushHead(unsafe.Pointer(packager)) default: - Self.list.PushBack(packager) + Self.lowestChain.pushHead(unsafe.Pointer(packager)) } - if Self.popWait { - Self.mutex.Unlock() - Self.allowPop() - return - } - Self.mutex.Unlock() + Self.allowPop() return } -func (Self *PriorityQueue) insert(packager *common.MuxPackager) { - element := Self.list.Back() - for { - if element == nil { // PriorityQueue dose not have any of msg package with this close package id - element = Self.list.Front() - if element != nil { - Self.list.InsertAfter(packager, element) - // insert close package to second - } else { - Self.list.PushFront(packager) - // list is empty, push to front - } - break - } - if element.Value.(*common.MuxPackager).Flag == common.MUX_NEW_MSG && - element.Value.(*common.MuxPackager).Id == packager.Id { - Self.list.InsertAfter(packager, element) // PriorityQueue has some msg package - // with this close package id, insert close package after last msg package - break - } - element = element.Prev() - } -} - func (Self *PriorityQueue) Pop() (packager *common.MuxPackager) { - Self.mutex.Lock() - element := Self.list.Front() - if element != nil { - packager = element.Value.(*common.MuxPackager) - Self.list.Remove(element) - Self.mutex.Unlock() +startPop: + ptr, ok := Self.highestChain.popTail() + if ok { + packager = (*common.MuxPackager)(ptr) return } - Self.popWait = true // PriorityQueue is empty, notice Push method - Self.mutex.Unlock() - select { - case <-Self.readOp: - return Self.Pop() - case <-Self.cleanOp: - return nil + if Self.hunger < 100 { + ptr, ok = Self.middleChain.popTail() + if ok { + packager = (*common.MuxPackager)(ptr) + Self.hunger++ + return + } } -} - -func (Self *PriorityQueue) Len() (n int) { - n = Self.list.Len() - return + ptr, ok = Self.lowestChain.popTail() + if ok { + packager = (*common.MuxPackager)(ptr) + if Self.hunger > 0 { + Self.hunger = uint8(Self.hunger / 2) + } + return + } + // PriorityQueue is empty, notice Push method + if atomic.CompareAndSwapInt32(&Self.popWait, 0, 1) { + select { + case <-Self.readOp: + goto startPop + case <-Self.cleanOp: + return nil + } + } + goto startPop } type ListElement struct { @@ -137,36 +125,36 @@ func (Self *ListElement) New(buf []byte, l uint16, part bool) (err error) { } type FIFOQueue struct { - list []*ListElement + QueueOp + chain *bufChain length uint32 stopOp chan struct{} timeout time.Time - QueueOp } func (Self *FIFOQueue) New() { Self.QueueOp.New() + Self.chain = new(bufChain) + Self.chain.new(64) Self.stopOp = make(chan struct{}, 1) } func (Self *FIFOQueue) Push(element *ListElement) { - Self.mutex.Lock() - Self.list = append(Self.list, element) + Self.chain.pushHead(unsafe.Pointer(element)) Self.length += uint32(element.l) - if Self.popWait { - Self.mutex.Unlock() - Self.allowPop() - return - } - Self.mutex.Unlock() + Self.allowPop() return } func (Self *FIFOQueue) Pop() (element *ListElement, err error) { - Self.mutex.Lock() - if len(Self.list) == 0 { - Self.popWait = true - Self.mutex.Unlock() +startPop: + ptr, ok := Self.chain.popTail() + if ok { + element = (*ListElement)(ptr) + Self.length -= uint32(element.l) + return + } + if atomic.CompareAndSwapInt32(&Self.popWait, 0, 1) { t := Self.timeout.Sub(time.Now()) if t <= 0 { t = time.Minute @@ -175,7 +163,7 @@ func (Self *FIFOQueue) Pop() (element *ListElement, err error) { defer timer.Stop() select { case <-Self.readOp: - Self.mutex.Lock() + goto startPop case <-Self.cleanOp: return case <-Self.stopOp: @@ -186,11 +174,7 @@ func (Self *FIFOQueue) Pop() (element *ListElement, err error) { return } } - element = Self.list[0] - Self.list = Self.list[1:] - Self.length -= uint32(element.l) - Self.mutex.Unlock() - return + goto startPop } func (Self *FIFOQueue) Len() (n uint32) { @@ -204,3 +188,231 @@ func (Self *FIFOQueue) Stop() { func (Self *FIFOQueue) SetTimeOut(t time.Time) { Self.timeout = t } + +// https://golang.org/src/sync/poolqueue.go + +type bufDequeue struct { + // headTail packs together a 32-bit head index and a 32-bit + // tail index. Both are indexes into vals modulo len(vals)-1. + // + // tail = index of oldest data in queue + // head = index of next slot to fill + // + // Slots in the range [tail, head) are owned by consumers. + // A consumer continues to own a slot outside this range until + // it nils the slot, at which point ownership passes to the + // producer. + // + // The head index is stored in the most-significant bits so + // that we can atomically add to it and the overflow is + // harmless. + headTail uint64 + + // vals is a ring buffer of interface{} values stored in this + // dequeue. The size of this must be a power of 2. + // + // A slot is still in use until *both* the tail + // index has moved beyond it and typ has been set to nil. This + // is set to nil atomically by the consumer and read + // atomically by the producer. + vals []unsafe.Pointer +} + +const dequeueBits = 32 + +// dequeueLimit is the maximum size of a bufDequeue. +// +// This must be at most (1<> dequeueBits) & mask) + tail = uint32(ptrs & mask) + return +} + +func (d *bufDequeue) pack(head, tail uint32) uint64 { + const mask = 1<= dequeueLimit { + // Can't make it any bigger. + newSize = dequeueLimit + } + + d2 := &bufChainElt{prev: d} + d2.vals = make([]unsafe.Pointer, newSize) + storePoolChainElt(&c.head, d2) + storePoolChainElt(&d.next, d2) + d2.pushHead(val) + atomic.SwapInt32(&c.chainStatus, 0) + } + } +} + +func (c *bufChain) popTail() (unsafe.Pointer, bool) { + d := loadPoolChainElt(&c.tail) + if d == nil { + return nil, false + } + + for { + // It's important that we load the next pointer + // *before* popping the tail. In general, d may be + // transiently empty, but if next is non-nil before + // the pop and the pop fails, then d is permanently + // empty, which is the only condition under which it's + // safe to drop d from the chain. + d2 := loadPoolChainElt(&d.next) + + if val, ok := d.popTail(); ok { + return val, ok + } + + if d2 == nil { + // This is the only dequeue. It's empty right + // now, but could be pushed to in the future. + return nil, false + } + + // The tail of the chain has been drained, so move on + // to the next dequeue. Try to drop it from the chain + // so the next pop doesn't have to look at the empty + // dequeue again. + if atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&c.tail)), unsafe.Pointer(d), unsafe.Pointer(d2)) { + // We won the race. Clear the prev pointer so + // the garbage collector can collect the empty + // dequeue and so popHead doesn't back up + // further than necessary. + storePoolChainElt(&d2.prev, nil) + } + d = d2 + } +} From 442354db17703919fa51e8c096e36e628708e3ad Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Wed, 23 Oct 2019 23:35:39 +0800 Subject: [PATCH 45/58] add test code --- lib/mux/conn.go | 93 +++++-------- lib/mux/mux.go | 6 +- lib/mux/mux_test.go | 330 ++++++++++++++++++++++++++++++++------------ lib/mux/queue.go | 32 +++-- 4 files changed, 300 insertions(+), 161 deletions(-) diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 3011732..99b6a05 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -2,7 +2,6 @@ package mux import ( "errors" - "github.com/astaxie/beego/logs" "io" "net" "strconv" @@ -178,21 +177,17 @@ func (Self *ReceiveWindow) New(mux *Mux) { Self.window.New() } -func (Self *ReceiveWindow) RemainingSize() (n uint32) { +func (Self *ReceiveWindow) remainingSize() (n uint32) { // receive window remaining - if Self.maxSize >= Self.bufQueue.Len() { - n = Self.maxSize - Self.bufQueue.Len() - } - // if maxSize is small than bufQueue length, return 0 - return + return Self.maxSize - Self.bufQueue.Len() } -func (Self *ReceiveWindow) ReadSize() (n uint32) { +func (Self *ReceiveWindow) readSize() (n uint32) { // acknowledge the size already read return atomic.SwapUint32(&Self.readLength, 0) } -func (Self *ReceiveWindow) CalcSize() { +func (Self *ReceiveWindow) calcSize() { // calculating maximum receive window size if Self.count == 0 { //logs.Warn("ping, bw", Self.mux.latency, Self.bw.Get()) @@ -222,22 +217,22 @@ func (Self *ReceiveWindow) Write(buf []byte, l uint16, part bool, id int32) (err if Self.closeOp { return errors.New("conn.receiveWindow: write on closed window") } - element := ListElement{} + element := new(ListElement) err = element.New(buf, l, part) //logs.Warn("push the buf", len(buf), l, (&element).l) if err != nil { return } - Self.bufQueue.Push(&element) // must push data before allow read + Self.bufQueue.Push(element) // must push data before allow read //logs.Warn("read session calc size ", Self.maxSize) // calculating the receive window size - Self.CalcSize() + Self.calcSize() //logs.Warn("read session calc size finish", Self.maxSize) - if Self.RemainingSize() == 0 { + if Self.remainingSize() == 0 { Self.windowFull = true //logs.Warn("window full true", Self.windowFull) } - Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.maxSize, Self.ReadSize()) + Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.maxSize, Self.readSize()) return nil } @@ -273,10 +268,10 @@ copyData: n += l l = 0 //Self.bw.EndRead() - Self.sendStatus(id) if Self.off == uint32(Self.element.l) { //logs.Warn("put the element end ", string(Self.element.buf[:15])) common.WindowBuff.Put(Self.element.buf) + Self.sendStatus(id) } if pOff < len(p) && Self.element.part { // element is a part of the segments, trying to fill up buf p @@ -289,7 +284,7 @@ func (Self *ReceiveWindow) sendStatus(id int32) { if Self.windowFull || Self.bufQueue.Len() == 0 { // window is full before read or empty now Self.windowFull = false - Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.maxSize, Self.ReadSize()) + Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.maxSize, Self.readSize()) // acknowledge other side, have empty some receive window space //} } @@ -314,11 +309,10 @@ type SendWindow struct { buf []byte sentLength uint32 setSizeCh chan struct{} - setSizeWait bool + setSizeWait int32 unSlide uint32 timeout time.Time window - mutex sync.Mutex } func (Self *SendWindow) New(mux *Mux) { @@ -330,17 +324,12 @@ func (Self *SendWindow) New(mux *Mux) { func (Self *SendWindow) SetSendBuf(buf []byte) { // send window buff from conn write method, set it to send window - Self.mutex.Lock() Self.buf = buf Self.off = 0 - Self.mutex.Unlock() } func (Self *SendWindow) RemainingSize() (n uint32) { - if Self.maxSize >= Self.sentLength { - n = Self.maxSize - Self.sentLength - } - return + return atomic.LoadUint32(&Self.maxSize) - atomic.LoadUint32(&Self.sentLength) } func (Self *SendWindow) SetSize(windowSize, readLength uint32) (closed bool) { @@ -353,25 +342,21 @@ func (Self *SendWindow) SetSize(windowSize, readLength uint32) (closed bool) { close(Self.setSizeCh) return true } - if readLength == 0 && Self.maxSize == windowSize { + + if readLength == 0 && atomic.LoadUint32(&Self.maxSize) == windowSize { //logs.Warn("waiting for another window size") return false // waiting for receive another usable window size } //logs.Warn("set send window size to ", windowSize, readLength) - Self.mutex.Lock() Self.slide(windowSize, readLength) - if Self.setSizeWait { + if Self.RemainingSize() == 0 { + //logs.Warn("waiting for another window size after slide") + // keep the wait status + atomic.StoreInt32(&Self.setSizeWait, 1) + return false + } + if atomic.CompareAndSwapInt32(&Self.setSizeWait, 1, 0) { // send window into the wait status, need notice the channel - //logs.Warn("send window remaining size is 0 , wait") - if Self.RemainingSize() == 0 { - //logs.Warn("waiting for another window size after slide") - // keep the wait status - Self.mutex.Unlock() - return false - } - Self.setSizeWait = false - Self.mutex.Unlock() - //logs.Warn("send window remaining size is 0 starting wait") select { case Self.setSizeCh <- struct{}{}: //logs.Warn("send window remaining size is 0 finish") @@ -382,43 +367,36 @@ func (Self *SendWindow) SetSize(windowSize, readLength uint32) (closed bool) { } } // send window not into the wait status, so just do slide - Self.mutex.Unlock() return false } func (Self *SendWindow) slide(windowSize, readLength uint32) { - Self.sentLength -= readLength - Self.maxSize = windowSize + atomic.AddUint32(&Self.sentLength, ^readLength-1) + atomic.SwapUint32(&Self.maxSize, windowSize) } -func (Self *SendWindow) WriteTo() (p []byte, part bool, err error) { +func (Self *SendWindow) WriteTo() (p []byte, sendSize uint32, part bool, err error) { // returns buf segments, return only one segments, need a loop outside // until err = io.EOF if Self.closeOp { - return nil, false, errors.New("conn.writeWindow: window closed") + return nil, 0, false, errors.New("conn.writeWindow: window closed") } if Self.off == uint32(len(Self.buf)) { - return nil, false, io.EOF + return nil, 0, false, io.EOF // send window buff is drain, return eof and get another one } - Self.mutex.Lock() if Self.RemainingSize() == 0 { - Self.setSizeWait = true - Self.mutex.Unlock() + atomic.StoreInt32(&Self.setSizeWait, 1) // into the wait status err = Self.waitReceiveWindow() if err != nil { - return nil, false, err + return nil, 0, false, err } - } else { - Self.mutex.Unlock() } - Self.mutex.Lock() - var sendSize uint32 if len(Self.buf[Self.off:]) > common.MAXIMUM_SEGMENT_SIZE { sendSize = common.MAXIMUM_SEGMENT_SIZE part = true - logs.Warn("cut buf by mss") + //logs.Warn("cut buf by mss") } else { sendSize = uint32(len(Self.buf[Self.off:])) part = false @@ -427,14 +405,13 @@ func (Self *SendWindow) WriteTo() (p []byte, part bool, err error) { // usable window size is small than // window MAXIMUM_SEGMENT_SIZE or send buf left sendSize = Self.RemainingSize() - logs.Warn("cut buf by remainingsize", sendSize, len(Self.buf[Self.off:])) + //logs.Warn("cut buf by remainingsize", sendSize, len(Self.buf[Self.off:])) part = true } //logs.Warn("send size", sendSize) p = Self.buf[Self.off : sendSize+Self.off] Self.off += sendSize - Self.sentLength += sendSize - Self.mutex.Unlock() + atomic.AddUint32(&Self.sentLength, sendSize) return } @@ -463,8 +440,9 @@ func (Self *SendWindow) WriteFull(buf []byte, id int32) (n int, err error) { Self.SetSendBuf(buf) // set the buf to send window var bufSeg []byte var part bool + var l uint32 for { - bufSeg, part, err = Self.WriteTo() + bufSeg, l, part, err = Self.WriteTo() //logs.Warn("buf seg", len(bufSeg), part, err) // get the buf segments from send window if bufSeg == nil && part == false && err == io.EOF { @@ -475,7 +453,8 @@ func (Self *SendWindow) WriteFull(buf []byte, id int32) (n int, err error) { if err != nil { break } - n += len(bufSeg) + n += int(l) + l = 0 if part { Self.mux.sendInfo(common.MUX_NEW_MSG_PART, id, bufSeg) } else { diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 6f08641..8300977 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -41,7 +41,7 @@ func NewMux(c net.Conn, connType string) *Mux { connMap: NewConnMap(), id: 0, closeChan: make(chan struct{}, 3), - newConnCh: make(chan *conn), + newConnCh: make(chan *conn, 10), bw: new(bandwidth), IsClose: false, connType: connType, @@ -321,11 +321,11 @@ func (s *Mux) Close() error { func (s *Mux) getId() (id int32) { //Avoid going beyond the scope if (math.MaxInt32 - s.id) < 10000 { - atomic.SwapInt32(&s.id, 0) + atomic.StoreInt32(&s.id, 0) } id = atomic.AddInt32(&s.id, 1) if _, ok := s.connMap.Get(id); ok { - s.getId() + return s.getId() } return } diff --git a/lib/mux/mux_test.go b/lib/mux/mux_test.go index 43e12e8..0ac54d5 100644 --- a/lib/mux/mux_test.go +++ b/lib/mux/mux_test.go @@ -3,19 +3,18 @@ package mux import ( "bufio" "fmt" - "io" + "github.com/cnlh/nps/lib/common" + "log" "net" "net/http" "net/http/httputil" _ "net/http/pprof" "strconv" - "sync" "testing" "time" "unsafe" "github.com/astaxie/beego/logs" - "github.com/cnlh/nps/lib/common" ) var conn1 net.Conn @@ -49,42 +48,42 @@ func TestNewMux(t *testing.T) { //c2.(*net.TCPConn).SetReadBuffer(0) //c2.(*net.TCPConn).SetReadBuffer(0) go func(c2 net.Conn, c *conn) { - wg := sync.WaitGroup{} - wg.Add(1) - go func() { - _, err = common.CopyBuffer(c2, c) - if err != nil { - c2.Close() - c.Close() - logs.Warn("close npc by copy from nps", err, c.connId) - } - wg.Done() - }() - wg.Add(1) - go func() { - _, err = common.CopyBuffer(c, c2) - if err != nil { - c2.Close() - c.Close() - logs.Warn("close npc by copy from server", err, c.connId) - } - wg.Done() - }() - //logs.Warn("npc wait") - wg.Wait() + //wg := sync.WaitGroup{} + //wg.Add(1) + //go func() { + // _, err = common.CopyBuffer(c2, c) + // if err != nil { + // c2.Close() + // c.Close() + // logs.Warn("close npc by copy from nps", err, c.connId) + // } + // wg.Done() + //}() + //wg.Add(1) + //go func() { + // _, err = common.CopyBuffer(c, c2) + // if err != nil { + // c2.Close() + // c.Close() + // logs.Warn("close npc by copy from server", err, c.connId) + // } + // wg.Done() + //}() + ////logs.Warn("npc wait") + //wg.Wait() }(c2, c.(*conn)) } }() go func() { - m1 := NewMux(conn1, "tcp") + //m1 := NewMux(conn1, "tcp") l, err := net.Listen("tcp", "127.0.0.1:7777") if err != nil { logs.Warn(err) } for { //logs.Warn("nps starting accept") - conns, err := l.Accept() + _, err := l.Accept() if err != nil { logs.Warn(err) continue @@ -92,37 +91,37 @@ func TestNewMux(t *testing.T) { //conns.(*net.TCPConn).SetReadBuffer(0) //conns.(*net.TCPConn).SetReadBuffer(0) //logs.Warn("nps accept success starting new conn") - tmpCpnn, err := m1.NewConn() - if err != nil { - logs.Warn("nps new conn err ", err) - continue - } - logs.Warn("nps new conn success ", tmpCpnn.connId) - go func(tmpCpnn *conn, conns net.Conn) { - go func() { - _, err := common.CopyBuffer(tmpCpnn, conns) - if err != nil { - conns.Close() - tmpCpnn.Close() - logs.Warn("close nps by copy from user", tmpCpnn.connId, err) - } - }() - //time.Sleep(time.Second) - _, err = common.CopyBuffer(conns, tmpCpnn) - if err != nil { - conns.Close() - tmpCpnn.Close() - logs.Warn("close nps by copy from npc ", tmpCpnn.connId, err) - } - }(tmpCpnn, conns) + //tmpCpnn, err := m1.NewConn() + //if err != nil { + // logs.Warn("nps new conn err ", err) + // continue + //} + ////logs.Warn("nps new conn success ", tmpCpnn.connId) + //go func(tmpCpnn *conn, conns net.Conn) { + // //go func() { + // // _, err := common.CopyBuffer(tmpCpnn, conns) + // // if err != nil { + // // conns.Close() + // // tmpCpnn.Close() + // // logs.Warn("close nps by copy from user", tmpCpnn.connId, err) + // // } + // //}() + // ////time.Sleep(time.Second) + // //_, err = common.CopyBuffer(conns, tmpCpnn) + // //if err != nil { + // // conns.Close() + // // tmpCpnn.Close() + // // logs.Warn("close nps by copy from npc ", tmpCpnn.connId, err) + // //} + //}(tmpCpnn, conns) } }() go NewLogServer() time.Sleep(time.Second * 5) - //for i:=0;i<1000;i++ { - // go test_raw(i) - //} + for i := 0; i < 1000; i++ { + go test_raw(i) + } for { time.Sleep(time.Second * 5) @@ -180,37 +179,37 @@ Connection: keep-alive func test_raw(k int) { for i := 0; i < 1; i++ { ti := time.Now() - conn, _ := net.Dial("tcp", "127.0.0.1:7777") + _, _ = net.Dial("tcp", "127.0.0.1:7777") tid := time.Now() - conn.Write([]byte(`GET / HTTP/1.1 -Host: 127.0.0.1:7777 - - -`)) - tiw := time.Now() - buf := make([]byte, 3572) - n, err := io.ReadFull(conn, buf) - //n, err := conn.Read(buf) - if err != nil { - logs.Warn("close by read response err", err) - break - } - //logs.Warn(n, string(buf[:50]), "\n--------------\n", string(buf[n-50:n])) - //time.Sleep(time.Second) - err = conn.Close() - if err != nil { - logs.Warn("close conn err ", err) - } + // conn.Write([]byte(`GET / HTTP/1.1 + //Host: 127.0.0.1:7777 + // + // + //`)) + // tiw := time.Now() + //buf := make([]byte, 3572) + //n, err := io.ReadFull(conn, buf) + ////n, err := conn.Read(buf) + //if err != nil { + // logs.Warn("close by read response err", err) + // break + //} + ////logs.Warn(n, string(buf[:50]), "\n--------------\n", string(buf[n-50:n])) + ////time.Sleep(time.Second) + //err = conn.Close() + //if err != nil { + // logs.Warn("close conn err ", err) + //} now := time.Now() du := now.Sub(ti).Seconds() dud := now.Sub(tid).Seconds() - duw := now.Sub(tiw).Seconds() - if du > 1 { - logs.Warn("duration long", du, dud, duw, k, i) - } - if n != 3572 { - logs.Warn("n loss", n, string(buf)) - } + //duw := now.Sub(tiw).Seconds() + //if du > 1 { + logs.Warn("duration long", du, dud, k, i) + //} + //if n != 3572 { + // logs.Warn("n loss", n, string(buf)) + //} } } @@ -249,29 +248,182 @@ func TestDQueue(t *testing.T) { } func TestChain(t *testing.T) { + go func() { + log.Println(http.ListenAndServe("0.0.0.0:8889", nil)) + }() logs.EnableFuncCallDepth(true) logs.SetLogFuncCallDepth(3) + time.Sleep(time.Second * 5) d := new(bufChain) d.new(256) go func() { time.Sleep(time.Second) - for i := 0; i < 1000; i++ { + for i := 0; i < 30000; i++ { unsa, ok := d.popTail() str := (*string)(unsa) if ok { - logs.Warn(i, str, *str, ok) + fmt.Println(i, str, *str, ok) + //logs.Warn(i, str, *str, ok) } else { - logs.Warn("nil", i, ok) + fmt.Println("nil", i, ok) + //logs.Warn("nil", i, ok) } } }() go func() { time.Sleep(time.Second) - for i := 0; i < 1000; i++ { - data := "test " + strconv.Itoa(i) - logs.Warn(data, unsafe.Pointer(&data)) - go d.pushHead(unsafe.Pointer(&data)) + for i := 0; i < 3000; i++ { + go func(i int) { + for n := 0; n < 10; n++ { + data := "test " + strconv.Itoa(i) + strconv.Itoa(n) + fmt.Println(data, unsafe.Pointer(&data)) + //logs.Warn(data, unsafe.Pointer(&data)) + d.pushHead(unsafe.Pointer(&data)) + } + }(i) } }() - time.Sleep(time.Second * 10) + time.Sleep(time.Second * 100000) } + +func TestFIFO(t *testing.T) { + go func() { + log.Println(http.ListenAndServe("0.0.0.0:8889", nil)) + }() + logs.EnableFuncCallDepth(true) + logs.SetLogFuncCallDepth(3) + time.Sleep(time.Second * 5) + d := new(FIFOQueue) + d.New() + go func() { + time.Sleep(time.Second) + for i := 0; i < 30000; i++ { + data, err := d.Pop() + if err == nil { + //fmt.Println(i, string(data.buf), err) + logs.Warn(i, string(data.buf), err) + } else { + //fmt.Println("err", err) + logs.Warn("err", err) + } + } + }() + go func() { + time.Sleep(time.Second * 10) + for i := 0; i < 3000; i++ { + go func(i int) { + for n := 0; n < 10; n++ { + data := new(ListElement) + by := []byte("test " + strconv.Itoa(i) + strconv.Itoa(n)) + _ = data.New(by, uint16(len(by)), true) + //fmt.Println(string((*data).buf), data) + logs.Warn(string((*data).buf), data) + d.Push(data) + } + }(i) + } + }() + time.Sleep(time.Second * 100000) +} + +func TestPriority(t *testing.T) { + go func() { + log.Println(http.ListenAndServe("0.0.0.0:8889", nil)) + }() + logs.EnableFuncCallDepth(true) + logs.SetLogFuncCallDepth(3) + time.Sleep(time.Second * 5) + d := new(PriorityQueue) + d.New() + go func() { + time.Sleep(time.Second) + for i := 0; i < 36000; i++ { + data := d.Pop() + //fmt.Println(i, string(data.buf), err) + logs.Warn(i, string(data.Content), data) + } + }() + go func() { + time.Sleep(time.Second * 10) + for i := 0; i < 3000; i++ { + go func(i int) { + for n := 0; n < 10; n++ { + data := new(common.MuxPackager) + by := []byte("test " + strconv.Itoa(i) + strconv.Itoa(n)) + _ = data.NewPac(common.MUX_NEW_MSG_PART, int32(i), by) + //fmt.Println(string((*data).buf), data) + logs.Warn(string((*data).Content), data) + d.Push(data) + } + }(i) + go func(i int) { + data := new(common.MuxPackager) + _ = data.NewPac(common.MUX_NEW_CONN, int32(i), nil) + //fmt.Println(string((*data).buf), data) + logs.Warn(data) + d.Push(data) + }(i) + go func(i int) { + data := new(common.MuxPackager) + _ = data.NewPac(common.MUX_NEW_CONN_OK, int32(i), nil) + //fmt.Println(string((*data).buf), data) + logs.Warn(data) + d.Push(data) + }(i) + } + }() + time.Sleep(time.Second * 100000) +} + +//func TestReceive(t *testing.T) { +// go func() { +// log.Println(http.ListenAndServe("0.0.0.0:8889", nil)) +// }() +// logs.EnableFuncCallDepth(true) +// logs.SetLogFuncCallDepth(3) +// time.Sleep(time.Second * 5) +// mux := new(Mux) +// mux.bw.readBandwidth = float64(1*1024*1024) +// mux.latency = float64(1/1000) +// wind := new(ReceiveWindow) +// wind.New(mux) +// wind. +// go func() { +// time.Sleep(time.Second) +// for i := 0; i < 36000; i++ { +// data := d.Pop() +// //fmt.Println(i, string(data.buf), err) +// logs.Warn(i, string(data.Content), data) +// } +// }() +// go func() { +// time.Sleep(time.Second*10) +// for i := 0; i < 3000; i++ { +// go func(i int) { +// for n := 0; n < 10; n++{ +// data := new(common.MuxPackager) +// by := []byte("test " + strconv.Itoa(i) + strconv.Itoa(n)) +// _ = data.NewPac(common.MUX_NEW_MSG_PART, int32(i), by) +// //fmt.Println(string((*data).buf), data) +// logs.Warn(string((*data).Content), data) +// d.Push(data) +// } +// }(i) +// go func(i int) { +// data := new(common.MuxPackager) +// _ = data.NewPac(common.MUX_NEW_CONN, int32(i), nil) +// //fmt.Println(string((*data).buf), data) +// logs.Warn(data) +// d.Push(data) +// }(i) +// go func(i int) { +// data := new(common.MuxPackager) +// _ = data.NewPac(common.MUX_NEW_CONN_OK, int32(i), nil) +// //fmt.Println(string((*data).buf), data) +// logs.Warn(data) +// d.Push(data) +// }(i) +// } +// }() +// time.Sleep(time.Second * 100000) +//} diff --git a/lib/mux/queue.go b/lib/mux/queue.go index ef0c904..488c616 100644 --- a/lib/mux/queue.go +++ b/lib/mux/queue.go @@ -73,6 +73,8 @@ func (Self *PriorityQueue) Push(packager *common.MuxPackager) { return } +const maxHunger uint8 = 10 + func (Self *PriorityQueue) Pop() (packager *common.MuxPackager) { startPop: ptr, ok := Self.highestChain.popTail() @@ -80,7 +82,7 @@ startPop: packager = (*common.MuxPackager)(ptr) return } - if Self.hunger < 100 { + if Self.hunger < maxHunger { ptr, ok = Self.middleChain.popTail() if ok { packager = (*common.MuxPackager)(ptr) @@ -96,6 +98,13 @@ startPop: } return } + if Self.hunger > 0 { + ptr, ok = Self.middleChain.popTail() + if ok { + packager = (*common.MuxPackager)(ptr) + return + } + } // PriorityQueue is empty, notice Push method if atomic.CompareAndSwapInt32(&Self.popWait, 0, 1) { select { @@ -141,7 +150,7 @@ func (Self *FIFOQueue) New() { func (Self *FIFOQueue) Push(element *ListElement) { Self.chain.pushHead(unsafe.Pointer(element)) - Self.length += uint32(element.l) + atomic.AddUint32(&Self.length, uint32(element.l)) Self.allowPop() return } @@ -151,7 +160,7 @@ startPop: ptr, ok := Self.chain.popTail() if ok { element = (*ListElement)(ptr) - Self.length -= uint32(element.l) + atomic.AddUint32(&Self.length, ^uint32(element.l-1)) return } if atomic.CompareAndSwapInt32(&Self.popWait, 0, 1) { @@ -178,7 +187,7 @@ startPop: } func (Self *FIFOQueue) Len() (n uint32) { - return Self.length + return atomic.LoadUint32(&Self.length) } func (Self *FIFOQueue) Stop() { @@ -273,17 +282,16 @@ func (d *bufDequeue) popTail() (unsafe.Pointer, bool) { return nil, false } slot := &d.vals[tail&uint32(len(d.vals)-1)] + var val unsafe.Pointer for { - typ := atomic.LoadPointer(slot) - if typ != nil { + val = atomic.LoadPointer(slot) + if val != nil { + // We now own slot. break } // Another goroutine is still pushing data on the tail. } - // We now own slot. - val := *slot - // Tell pushHead that we're done with this slot. Zeroing the // slot is also important so we don't leave behind references // that could keep this object live longer than necessary. @@ -369,10 +377,10 @@ func (c *bufChain) pushHead(val unsafe.Pointer) { d2 := &bufChainElt{prev: d} d2.vals = make([]unsafe.Pointer, newSize) - storePoolChainElt(&c.head, d2) - storePoolChainElt(&d.next, d2) d2.pushHead(val) - atomic.SwapInt32(&c.chainStatus, 0) + storePoolChainElt(&d.next, d2) + storePoolChainElt(&c.head, d2) + atomic.StoreInt32(&c.chainStatus, 0) } } } From 5f354158496443e4294c2b104d6dc344236fdcba Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Sun, 27 Oct 2019 23:25:12 +0800 Subject: [PATCH 46/58] fix queue bug --- lib/mux/conn.go | 77 +++++++++---------- lib/mux/mux.go | 65 ++++++++-------- lib/mux/mux_test.go | 175 +++++++++++++++++++++++--------------------- lib/mux/queue.go | 152 +++++++++++++++++++++++++++----------- 4 files changed, 275 insertions(+), 194 deletions(-) diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 99b6a05..f3217d8 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -4,7 +4,6 @@ import ( "errors" "io" "net" - "strconv" "sync" "sync/atomic" "time" @@ -41,12 +40,12 @@ func NewConn(connId int32, mux *Mux, label ...string) *conn { } c.receiveWindow.New(mux) c.sendWindow.New(mux) - logm := &connLog{ - startTime: time.Now(), - isClose: false, - logs: []string{c.label + "new conn success"}, - } - setM(label[0], int(connId), logm) + //logm := &connLog{ + // startTime: time.Now(), + // isClose: false, + // logs: []string{c.label + "new conn success"}, + //} + //setM(label[0], int(connId), logm) return c } @@ -59,15 +58,15 @@ func (s *conn) Read(buf []byte) (n int, err error) { } // waiting for takeout from receive window finish or timeout n, err = s.receiveWindow.Read(buf, s.connId) - var errstr string - if err == nil { - errstr = "err:nil" - } else { - errstr = err.Error() - } - d := getM(s.label, int(s.connId)) - d.logs = append(d.logs, s.label+"read "+strconv.Itoa(n)+" "+errstr+" "+string(buf[:100])) - setM(s.label, int(s.connId), d) + //var errstr string + //if err == nil { + // errstr = "err:nil" + //} else { + // errstr = err.Error() + //} + //d := getM(s.label, int(s.connId)) + //d.logs = append(d.logs, s.label+"read "+strconv.Itoa(n)+" "+errstr+" "+string(buf[:100])) + //setM(s.label, int(s.connId), d) return } @@ -102,10 +101,10 @@ func (s *conn) closeProcess() { } s.sendWindow.CloseWindow() s.receiveWindow.CloseWindow() - d := getM(s.label, int(s.connId)) - d.isClose = true - d.logs = append(d.logs, s.label+"close "+time.Now().String()) - setM(s.label, int(s.connId), d) + //d := getM(s.label, int(s.connId)) + //d.isClose = true + //d.logs = append(d.logs, s.label+"close "+time.Now().String()) + //setM(s.label, int(s.connId), d) return } @@ -154,12 +153,12 @@ func (Self *window) CloseWindow() { } type ReceiveWindow struct { - bufQueue FIFOQueue + bufQueue ReceiveWindowQueue element *ListElement readLength uint32 readOp chan struct{} readWait bool - windowFull bool + windowFull uint32 count int8 //bw *bandwidth once sync.Once @@ -179,7 +178,7 @@ func (Self *ReceiveWindow) New(mux *Mux) { func (Self *ReceiveWindow) remainingSize() (n uint32) { // receive window remaining - return Self.maxSize - Self.bufQueue.Len() + return atomic.LoadUint32(&Self.maxSize) - Self.bufQueue.Len() } func (Self *ReceiveWindow) readSize() (n uint32) { @@ -207,7 +206,7 @@ func (Self *ReceiveWindow) calcSize() { } // set the maximum size //logs.Warn("n", n) - Self.maxSize = n + atomic.StoreUint32(&Self.maxSize, n) Self.count = -10 } Self.count += 1 @@ -229,7 +228,7 @@ func (Self *ReceiveWindow) Write(buf []byte, l uint16, part bool, id int32) (err Self.calcSize() //logs.Warn("read session calc size finish", Self.maxSize) if Self.remainingSize() == 0 { - Self.windowFull = true + atomic.StoreUint32(&Self.windowFull, 1) //logs.Warn("window full true", Self.windowFull) } Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.maxSize, Self.readSize()) @@ -259,7 +258,7 @@ copyData: } //logs.Warn("pop element", Self.element.l, Self.element.part) } - l = copy(p[pOff:], Self.element.buf[Self.off:]) + l = copy(p[pOff:], Self.element.buf[Self.off:Self.element.l]) //Self.bw.SetCopySize(l) pOff += l Self.off += uint32(l) @@ -281,13 +280,16 @@ copyData: } func (Self *ReceiveWindow) sendStatus(id int32) { - if Self.windowFull || Self.bufQueue.Len() == 0 { + if Self.bufQueue.Len() == 0 { // window is full before read or empty now - Self.windowFull = false - Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.maxSize, Self.readSize()) + Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, atomic.LoadUint32(&Self.maxSize), Self.readSize()) // acknowledge other side, have empty some receive window space //} } + if atomic.LoadUint32(&Self.windowFull) > 0 && Self.remainingSize() > 0 { + atomic.StoreUint32(&Self.windowFull, 0) + Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, atomic.LoadUint32(&Self.maxSize), Self.readSize()) + } } func (Self *ReceiveWindow) SetTimeOut(t time.Time) { @@ -309,8 +311,7 @@ type SendWindow struct { buf []byte sentLength uint32 setSizeCh chan struct{} - setSizeWait int32 - unSlide uint32 + setSizeWait uint32 timeout time.Time window } @@ -352,10 +353,10 @@ func (Self *SendWindow) SetSize(windowSize, readLength uint32) (closed bool) { if Self.RemainingSize() == 0 { //logs.Warn("waiting for another window size after slide") // keep the wait status - atomic.StoreInt32(&Self.setSizeWait, 1) + //atomic.StoreUint32(&Self.setSizeWait, 1) return false } - if atomic.CompareAndSwapInt32(&Self.setSizeWait, 1, 0) { + if atomic.CompareAndSwapUint32(&Self.setSizeWait, 1, 0) { // send window into the wait status, need notice the channel select { case Self.setSizeCh <- struct{}{}: @@ -372,7 +373,7 @@ func (Self *SendWindow) SetSize(windowSize, readLength uint32) (closed bool) { func (Self *SendWindow) slide(windowSize, readLength uint32) { atomic.AddUint32(&Self.sentLength, ^readLength-1) - atomic.SwapUint32(&Self.maxSize, windowSize) + atomic.StoreUint32(&Self.maxSize, windowSize) } func (Self *SendWindow) WriteTo() (p []byte, sendSize uint32, part bool, err error) { @@ -386,7 +387,7 @@ func (Self *SendWindow) WriteTo() (p []byte, sendSize uint32, part bool, err err // send window buff is drain, return eof and get another one } if Self.RemainingSize() == 0 { - atomic.StoreInt32(&Self.setSizeWait, 1) + atomic.StoreUint32(&Self.setSizeWait, 1) // into the wait status err = Self.waitReceiveWindow() if err != nil { @@ -395,20 +396,20 @@ func (Self *SendWindow) WriteTo() (p []byte, sendSize uint32, part bool, err err } if len(Self.buf[Self.off:]) > common.MAXIMUM_SEGMENT_SIZE { sendSize = common.MAXIMUM_SEGMENT_SIZE - part = true //logs.Warn("cut buf by mss") } else { sendSize = uint32(len(Self.buf[Self.off:])) - part = false } if Self.RemainingSize() < sendSize { // usable window size is small than // window MAXIMUM_SEGMENT_SIZE or send buf left sendSize = Self.RemainingSize() //logs.Warn("cut buf by remainingsize", sendSize, len(Self.buf[Self.off:])) - part = true } //logs.Warn("send size", sendSize) + if sendSize < uint32(len(Self.buf[Self.off:])) { + part = true + } p = Self.buf[Self.off : sendSize+Self.off] Self.off += sendSize atomic.AddUint32(&Self.sentLength, sendSize) diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 8300977..8a6086c 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -1,7 +1,6 @@ package mux import ( - "bytes" "errors" "io" "math" @@ -29,7 +28,7 @@ type Mux struct { pingTimer *time.Timer connType string writeQueue PriorityQueue - bufCh chan *bytes.Buffer + //bufQueue BytesQueue sync.Mutex } @@ -40,16 +39,16 @@ func NewMux(c net.Conn, connType string) *Mux { conn: c, connMap: NewConnMap(), id: 0, - closeChan: make(chan struct{}, 3), + closeChan: make(chan struct{}, 1), newConnCh: make(chan *conn, 10), bw: new(bandwidth), IsClose: false, connType: connType, - bufCh: make(chan *bytes.Buffer), pingCh: make(chan []byte), pingTimer: time.NewTimer(15 * time.Second), } m.writeQueue.New() + //m.bufQueue.New() //read session by flag m.readSession() //ping @@ -111,16 +110,18 @@ func (s *Mux) sendInfo(flag uint8, id int32, data ...interface{}) { func (s *Mux) writeSession() { go s.packBuf() - go s.writeBuf() + //go s.writeBuf() } func (s *Mux) packBuf() { + buffer := common.BuffPool.Get() for { if s.IsClose { break } + buffer.Reset() pack := s.writeQueue.Pop() - buffer := common.BuffPool.Get() + //buffer := common.BuffPool.Get() err := pack.Pack(buffer) common.MuxPack.Put(pack) if err != nil { @@ -129,34 +130,37 @@ func (s *Mux) packBuf() { break } //logs.Warn(buffer.String()) - select { - case s.bufCh <- buffer: - case <-s.closeChan: + //s.bufQueue.Push(buffer) + l := buffer.Len() + n, err := buffer.WriteTo(s.conn) + //common.BuffPool.Put(buffer) + if err != nil || int(n) != l { + logs.Warn("close from write session fail ", err, n, l) + s.Close() break } } } -func (s *Mux) writeBuf() { - for { - if s.IsClose { - break - } - select { - case buffer := <-s.bufCh: - l := buffer.Len() - n, err := buffer.WriteTo(s.conn) - common.BuffPool.Put(buffer) - if err != nil || int(n) != l { - logs.Warn("close from write session fail ", err, n, l) - s.Close() - break - } - case <-s.closeChan: - break - } - } -} +//func (s *Mux) writeBuf() { +// for { +// if s.IsClose { +// break +// } +// buffer, err := s.bufQueue.Pop() +// if err != nil { +// break +// } +// l := buffer.Len() +// n, err := buffer.WriteTo(s.conn) +// common.BuffPool.Put(buffer) +// if err != nil || int(n) != l { +// logs.Warn("close from write session fail ", err, n, l) +// s.Close() +// break +// } +// } +//} func (s *Mux) ping() { go func() { @@ -310,8 +314,7 @@ func (s *Mux) Close() error { } s.IsClose = true s.connMap.Close() - s.closeChan <- struct{}{} - s.closeChan <- struct{}{} + //s.bufQueue.Stop() s.closeChan <- struct{}{} close(s.newConnCh) return s.conn.Close() diff --git a/lib/mux/mux_test.go b/lib/mux/mux_test.go index 0ac54d5..e3f9dcc 100644 --- a/lib/mux/mux_test.go +++ b/lib/mux/mux_test.go @@ -4,12 +4,14 @@ import ( "bufio" "fmt" "github.com/cnlh/nps/lib/common" + "io" "log" "net" "net/http" "net/http/httputil" _ "net/http/pprof" "strconv" + "sync" "testing" "time" "unsafe" @@ -48,42 +50,42 @@ func TestNewMux(t *testing.T) { //c2.(*net.TCPConn).SetReadBuffer(0) //c2.(*net.TCPConn).SetReadBuffer(0) go func(c2 net.Conn, c *conn) { - //wg := sync.WaitGroup{} - //wg.Add(1) - //go func() { - // _, err = common.CopyBuffer(c2, c) - // if err != nil { - // c2.Close() - // c.Close() - // logs.Warn("close npc by copy from nps", err, c.connId) - // } - // wg.Done() - //}() - //wg.Add(1) - //go func() { - // _, err = common.CopyBuffer(c, c2) - // if err != nil { - // c2.Close() - // c.Close() - // logs.Warn("close npc by copy from server", err, c.connId) - // } - // wg.Done() - //}() - ////logs.Warn("npc wait") - //wg.Wait() + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + _, err = common.CopyBuffer(c2, c) + if err != nil { + c2.Close() + c.Close() + //logs.Warn("close npc by copy from nps", err, c.connId) + } + wg.Done() + }() + wg.Add(1) + go func() { + _, err = common.CopyBuffer(c, c2) + if err != nil { + c2.Close() + c.Close() + //logs.Warn("close npc by copy from server", err, c.connId) + } + wg.Done() + }() + //logs.Warn("npc wait") + wg.Wait() }(c2, c.(*conn)) } }() go func() { - //m1 := NewMux(conn1, "tcp") + m1 := NewMux(conn1, "tcp") l, err := net.Listen("tcp", "127.0.0.1:7777") if err != nil { logs.Warn(err) } for { //logs.Warn("nps starting accept") - _, err := l.Accept() + conns, err := l.Accept() if err != nil { logs.Warn(err) continue @@ -91,37 +93,38 @@ func TestNewMux(t *testing.T) { //conns.(*net.TCPConn).SetReadBuffer(0) //conns.(*net.TCPConn).SetReadBuffer(0) //logs.Warn("nps accept success starting new conn") - //tmpCpnn, err := m1.NewConn() - //if err != nil { - // logs.Warn("nps new conn err ", err) - // continue - //} - ////logs.Warn("nps new conn success ", tmpCpnn.connId) - //go func(tmpCpnn *conn, conns net.Conn) { - // //go func() { - // // _, err := common.CopyBuffer(tmpCpnn, conns) - // // if err != nil { - // // conns.Close() - // // tmpCpnn.Close() - // // logs.Warn("close nps by copy from user", tmpCpnn.connId, err) - // // } - // //}() - // ////time.Sleep(time.Second) - // //_, err = common.CopyBuffer(conns, tmpCpnn) - // //if err != nil { - // // conns.Close() - // // tmpCpnn.Close() - // // logs.Warn("close nps by copy from npc ", tmpCpnn.connId, err) - // //} - //}(tmpCpnn, conns) + tmpCpnn, err := m1.NewConn() + if err != nil { + logs.Warn("nps new conn err ", err) + continue + } + //logs.Warn("nps new conn success ", tmpCpnn.connId) + go func(tmpCpnn *conn, conns net.Conn) { + go func() { + _, err := common.CopyBuffer(tmpCpnn, conns) + if err != nil { + conns.Close() + tmpCpnn.Close() + //logs.Warn("close nps by copy from user", tmpCpnn.connId, err) + } + }() + //time.Sleep(time.Second) + _, err = common.CopyBuffer(conns, tmpCpnn) + if err != nil { + conns.Close() + tmpCpnn.Close() + //logs.Warn("close nps by copy from npc ", tmpCpnn.connId, err) + } + }(tmpCpnn, conns) } }() - go NewLogServer() + //go NewLogServer() time.Sleep(time.Second * 5) for i := 0; i < 1000; i++ { go test_raw(i) } + //test_request() for { time.Sleep(time.Second * 5) @@ -154,7 +157,7 @@ func client() { func test_request() { conn, _ := net.Dial("tcp", "127.0.0.1:7777") for { - conn.Write([]byte(`GET /videojs5/video.js HTTP/1.1 + conn.Write([]byte(`GET / HTTP/1.1 Host: 127.0.0.1:7777 Connection: keep-alive @@ -177,39 +180,42 @@ Connection: keep-alive } func test_raw(k int) { - for i := 0; i < 1; i++ { + for i := 0; i < 10; i++ { ti := time.Now() - _, _ = net.Dial("tcp", "127.0.0.1:7777") + conn, err := net.Dial("tcp", "127.0.0.1:7777") + if err != nil { + logs.Warn("conn dial err", err) + } tid := time.Now() - // conn.Write([]byte(`GET / HTTP/1.1 - //Host: 127.0.0.1:7777 - // - // - //`)) - // tiw := time.Now() - //buf := make([]byte, 3572) - //n, err := io.ReadFull(conn, buf) - ////n, err := conn.Read(buf) - //if err != nil { - // logs.Warn("close by read response err", err) - // break - //} - ////logs.Warn(n, string(buf[:50]), "\n--------------\n", string(buf[n-50:n])) - ////time.Sleep(time.Second) - //err = conn.Close() - //if err != nil { - // logs.Warn("close conn err ", err) - //} + conn.Write([]byte(`GET / HTTP/1.1 +Host: 127.0.0.1:7777 + + +`)) + tiw := time.Now() + buf := make([]byte, 3572) + n, err := io.ReadFull(conn, buf) + //n, err := conn.Read(buf) + if err != nil { + logs.Warn("close by read response err", err) + break + } + logs.Warn(n, string(buf[:50]), "\n--------------\n", string(buf[n-50:n])) + //time.Sleep(time.Second) + err = conn.Close() + if err != nil { + logs.Warn("close conn err ", err) + } now := time.Now() du := now.Sub(ti).Seconds() dud := now.Sub(tid).Seconds() - //duw := now.Sub(tiw).Seconds() - //if du > 1 { - logs.Warn("duration long", du, dud, k, i) - //} - //if n != 3572 { - // logs.Warn("n loss", n, string(buf)) - //} + duw := now.Sub(tiw).Seconds() + if du > 1 { + logs.Warn("duration long", du, dud, duw, k, i) + } + if n != 3572 { + logs.Warn("n loss", n, string(buf)) + } } } @@ -293,11 +299,11 @@ func TestFIFO(t *testing.T) { logs.EnableFuncCallDepth(true) logs.SetLogFuncCallDepth(3) time.Sleep(time.Second * 5) - d := new(FIFOQueue) + d := new(ReceiveWindowQueue) d.New() go func() { time.Sleep(time.Second) - for i := 0; i < 30000; i++ { + for i := 0; i < 30010; i++ { data, err := d.Pop() if err == nil { //fmt.Println(i, string(data.buf), err) @@ -306,7 +312,9 @@ func TestFIFO(t *testing.T) { //fmt.Println("err", err) logs.Warn("err", err) } + //logs.Warn(d.Len()) } + logs.Warn("pop finish") }() go func() { time.Sleep(time.Second * 10) @@ -314,10 +322,10 @@ func TestFIFO(t *testing.T) { go func(i int) { for n := 0; n < 10; n++ { data := new(ListElement) - by := []byte("test " + strconv.Itoa(i) + strconv.Itoa(n)) + by := []byte("test " + strconv.Itoa(i) + " " + strconv.Itoa(n)) // _ = data.New(by, uint16(len(by)), true) //fmt.Println(string((*data).buf), data) - logs.Warn(string((*data).buf), data) + //logs.Warn(string((*data).buf), data) d.Push(data) } }(i) @@ -337,11 +345,12 @@ func TestPriority(t *testing.T) { d.New() go func() { time.Sleep(time.Second) - for i := 0; i < 36000; i++ { + for i := 0; i < 36005; i++ { data := d.Pop() //fmt.Println(i, string(data.buf), err) logs.Warn(i, string(data.Content), data) } + logs.Warn("pop finish") }() go func() { time.Sleep(time.Second * 10) diff --git a/lib/mux/queue.go b/lib/mux/queue.go index 488c616..6ed2dd6 100644 --- a/lib/mux/queue.go +++ b/lib/mux/queue.go @@ -1,10 +1,12 @@ package mux import ( + "bytes" "errors" "github.com/cnlh/nps/lib/common" "io" "math" + "runtime" "sync/atomic" "time" "unsafe" @@ -13,7 +15,7 @@ import ( type QueueOp struct { readOp chan struct{} cleanOp chan struct{} - popWait int32 + popWait uint32 } func (Self *QueueOp) New() { @@ -22,7 +24,7 @@ func (Self *QueueOp) New() { } func (Self *QueueOp) allowPop() (closed bool) { - if atomic.CompareAndSwapInt32(&Self.popWait, 1, 0) { + if atomic.CompareAndSwapUint32(&Self.popWait, 1, 0) { select { case Self.readOp <- struct{}{}: return false @@ -44,7 +46,7 @@ type PriorityQueue struct { highestChain *bufChain middleChain *bufChain lowestChain *bufChain - hunger uint8 + starving uint8 } func (Self *PriorityQueue) New() { @@ -73,7 +75,7 @@ func (Self *PriorityQueue) Push(packager *common.MuxPackager) { return } -const maxHunger uint8 = 10 +const maxStarving uint8 = 8 func (Self *PriorityQueue) Pop() (packager *common.MuxPackager) { startPop: @@ -82,31 +84,32 @@ startPop: packager = (*common.MuxPackager)(ptr) return } - if Self.hunger < maxHunger { + if Self.starving < maxStarving { ptr, ok = Self.middleChain.popTail() if ok { packager = (*common.MuxPackager)(ptr) - Self.hunger++ + Self.starving++ return } } ptr, ok = Self.lowestChain.popTail() if ok { packager = (*common.MuxPackager)(ptr) - if Self.hunger > 0 { - Self.hunger = uint8(Self.hunger / 2) + if Self.starving > 0 { + Self.starving = uint8(Self.starving / 2) } return } - if Self.hunger > 0 { + if Self.starving > 0 { ptr, ok = Self.middleChain.popTail() if ok { packager = (*common.MuxPackager)(ptr) + Self.starving++ return } } // PriorityQueue is empty, notice Push method - if atomic.CompareAndSwapInt32(&Self.popWait, 0, 1) { + if atomic.CompareAndSwapUint32(&Self.popWait, 0, 1) { select { case <-Self.readOp: goto startPop @@ -133,7 +136,7 @@ func (Self *ListElement) New(buf []byte, l uint16, part bool) (err error) { return nil } -type FIFOQueue struct { +type ReceiveWindowQueue struct { QueueOp chain *bufChain length uint32 @@ -141,21 +144,21 @@ type FIFOQueue struct { timeout time.Time } -func (Self *FIFOQueue) New() { +func (Self *ReceiveWindowQueue) New() { Self.QueueOp.New() Self.chain = new(bufChain) Self.chain.new(64) Self.stopOp = make(chan struct{}, 1) } -func (Self *FIFOQueue) Push(element *ListElement) { +func (Self *ReceiveWindowQueue) Push(element *ListElement) { Self.chain.pushHead(unsafe.Pointer(element)) atomic.AddUint32(&Self.length, uint32(element.l)) Self.allowPop() return } -func (Self *FIFOQueue) Pop() (element *ListElement, err error) { +func (Self *ReceiveWindowQueue) Pop() (element *ListElement, err error) { startPop: ptr, ok := Self.chain.popTail() if ok { @@ -163,7 +166,7 @@ startPop: atomic.AddUint32(&Self.length, ^uint32(element.l-1)) return } - if atomic.CompareAndSwapInt32(&Self.popWait, 0, 1) { + if atomic.CompareAndSwapUint32(&Self.popWait, 0, 1) { t := Self.timeout.Sub(time.Now()) if t <= 0 { t = time.Minute @@ -186,18 +189,62 @@ startPop: goto startPop } -func (Self *FIFOQueue) Len() (n uint32) { +func (Self *ReceiveWindowQueue) Len() (n uint32) { return atomic.LoadUint32(&Self.length) } -func (Self *FIFOQueue) Stop() { +func (Self *ReceiveWindowQueue) Stop() { Self.stopOp <- struct{}{} } -func (Self *FIFOQueue) SetTimeOut(t time.Time) { +func (Self *ReceiveWindowQueue) SetTimeOut(t time.Time) { Self.timeout = t } +type BytesQueue struct { + QueueOp + chain *bufChain + stopOp chan struct{} +} + +func (Self *BytesQueue) New() { + Self.QueueOp.New() + Self.chain = new(bufChain) + Self.chain.new(8) + Self.stopOp = make(chan struct{}, 1) +} + +func (Self *BytesQueue) Push(buf *bytes.Buffer) { + Self.chain.pushHead(unsafe.Pointer(buf)) + Self.allowPop() + return +} + +func (Self *BytesQueue) Pop() (buf *bytes.Buffer, err error) { +startPop: + ptr, ok := Self.chain.popTail() + if ok { + buf = (*bytes.Buffer)(ptr) + return + } + if atomic.CompareAndSwapUint32(&Self.popWait, 0, 1) { + select { + case <-Self.readOp: + goto startPop + case <-Self.cleanOp: + return + case <-Self.stopOp: + err = io.EOF + return + } + } + goto startPop +} + +func (Self *BytesQueue) Stop() { + Self.stopOp <- struct{}{} +} + // https://golang.org/src/sync/poolqueue.go type bufDequeue struct { @@ -224,7 +271,8 @@ type bufDequeue struct { // index has moved beyond it and typ has been set to nil. This // is set to nil atomically by the consumer and read // atomically by the producer. - vals []unsafe.Pointer + vals []unsafe.Pointer + starving uint32 } const dequeueBits = 32 @@ -253,6 +301,10 @@ func (d *bufDequeue) pack(head, tail uint32) uint64 { // queue is full. func (d *bufDequeue) pushHead(val unsafe.Pointer) bool { var slot *unsafe.Pointer + var starve uint8 + if atomic.LoadUint32(&d.starving) > 0 { + runtime.Gosched() + } for { ptrs := atomic.LoadUint64(&d.headTail) head, tail := d.unpack(ptrs) @@ -263,8 +315,15 @@ func (d *bufDequeue) pushHead(val unsafe.Pointer) bool { ptrs2 := d.pack(head+1, tail) if atomic.CompareAndSwapUint64(&d.headTail, ptrs, ptrs2) { slot = &d.vals[head&uint32(len(d.vals)-1)] + if starve >= 3 && atomic.LoadUint32(&d.starving) > 0 { + atomic.StoreUint32(&d.starving, 0) + } break } + starve++ + if starve >= 3 { + atomic.StoreUint32(&d.starving, 1) + } } // The head slot is free, so we own it. *slot = val @@ -321,8 +380,8 @@ type bufChain struct { // tail is the bufDequeue to popTail from. This is accessed // by consumers, so reads and writes must be atomic. - tail *bufChainElt - chainStatus int32 + tail *bufChainElt + newChain uint32 } type bufChainElt struct { @@ -359,30 +418,39 @@ func (c *bufChain) new(initSize int) { } func (c *bufChain) pushHead(val unsafe.Pointer) { +startPush: for { - d := loadPoolChainElt(&c.head) - - if d.pushHead(val) { - return - } - - // The current dequeue is full. Allocate a new one of twice - // the size. - if atomic.CompareAndSwapInt32(&c.chainStatus, 0, 1) { - newSize := len(d.vals) * 2 - if newSize >= dequeueLimit { - // Can't make it any bigger. - newSize = dequeueLimit - } - - d2 := &bufChainElt{prev: d} - d2.vals = make([]unsafe.Pointer, newSize) - d2.pushHead(val) - storePoolChainElt(&d.next, d2) - storePoolChainElt(&c.head, d2) - atomic.StoreInt32(&c.chainStatus, 0) + if atomic.LoadUint32(&c.newChain) > 0 { + runtime.Gosched() + } else { + break } } + + d := loadPoolChainElt(&c.head) + + if d.pushHead(val) { + return + } + + // The current dequeue is full. Allocate a new one of twice + // the size. + if atomic.CompareAndSwapUint32(&c.newChain, 0, 1) { + newSize := len(d.vals) * 2 + if newSize >= dequeueLimit { + // Can't make it any bigger. + newSize = dequeueLimit + } + + d2 := &bufChainElt{prev: d} + d2.vals = make([]unsafe.Pointer, newSize) + d2.pushHead(val) + storePoolChainElt(&c.head, d2) + storePoolChainElt(&d.next, d2) + atomic.StoreUint32(&c.newChain, 0) + return + } + goto startPush } func (c *bufChain) popTail() (unsafe.Pointer, bool) { From 5f58c34c8bd53c584f832ace882fe7d175508994 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Sat, 2 Nov 2019 22:59:52 +0800 Subject: [PATCH 47/58] perf test --- go.mod | 1 + go.sum | 2 + lib/common/pool.go | 53 ++++++++++++++ lib/mux/conn.go | 4 +- lib/mux/mux.go | 11 ++- lib/mux/mux_test.go | 122 ++++++++++++++++--------------- lib/mux/queue.go | 172 ++++++++++++++++++++------------------------ 7 files changed, 207 insertions(+), 158 deletions(-) diff --git a/go.mod b/go.mod index 8a19eaf..a540dae 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/klauspost/cpuid v1.2.1 // indirect github.com/klauspost/reedsolomon v1.9.2 // indirect github.com/onsi/gomega v1.5.0 // indirect + github.com/panjf2000/ants/v2 v2.2.2 github.com/pkg/errors v0.8.0 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect github.com/shirou/gopsutil v2.18.12+incompatible diff --git a/go.sum b/go.sum index f3a17f4..f0c4d7f 100644 --- a/go.sum +++ b/go.sum @@ -44,6 +44,8 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/panjf2000/ants/v2 v2.2.2 h1:TWzusBjq/IflXhy+/S6u5wmMLCBdJnB9tPIx9Zmhvok= +github.com/panjf2000/ants/v2 v2.2.2/go.mod h1:1GFm8bV8nyCQvU5K4WvBCTG1/YBFOD2VzjffD8fV55A= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/lib/common/pool.go b/lib/common/pool.go index 240f7f9..5010012 100644 --- a/lib/common/pool.go +++ b/lib/common/pool.go @@ -2,6 +2,8 @@ package common import ( "bytes" + "github.com/panjf2000/ants/v2" + "net" "sync" ) @@ -149,11 +151,62 @@ func (Self *muxPackagerPool) Put(pack *MuxPackager) { Self.pool.Put(pack) } +type connGroup struct { + src net.Conn + dst net.Conn + wg *sync.WaitGroup +} + +func newConnGroup(src net.Conn, dst net.Conn, wg *sync.WaitGroup) connGroup { + return connGroup{ + src: src, + dst: dst, + wg: wg, + } +} + +func copyConnGroup(group interface{}) { + cg, ok := group.(connGroup) + if !ok { + return + } + _, err := CopyBuffer(cg.src, cg.dst) + if err != nil { + cg.src.Close() + cg.dst.Close() + //logs.Warn("close npc by copy from nps", err, c.connId) + } + cg.wg.Done() +} + +type Conns struct { + conn1 net.Conn + conn2 net.Conn +} + +func NewConns(c1 net.Conn, c2 net.Conn) Conns { + return Conns{ + conn1: c1, + conn2: c2, + } +} + +func copyConns(group interface{}) { + conns := group.(Conns) + wg := new(sync.WaitGroup) + wg.Add(2) + _ = connCopyPool.Invoke(newConnGroup(conns.conn1, conns.conn2, wg)) + _ = connCopyPool.Invoke(newConnGroup(conns.conn2, conns.conn1, wg)) + wg.Wait() +} + var once = sync.Once{} var BuffPool = bufferPool{} var CopyBuff = copyBufferPool{} var MuxPack = muxPackagerPool{} var WindowBuff = windowBufferPool{} +var connCopyPool, _ = ants.NewPoolWithFunc(200000, copyConnGroup, ants.WithNonblocking(false)) +var CopyConnsPool, _ = ants.NewPoolWithFunc(100000, copyConns, ants.WithNonblocking(false)) func newPool() { BuffPool.New() diff --git a/lib/mux/conn.go b/lib/mux/conn.go index f3217d8..0ba6f90 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -156,7 +156,7 @@ type ReceiveWindow struct { bufQueue ReceiveWindowQueue element *ListElement readLength uint32 - readOp chan struct{} + //readOp chan struct{} readWait bool windowFull uint32 count int8 @@ -167,7 +167,7 @@ type ReceiveWindow struct { func (Self *ReceiveWindow) New(mux *Mux) { // initial a window for receive - Self.readOp = make(chan struct{}) + //Self.readOp = make(chan struct{}) Self.bufQueue.New() //Self.bw = new(bandwidth) Self.element = new(ListElement) diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 8a6086c..6a2d6b6 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -5,7 +5,6 @@ import ( "io" "math" "net" - "sync" "sync/atomic" "time" @@ -29,7 +28,7 @@ type Mux struct { connType string writeQueue PriorityQueue //bufQueue BytesQueue - sync.Mutex + //sync.Mutex } func NewMux(c net.Conn, connType string) *Mux { @@ -216,7 +215,7 @@ func (s *Mux) pingReturn() { if latency < 0.5 && latency > 0 { s.latency = latency } - //logs.Warn("latency", s.latency) + logs.Warn("latency", s.latency) common.WindowBuff.Put(data) } }() @@ -242,15 +241,19 @@ func (s *Mux) readSession() { case common.MUX_NEW_CONN: //new connection connection := NewConn(pack.Id, s, "npc ") s.connMap.Set(pack.Id, connection) //it has been set before send ok + //go func(connection *conn) { s.newConnCh <- connection s.sendInfo(common.MUX_NEW_CONN_OK, connection.connId, nil) + //}(connection) continue case common.MUX_PING_FLAG: //ping s.sendInfo(common.MUX_PING_RETURN, common.MUX_PING, pack.Content) common.WindowBuff.Put(pack.Content) continue case common.MUX_PING_RETURN: + //go func(content []byte) { s.pingCh <- pack.Content + //}(pack.Content) continue } if connection, ok := s.connMap.Get(pack.Id); ok && !connection.isClose { @@ -275,8 +278,10 @@ func (s *Mux) readSession() { continue case common.MUX_CONN_CLOSE: //close the connection s.connMap.Delete(pack.Id) + //go func(connection *conn) { connection.closeFlag = true connection.receiveWindow.Stop() // close signal to receive window + //}(connection) continue } } else if pack.Flag == common.MUX_CONN_CLOSE { diff --git a/lib/mux/mux_test.go b/lib/mux/mux_test.go index e3f9dcc..d3061ab 100644 --- a/lib/mux/mux_test.go +++ b/lib/mux/mux_test.go @@ -11,7 +11,6 @@ import ( "net/http/httputil" _ "net/http/pprof" "strconv" - "sync" "testing" "time" "unsafe" @@ -30,6 +29,7 @@ func TestNewMux(t *testing.T) { logs.SetLogFuncCallDepth(3) server() client() + //poolConnCopy, _ := ants.NewPoolWithFunc(200000, common.copyConn, ants.WithNonblocking(false)) time.Sleep(time.Second * 3) go func() { m2 := NewMux(conn2, "tcp") @@ -49,31 +49,34 @@ func TestNewMux(t *testing.T) { } //c2.(*net.TCPConn).SetReadBuffer(0) //c2.(*net.TCPConn).SetReadBuffer(0) - go func(c2 net.Conn, c *conn) { - wg := sync.WaitGroup{} - wg.Add(1) - go func() { - _, err = common.CopyBuffer(c2, c) - if err != nil { - c2.Close() - c.Close() - //logs.Warn("close npc by copy from nps", err, c.connId) - } - wg.Done() - }() - wg.Add(1) - go func() { - _, err = common.CopyBuffer(c, c2) - if err != nil { - c2.Close() - c.Close() - //logs.Warn("close npc by copy from server", err, c.connId) - } - wg.Done() - }() - //logs.Warn("npc wait") - wg.Wait() - }(c2, c.(*conn)) + _ = common.CopyConnsPool.Invoke(common.NewConns(c2, c)) + //go func(c2 net.Conn, c *conn) { + // wg := new(sync.WaitGroup) + // wg.Add(2) + // _ = poolConnCopy.Invoke(common.newConnGroup(c2, c, wg)) + // //go func() { + // // _, err = common.CopyBuffer(c2, c) + // // if err != nil { + // // c2.Close() + // // c.Close() + // // //logs.Warn("close npc by copy from nps", err, c.connId) + // // } + // // wg.Done() + // //}() + // //wg.Add(1) + // _ = poolConnCopy.Invoke(common.newConnGroup(c, c2, wg)) + // //go func() { + // // _, err = common.CopyBuffer(c, c2) + // // if err != nil { + // // c2.Close() + // // c.Close() + // // //logs.Warn("close npc by copy from server", err, c.connId) + // // } + // // wg.Done() + // //}() + // //logs.Warn("npc wait") + // wg.Wait() + //}(c2, c.(*conn)) } }() @@ -99,23 +102,30 @@ func TestNewMux(t *testing.T) { continue } //logs.Warn("nps new conn success ", tmpCpnn.connId) - go func(tmpCpnn *conn, conns net.Conn) { - go func() { - _, err := common.CopyBuffer(tmpCpnn, conns) - if err != nil { - conns.Close() - tmpCpnn.Close() - //logs.Warn("close nps by copy from user", tmpCpnn.connId, err) - } - }() - //time.Sleep(time.Second) - _, err = common.CopyBuffer(conns, tmpCpnn) - if err != nil { - conns.Close() - tmpCpnn.Close() - //logs.Warn("close nps by copy from npc ", tmpCpnn.connId, err) - } - }(tmpCpnn, conns) + _ = common.CopyConnsPool.Invoke(common.NewConns(tmpCpnn, conns)) + //go func(tmpCpnn *conn, conns net.Conn) { + // wg := new(sync.WaitGroup) + // wg.Add(2) + // _ = poolConnCopy.Invoke(common.newConnGroup(tmpCpnn, conns, wg)) + // //go func() { + // // _, err := common.CopyBuffer(tmpCpnn, conns) + // // if err != nil { + // // conns.Close() + // // tmpCpnn.Close() + // // //logs.Warn("close nps by copy from user", tmpCpnn.connId, err) + // // } + // //}() + // //wg.Add(1) + // _ = poolConnCopy.Invoke(common.newConnGroup(conns, tmpCpnn, wg)) + // //time.Sleep(time.Second) + // //_, err = common.CopyBuffer(conns, tmpCpnn) + // //if err != nil { + // // conns.Close() + // // tmpCpnn.Close() + // // //logs.Warn("close nps by copy from npc ", tmpCpnn.connId, err) + // //} + // wg.Wait() + //}(tmpCpnn, conns) } }() @@ -180,7 +190,7 @@ Connection: keep-alive } func test_raw(k int) { - for i := 0; i < 10; i++ { + for i := 0; i < 1; i++ { ti := time.Now() conn, err := net.Dial("tcp", "127.0.0.1:7777") if err != nil { @@ -303,7 +313,7 @@ func TestFIFO(t *testing.T) { d.New() go func() { time.Sleep(time.Second) - for i := 0; i < 30010; i++ { + for i := 0; i < 300100; i++ { data, err := d.Pop() if err == nil { //fmt.Println(i, string(data.buf), err) @@ -318,17 +328,13 @@ func TestFIFO(t *testing.T) { }() go func() { time.Sleep(time.Second * 10) - for i := 0; i < 3000; i++ { - go func(i int) { - for n := 0; n < 10; n++ { - data := new(ListElement) - by := []byte("test " + strconv.Itoa(i) + " " + strconv.Itoa(n)) // - _ = data.New(by, uint16(len(by)), true) - //fmt.Println(string((*data).buf), data) - //logs.Warn(string((*data).buf), data) - d.Push(data) - } - }(i) + for i := 0; i < 300000; i++ { + data := new(ListElement) + by := []byte("test " + strconv.Itoa(i) + " ") // + _ = data.New(by, uint16(len(by)), true) + //fmt.Println(string((*data).buf), data) + //logs.Warn(string((*data).buf), data) + d.Push(data) } }() time.Sleep(time.Second * 100000) @@ -345,7 +351,7 @@ func TestPriority(t *testing.T) { d.New() go func() { time.Sleep(time.Second) - for i := 0; i < 36005; i++ { + for i := 0; i < 360050; i++ { data := d.Pop() //fmt.Println(i, string(data.buf), err) logs.Warn(i, string(data.Content), data) @@ -354,7 +360,7 @@ func TestPriority(t *testing.T) { }() go func() { time.Sleep(time.Second * 10) - for i := 0; i < 3000; i++ { + for i := 0; i < 30000; i++ { go func(i int) { for n := 0; n < 10; n++ { data := new(common.MuxPackager) diff --git a/lib/mux/queue.go b/lib/mux/queue.go index 6ed2dd6..e3c39a1 100644 --- a/lib/mux/queue.go +++ b/lib/mux/queue.go @@ -1,52 +1,24 @@ package mux import ( - "bytes" "errors" "github.com/cnlh/nps/lib/common" "io" "math" "runtime" + "sync" "sync/atomic" "time" "unsafe" ) -type QueueOp struct { - readOp chan struct{} - cleanOp chan struct{} - popWait uint32 -} - -func (Self *QueueOp) New() { - Self.readOp = make(chan struct{}) - Self.cleanOp = make(chan struct{}, 2) -} - -func (Self *QueueOp) allowPop() (closed bool) { - if atomic.CompareAndSwapUint32(&Self.popWait, 1, 0) { - select { - case Self.readOp <- struct{}{}: - return false - case <-Self.cleanOp: - return true - } - } - return -} - -func (Self *QueueOp) Clean() { - Self.cleanOp <- struct{}{} - Self.cleanOp <- struct{}{} - close(Self.cleanOp) -} - type PriorityQueue struct { - QueueOp highestChain *bufChain middleChain *bufChain lowestChain *bufChain starving uint8 + stop bool + cond *sync.Cond } func (Self *PriorityQueue) New() { @@ -56,7 +28,8 @@ func (Self *PriorityQueue) New() { Self.middleChain.new(32) Self.lowestChain = new(bufChain) Self.lowestChain.new(256) - Self.QueueOp.New() + locker := new(sync.Mutex) + Self.cond = sync.NewCond(locker) } func (Self *PriorityQueue) Push(packager *common.MuxPackager) { @@ -71,14 +44,44 @@ func (Self *PriorityQueue) Push(packager *common.MuxPackager) { default: Self.lowestChain.pushHead(unsafe.Pointer(packager)) } - Self.allowPop() + //atomic.AddUint32(&Self.count, 1) + Self.cond.Signal() return } const maxStarving uint8 = 8 func (Self *PriorityQueue) Pop() (packager *common.MuxPackager) { -startPop: + // PriorityQueue is empty, notice Push method + var iter bool + for { + packager = Self.pop() + if packager != nil { + return + } + if Self.stop { + return + } + if iter { + break + } + iter = true + runtime.Gosched() + } + Self.cond.L.Lock() + defer Self.cond.L.Unlock() + for packager = Self.pop(); packager == nil; { + if Self.stop { + return + } + Self.cond.Wait() + packager = Self.pop() + } + //atomic.AddUint32(&Self.count, ^uint32(0)) + return +} + +func (Self *PriorityQueue) pop() (packager *common.MuxPackager) { ptr, ok := Self.highestChain.popTail() if ok { packager = (*common.MuxPackager)(ptr) @@ -108,16 +111,12 @@ startPop: return } } - // PriorityQueue is empty, notice Push method - if atomic.CompareAndSwapUint32(&Self.popWait, 0, 1) { - select { - case <-Self.readOp: - goto startPop - case <-Self.cleanOp: - return nil - } - } - goto startPop + return +} + +func (Self *PriorityQueue) Stop() { + Self.stop = true + Self.cond.Broadcast() } type ListElement struct { @@ -137,18 +136,19 @@ func (Self *ListElement) New(buf []byte, l uint16, part bool) (err error) { } type ReceiveWindowQueue struct { - QueueOp chain *bufChain length uint32 stopOp chan struct{} + readOp chan struct{} + popWait uint32 timeout time.Time } func (Self *ReceiveWindowQueue) New() { - Self.QueueOp.New() + Self.readOp = make(chan struct{}) Self.chain = new(bufChain) Self.chain.new(64) - Self.stopOp = make(chan struct{}, 1) + Self.stopOp = make(chan struct{}, 2) } func (Self *ReceiveWindowQueue) Push(element *ListElement) { @@ -158,15 +158,30 @@ func (Self *ReceiveWindowQueue) Push(element *ListElement) { return } -func (Self *ReceiveWindowQueue) Pop() (element *ListElement, err error) { -startPop: +func (Self *ReceiveWindowQueue) pop() (element *ListElement) { ptr, ok := Self.chain.popTail() if ok { element = (*ListElement)(ptr) atomic.AddUint32(&Self.length, ^uint32(element.l-1)) return } + return +} + +func (Self *ReceiveWindowQueue) Pop() (element *ListElement, err error) { + var iter bool +startPop: + element = Self.pop() + if element != nil { + return + } + if !iter { + iter = true + runtime.Gosched() + goto startPop + } if atomic.CompareAndSwapUint32(&Self.popWait, 0, 1) { + iter = false t := Self.timeout.Sub(time.Now()) if t <= 0 { t = time.Minute @@ -176,8 +191,6 @@ startPop: select { case <-Self.readOp: goto startPop - case <-Self.cleanOp: - return case <-Self.stopOp: err = io.EOF return @@ -189,62 +202,31 @@ startPop: goto startPop } +func (Self *ReceiveWindowQueue) allowPop() (closed bool) { + if atomic.CompareAndSwapUint32(&Self.popWait, 1, 0) { + select { + case Self.readOp <- struct{}{}: + return false + case <-Self.stopOp: + return true + } + } + return +} + func (Self *ReceiveWindowQueue) Len() (n uint32) { return atomic.LoadUint32(&Self.length) } func (Self *ReceiveWindowQueue) Stop() { Self.stopOp <- struct{}{} + Self.stopOp <- struct{}{} } func (Self *ReceiveWindowQueue) SetTimeOut(t time.Time) { Self.timeout = t } -type BytesQueue struct { - QueueOp - chain *bufChain - stopOp chan struct{} -} - -func (Self *BytesQueue) New() { - Self.QueueOp.New() - Self.chain = new(bufChain) - Self.chain.new(8) - Self.stopOp = make(chan struct{}, 1) -} - -func (Self *BytesQueue) Push(buf *bytes.Buffer) { - Self.chain.pushHead(unsafe.Pointer(buf)) - Self.allowPop() - return -} - -func (Self *BytesQueue) Pop() (buf *bytes.Buffer, err error) { -startPop: - ptr, ok := Self.chain.popTail() - if ok { - buf = (*bytes.Buffer)(ptr) - return - } - if atomic.CompareAndSwapUint32(&Self.popWait, 0, 1) { - select { - case <-Self.readOp: - goto startPop - case <-Self.cleanOp: - return - case <-Self.stopOp: - err = io.EOF - return - } - } - goto startPop -} - -func (Self *BytesQueue) Stop() { - Self.stopOp <- struct{}{} -} - // https://golang.org/src/sync/poolqueue.go type bufDequeue struct { From f362c96e1ee801e41703de2fea93c3239593122e Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Sat, 9 Nov 2019 23:02:29 +0800 Subject: [PATCH 48/58] fine mux, add goroutine pool --- lib/common/pool.go | 67 ++++-------- lib/conn/conn.go | 37 ++++--- lib/goroutine/pool.go | 73 +++++++++++++ lib/mux/conn.go | 247 +++++++++++++++++++++++++----------------- lib/mux/mux.go | 2 +- lib/mux/mux_test.go | 31 +++--- lib/mux/queue.go | 123 +++++++++++---------- 7 files changed, 352 insertions(+), 228 deletions(-) create mode 100644 lib/goroutine/pool.go diff --git a/lib/common/pool.go b/lib/common/pool.go index 5010012..5d4da00 100644 --- a/lib/common/pool.go +++ b/lib/common/pool.go @@ -2,8 +2,6 @@ package common import ( "bytes" - "github.com/panjf2000/ants/v2" - "net" "sync" ) @@ -151,53 +149,34 @@ func (Self *muxPackagerPool) Put(pack *MuxPackager) { Self.pool.Put(pack) } -type connGroup struct { - src net.Conn - dst net.Conn - wg *sync.WaitGroup +type ListElement struct { + Buf []byte + L uint16 + Part bool } -func newConnGroup(src net.Conn, dst net.Conn, wg *sync.WaitGroup) connGroup { - return connGroup{ - src: src, - dst: dst, - wg: wg, +type listElementPool struct { + pool sync.Pool +} + +func (Self *listElementPool) New() { + Self.pool = sync.Pool{ + New: func() interface{} { + element := ListElement{} + return &element + }, } } -func copyConnGroup(group interface{}) { - cg, ok := group.(connGroup) - if !ok { - return - } - _, err := CopyBuffer(cg.src, cg.dst) - if err != nil { - cg.src.Close() - cg.dst.Close() - //logs.Warn("close npc by copy from nps", err, c.connId) - } - cg.wg.Done() +func (Self *listElementPool) Get() *ListElement { + return Self.pool.Get().(*ListElement) } -type Conns struct { - conn1 net.Conn - conn2 net.Conn -} - -func NewConns(c1 net.Conn, c2 net.Conn) Conns { - return Conns{ - conn1: c1, - conn2: c2, - } -} - -func copyConns(group interface{}) { - conns := group.(Conns) - wg := new(sync.WaitGroup) - wg.Add(2) - _ = connCopyPool.Invoke(newConnGroup(conns.conn1, conns.conn2, wg)) - _ = connCopyPool.Invoke(newConnGroup(conns.conn2, conns.conn1, wg)) - wg.Wait() +func (Self *listElementPool) Put(element *ListElement) { + element.L = 0 + element.Buf = nil + element.Part = false + Self.pool.Put(element) } var once = sync.Once{} @@ -205,14 +184,14 @@ var BuffPool = bufferPool{} var CopyBuff = copyBufferPool{} var MuxPack = muxPackagerPool{} var WindowBuff = windowBufferPool{} -var connCopyPool, _ = ants.NewPoolWithFunc(200000, copyConnGroup, ants.WithNonblocking(false)) -var CopyConnsPool, _ = ants.NewPoolWithFunc(100000, copyConns, ants.WithNonblocking(false)) +var ListElementPool = listElementPool{} func newPool() { BuffPool.New() CopyBuff.New() MuxPack.New() WindowBuff.New() + ListElementPool.New() } func init() { diff --git a/lib/conn/conn.go b/lib/conn/conn.go index 7946c0d..9f0c397 100755 --- a/lib/conn/conn.go +++ b/lib/conn/conn.go @@ -6,13 +6,14 @@ import ( "encoding/binary" "encoding/json" "errors" + "github.com/astaxie/beego/logs" + "github.com/cnlh/nps/lib/goroutine" "io" "net" "net/http" "net/url" "strconv" "strings" - "sync" "time" "github.com/cnlh/nps/lib/common" @@ -350,25 +351,29 @@ func SetUdpSession(sess *kcp.UDPSession) { //conn1 mux conn func CopyWaitGroup(conn1, conn2 net.Conn, crypt bool, snappy bool, rate *rate.Rate, flow *file.Flow, isServer bool, rb []byte) { - var in, out int64 - var wg sync.WaitGroup + //var in, out int64 + //var wg sync.WaitGroup connHandle := GetConn(conn1, crypt, snappy, rate, isServer) if rb != nil { connHandle.Write(rb) } - go func(in *int64) { - wg.Add(1) - *in, _ = common.CopyBuffer(connHandle, conn2) - connHandle.Close() - conn2.Close() - wg.Done() - }(&in) - out, _ = common.CopyBuffer(conn2, connHandle) - connHandle.Close() - conn2.Close() - wg.Wait() - if flow != nil { - flow.Add(in, out) + //go func(in *int64) { + // wg.Add(1) + // *in, _ = common.CopyBuffer(connHandle, conn2) + // connHandle.Close() + // conn2.Close() + // wg.Done() + //}(&in) + //out, _ = common.CopyBuffer(conn2, connHandle) + //connHandle.Close() + //conn2.Close() + //wg.Wait() + //if flow != nil { + // flow.Add(in, out) + //} + err := goroutine.CopyConnsPool.Invoke(goroutine.NewConns(connHandle, conn2, flow)) + if err != nil { + logs.Error(err) } } diff --git a/lib/goroutine/pool.go b/lib/goroutine/pool.go new file mode 100644 index 0000000..287c711 --- /dev/null +++ b/lib/goroutine/pool.go @@ -0,0 +1,73 @@ +package goroutine + +import ( + "github.com/cnlh/nps/lib/common" + "github.com/cnlh/nps/lib/file" + "github.com/panjf2000/ants/v2" + "io" + "net" + "sync" +) + +type connGroup struct { + src io.ReadWriteCloser + dst io.ReadWriteCloser + wg *sync.WaitGroup + n *int64 +} + +func newConnGroup(dst, src io.ReadWriteCloser, wg *sync.WaitGroup, n *int64) connGroup { + return connGroup{ + src: src, + dst: dst, + wg: wg, + n: n, + } +} + +func copyConnGroup(group interface{}) { + cg, ok := group.(connGroup) + if !ok { + return + } + var err error + *cg.n, err = common.CopyBuffer(cg.dst, cg.src) + if err != nil { + cg.src.Close() + cg.dst.Close() + //logs.Warn("close npc by copy from nps", err, c.connId) + } + cg.wg.Done() +} + +type Conns struct { + conn1 io.ReadWriteCloser // mux connection + conn2 net.Conn // outside connection + flow *file.Flow +} + +func NewConns(c1 io.ReadWriteCloser, c2 net.Conn, flow *file.Flow) Conns { + return Conns{ + conn1: c1, + conn2: c2, + flow: flow, + } +} + +func copyConns(group interface{}) { + conns := group.(Conns) + wg := new(sync.WaitGroup) + wg.Add(2) + var in, out int64 + _ = connCopyPool.Invoke(newConnGroup(conns.conn1, conns.conn2, wg, &in)) + // outside to mux : incoming + _ = connCopyPool.Invoke(newConnGroup(conns.conn2, conns.conn1, wg, &out)) + // mux to outside : outgoing + wg.Wait() + if conns.flow != nil { + conns.flow.Add(in, out) + } +} + +var connCopyPool, _ = ants.NewPoolWithFunc(200000, copyConnGroup, ants.WithNonblocking(false)) +var CopyConnsPool, _ = ants.NewPoolWithFunc(100000, copyConns, ants.WithNonblocking(false)) diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 0ba6f90..cb982e8 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -4,6 +4,7 @@ import ( "errors" "io" "net" + "runtime" "sync" "sync/atomic" "time" @@ -57,7 +58,12 @@ func (s *conn) Read(buf []byte) (n int, err error) { return 0, nil } // waiting for takeout from receive window finish or timeout + //now := time.Now() n, err = s.receiveWindow.Read(buf, s.connId) + //t := time.Now().Sub(now) + //if t.Seconds() > 0.5 { + //logs.Warn("conn read long", n, t.Seconds()) + //} //var errstr string //if err == nil { // errstr = "err:nil" @@ -82,7 +88,12 @@ func (s *conn) Write(buf []byte) (n int, err error) { return 0, nil } //logs.Warn("write buf", len(buf)) + //now := time.Now() n, err = s.sendWindow.WriteFull(buf, s.connId) + //t := time.Now().Sub(now) + //if t.Seconds() > 0.5 { + // logs.Warn("conn write long", n, t.Seconds()) + //} return } @@ -133,11 +144,25 @@ func (s *conn) SetWriteDeadline(t time.Time) error { } type window struct { - off uint32 - maxSize uint32 - closeOp bool - closeOpCh chan struct{} - mux *Mux + off uint32 + maxSize uint32 + closeOp bool + closeOpCh chan struct{} + remainingWait uint64 + mux *Mux +} + +func (Self *window) unpack(ptrs uint64) (remaining, wait uint32) { + const mask = 1<> dequeueBits) & mask) + wait = uint32(ptrs & mask) + return +} + +func (Self *window) pack(remaining, wait uint32) uint64 { + const mask = 1< 0 { + n = uint32(l) + } + return } func (Self *ReceiveWindow) calcSize() { @@ -194,8 +212,9 @@ func (Self *ReceiveWindow) calcSize() { if n < 8192 { n = 8192 } - if n < Self.bufQueue.Len() { - n = Self.bufQueue.Len() + bufLen := Self.bufQueue.Len() + if n < bufLen { + n = bufLen } // set the minimal size if n > 2*Self.maxSize { @@ -210,28 +229,39 @@ func (Self *ReceiveWindow) calcSize() { Self.count = -10 } Self.count += 1 + return } func (Self *ReceiveWindow) Write(buf []byte, l uint16, part bool, id int32) (err error) { if Self.closeOp { return errors.New("conn.receiveWindow: write on closed window") } - element := new(ListElement) - err = element.New(buf, l, part) + element, err := NewListElement(buf, l, part) //logs.Warn("push the buf", len(buf), l, (&element).l) if err != nil { return } - Self.bufQueue.Push(element) // must push data before allow read - //logs.Warn("read session calc size ", Self.maxSize) - // calculating the receive window size - Self.calcSize() - //logs.Warn("read session calc size finish", Self.maxSize) - if Self.remainingSize() == 0 { - atomic.StoreUint32(&Self.windowFull, 1) - //logs.Warn("window full true", Self.windowFull) + Self.calcSize() // calculate the max window size + var wait uint32 +start: + ptrs := atomic.LoadUint64(&Self.remainingWait) + _, wait = Self.unpack(ptrs) + newRemaining := Self.remainingSize(l) + // calculate the remaining window size now, plus the element we will push + if newRemaining == 0 { + //logs.Warn("window full true", remaining) + wait = 1 + } + if !atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(0, wait)) { + goto start + // another goroutine change the status, make sure shall we need wait + } + Self.bufQueue.Push(element) + // status check finish, now we can push the element into the queue + if wait == 0 { + Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.maxSize, newRemaining) + // send the remaining window size, not including zero size } - Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, Self.maxSize, Self.readSize()) return nil } @@ -243,10 +273,10 @@ func (Self *ReceiveWindow) Read(p []byte, id int32) (n int, err error) { l := 0 //logs.Warn("receive window read off, element.l", Self.off, Self.element.l) copyData: - //Self.bw.StartRead() - if Self.off == uint32(Self.element.l) { + if Self.off == uint32(Self.element.L) { // on the first Read method invoked, Self.off and Self.element.l // both zero value + common.ListElementPool.Put(Self.element) Self.element, err = Self.bufQueue.Pop() // if the queue is empty, Pop method will wait until one element push // into the queue successful, or timeout. @@ -258,38 +288,44 @@ copyData: } //logs.Warn("pop element", Self.element.l, Self.element.part) } - l = copy(p[pOff:], Self.element.buf[Self.off:Self.element.l]) - //Self.bw.SetCopySize(l) + l = copy(p[pOff:], Self.element.Buf[Self.off:Self.element.L]) pOff += l Self.off += uint32(l) - atomic.AddUint32(&Self.readLength, uint32(l)) //logs.Warn("window read length buf len", Self.readLength, Self.bufQueue.Len()) n += l l = 0 - //Self.bw.EndRead() - if Self.off == uint32(Self.element.l) { + if Self.off == uint32(Self.element.L) { //logs.Warn("put the element end ", string(Self.element.buf[:15])) - common.WindowBuff.Put(Self.element.buf) - Self.sendStatus(id) + common.WindowBuff.Put(Self.element.Buf) + Self.sendStatus(id, Self.element.L) + // check the window full status } - if pOff < len(p) && Self.element.part { + if pOff < len(p) && Self.element.Part { // element is a part of the segments, trying to fill up buf p goto copyData } return // buf p is full or all of segments in buf, return } -func (Self *ReceiveWindow) sendStatus(id int32) { - if Self.bufQueue.Len() == 0 { - // window is full before read or empty now - Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, atomic.LoadUint32(&Self.maxSize), Self.readSize()) - // acknowledge other side, have empty some receive window space - //} +func (Self *ReceiveWindow) sendStatus(id int32, l uint16) { + var remaining, wait uint32 + for { + ptrs := atomic.LoadUint64(&Self.remainingWait) + remaining, wait = Self.unpack(ptrs) + remaining += uint32(l) + if atomic.CompareAndSwapUint64(&Self.remainingWait, ptrs, Self.pack(remaining, 0)) { + break + } + runtime.Gosched() + // another goroutine change remaining or wait status, make sure + // we need acknowledge other side } - if atomic.LoadUint32(&Self.windowFull) > 0 && Self.remainingSize() > 0 { - atomic.StoreUint32(&Self.windowFull, 0) - Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, atomic.LoadUint32(&Self.maxSize), Self.readSize()) + // now we get the current window status success + if wait == 1 { + //logs.Warn("send the wait status", remaining) + Self.mux.sendInfo(common.MUX_MSG_SEND_OK, id, atomic.LoadUint32(&Self.maxSize), remaining) } + return } func (Self *ReceiveWindow) SetTimeOut(t time.Time) { @@ -308,17 +344,16 @@ func (Self *ReceiveWindow) CloseWindow() { } type SendWindow struct { - buf []byte - sentLength uint32 - setSizeCh chan struct{} - setSizeWait uint32 - timeout time.Time + buf []byte + setSizeCh chan struct{} + timeout time.Time window } func (Self *SendWindow) New(mux *Mux) { Self.setSizeCh = make(chan struct{}) Self.maxSize = 4096 + atomic.AddUint64(&Self.remainingWait, uint64(4096)< common.MAXIMUM_SEGMENT_SIZE { sendSize = common.MAXIMUM_SEGMENT_SIZE //logs.Warn("cut buf by mss") } else { sendSize = uint32(len(Self.buf[Self.off:])) } - if Self.RemainingSize() < sendSize { + if remaining < sendSize { // usable window size is small than // window MAXIMUM_SEGMENT_SIZE or send buf left - sendSize = Self.RemainingSize() + sendSize = remaining //logs.Warn("cut buf by remainingsize", sendSize, len(Self.buf[Self.off:])) } //logs.Warn("send size", sendSize) @@ -412,7 +464,7 @@ func (Self *SendWindow) WriteTo() (p []byte, sendSize uint32, part bool, err err } p = Self.buf[Self.off : sendSize+Self.off] Self.off += sendSize - atomic.AddUint32(&Self.sentLength, sendSize) + Self.sent(sendSize) return } @@ -439,6 +491,7 @@ func (Self *SendWindow) waitReceiveWindow() (err error) { func (Self *SendWindow) WriteFull(buf []byte, id int32) (n int, err error) { Self.SetSendBuf(buf) // set the buf to send window + //logs.Warn("set the buf to send window") var bufSeg []byte var part bool var l uint32 diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 6a2d6b6..585c980 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -215,7 +215,7 @@ func (s *Mux) pingReturn() { if latency < 0.5 && latency > 0 { s.latency = latency } - logs.Warn("latency", s.latency) + //logs.Warn("latency", s.latency) common.WindowBuff.Put(data) } }() diff --git a/lib/mux/mux_test.go b/lib/mux/mux_test.go index d3061ab..151def1 100644 --- a/lib/mux/mux_test.go +++ b/lib/mux/mux_test.go @@ -4,6 +4,7 @@ import ( "bufio" "fmt" "github.com/cnlh/nps/lib/common" + "github.com/cnlh/nps/lib/goroutine" "io" "log" "net" @@ -49,7 +50,7 @@ func TestNewMux(t *testing.T) { } //c2.(*net.TCPConn).SetReadBuffer(0) //c2.(*net.TCPConn).SetReadBuffer(0) - _ = common.CopyConnsPool.Invoke(common.NewConns(c2, c)) + _ = goroutine.CopyConnsPool.Invoke(goroutine.NewConns(c, c2, nil)) //go func(c2 net.Conn, c *conn) { // wg := new(sync.WaitGroup) // wg.Add(2) @@ -102,7 +103,7 @@ func TestNewMux(t *testing.T) { continue } //logs.Warn("nps new conn success ", tmpCpnn.connId) - _ = common.CopyConnsPool.Invoke(common.NewConns(tmpCpnn, conns)) + _ = goroutine.CopyConnsPool.Invoke(goroutine.NewConns(tmpCpnn, conns, nil)) //go func(tmpCpnn *conn, conns net.Conn) { // wg := new(sync.WaitGroup) // wg.Add(2) @@ -131,9 +132,9 @@ func TestNewMux(t *testing.T) { //go NewLogServer() time.Sleep(time.Second * 5) - for i := 0; i < 1000; i++ { - go test_raw(i) - } + //for i := 0; i < 1; i++ { + // go test_raw(i) + //} //test_request() for { @@ -166,7 +167,7 @@ func client() { func test_request() { conn, _ := net.Dial("tcp", "127.0.0.1:7777") - for { + for i := 0; i < 1000; i++ { conn.Write([]byte(`GET / HTTP/1.1 Host: 127.0.0.1:7777 Connection: keep-alive @@ -185,19 +186,20 @@ Connection: keep-alive break } fmt.Println(string(b[:20]), err) - time.Sleep(time.Second) + //time.Sleep(time.Second) } + logs.Warn("finish") } func test_raw(k int) { - for i := 0; i < 1; i++ { + for i := 0; i < 1000; i++ { ti := time.Now() conn, err := net.Dial("tcp", "127.0.0.1:7777") if err != nil { logs.Warn("conn dial err", err) } tid := time.Now() - conn.Write([]byte(`GET / HTTP/1.1 + conn.Write([]byte(`GET /videojs5/video.js HTTP/1.1 Host: 127.0.0.1:7777 @@ -227,6 +229,7 @@ Host: 127.0.0.1:7777 logs.Warn("n loss", n, string(buf)) } } + logs.Warn("finish") } func TestNewConn(t *testing.T) { @@ -313,11 +316,12 @@ func TestFIFO(t *testing.T) { d.New() go func() { time.Sleep(time.Second) - for i := 0; i < 300100; i++ { + for i := 0; i < 1001; i++ { data, err := d.Pop() if err == nil { //fmt.Println(i, string(data.buf), err) - logs.Warn(i, string(data.buf), err) + logs.Warn(i, string(data.Buf), err) + common.ListElementPool.Put(data) } else { //fmt.Println("err", err) logs.Warn("err", err) @@ -328,10 +332,9 @@ func TestFIFO(t *testing.T) { }() go func() { time.Sleep(time.Second * 10) - for i := 0; i < 300000; i++ { - data := new(ListElement) + for i := 0; i < 1000; i++ { by := []byte("test " + strconv.Itoa(i) + " ") // - _ = data.New(by, uint16(len(by)), true) + data, _ := NewListElement(by, uint16(len(by)), true) //fmt.Println(string((*data).buf), data) //logs.Warn(string((*data).buf), data) d.Push(data) diff --git a/lib/mux/queue.go b/lib/mux/queue.go index e3c39a1..4790779 100644 --- a/lib/mux/queue.go +++ b/lib/mux/queue.go @@ -44,7 +44,6 @@ func (Self *PriorityQueue) Push(packager *common.MuxPackager) { default: Self.lowestChain.pushHead(unsafe.Pointer(packager)) } - //atomic.AddUint32(&Self.count, 1) Self.cond.Signal() return } @@ -52,7 +51,6 @@ func (Self *PriorityQueue) Push(packager *common.MuxPackager) { const maxStarving uint8 = 8 func (Self *PriorityQueue) Pop() (packager *common.MuxPackager) { - // PriorityQueue is empty, notice Push method var iter bool for { packager = Self.pop() @@ -64,6 +62,7 @@ func (Self *PriorityQueue) Pop() (packager *common.MuxPackager) { } if iter { break + // trying to pop twice } iter = true runtime.Gosched() @@ -74,10 +73,12 @@ func (Self *PriorityQueue) Pop() (packager *common.MuxPackager) { if Self.stop { return } + //logs.Warn("queue into wait") Self.cond.Wait() + // wait for it with no more iter packager = Self.pop() + //logs.Warn("queue wait finish", packager) } - //atomic.AddUint32(&Self.count, ^uint32(0)) return } @@ -88,6 +89,7 @@ func (Self *PriorityQueue) pop() (packager *common.MuxPackager) { return } if Self.starving < maxStarving { + // not pop too much, lowestChain will wait too long ptr, ok = Self.middleChain.popTail() if ok { packager = (*common.MuxPackager)(ptr) @@ -119,29 +121,27 @@ func (Self *PriorityQueue) Stop() { Self.cond.Broadcast() } -type ListElement struct { - buf []byte - l uint16 - part bool -} - -func (Self *ListElement) New(buf []byte, l uint16, part bool) (err error) { +func NewListElement(buf []byte, l uint16, part bool) (element *common.ListElement, err error) { if uint16(len(buf)) != l { - return errors.New("ListElement: buf length not match") + err = errors.New("ListElement: buf length not match") + return } - Self.buf = buf - Self.l = l - Self.part = part - return nil + //if l == 0 { + // logs.Warn("push zero") + //} + element = common.ListElementPool.Get() + element.Buf = buf + element.L = l + element.Part = part + return } type ReceiveWindowQueue struct { - chain *bufChain - length uint32 - stopOp chan struct{} - readOp chan struct{} - popWait uint32 - timeout time.Time + chain *bufChain + stopOp chan struct{} + readOp chan struct{} + lengthWait uint64 + timeout time.Time } func (Self *ReceiveWindowQueue) New() { @@ -151,45 +151,45 @@ func (Self *ReceiveWindowQueue) New() { Self.stopOp = make(chan struct{}, 2) } -func (Self *ReceiveWindowQueue) Push(element *ListElement) { +func (Self *ReceiveWindowQueue) Push(element *common.ListElement) { + var length, wait uint32 + for { + ptrs := atomic.LoadUint64(&Self.lengthWait) + length, wait = Self.chain.head.unpack(ptrs) + length += uint32(element.L) + if atomic.CompareAndSwapUint64(&Self.lengthWait, ptrs, Self.chain.head.pack(length, 0)) { + break + } + // another goroutine change the length or into wait, make sure + } + //logs.Warn("window push before", Self.Len(), uint32(element.l), len(element.buf)) Self.chain.pushHead(unsafe.Pointer(element)) - atomic.AddUint32(&Self.length, uint32(element.l)) - Self.allowPop() - return -} - -func (Self *ReceiveWindowQueue) pop() (element *ListElement) { - ptr, ok := Self.chain.popTail() - if ok { - element = (*ListElement)(ptr) - atomic.AddUint32(&Self.length, ^uint32(element.l-1)) - return + //logs.Warn("window push", Self.Len()) + if wait == 1 { + Self.allowPop() } return } -func (Self *ReceiveWindowQueue) Pop() (element *ListElement, err error) { - var iter bool +func (Self *ReceiveWindowQueue) Pop() (element *common.ListElement, err error) { + var length uint32 startPop: - element = Self.pop() - if element != nil { - return - } - if !iter { - iter = true - runtime.Gosched() - goto startPop - } - if atomic.CompareAndSwapUint32(&Self.popWait, 0, 1) { - iter = false + ptrs := atomic.LoadUint64(&Self.lengthWait) + length, _ = Self.chain.head.unpack(ptrs) + if length == 0 { + if !atomic.CompareAndSwapUint64(&Self.lengthWait, ptrs, Self.chain.head.pack(0, 1)) { + goto startPop // another goroutine is pushing + } t := Self.timeout.Sub(time.Now()) if t <= 0 { t = time.Minute } timer := time.NewTimer(t) defer timer.Stop() + //logs.Warn("queue into wait") select { case <-Self.readOp: + //logs.Warn("queue wait finish") goto startPop case <-Self.stopOp: err = io.EOF @@ -199,23 +199,34 @@ startPop: return } } - goto startPop + // length is not zero, so try to pop + for { + ptr, ok := Self.chain.popTail() + if ok { + //logs.Warn("window pop before", Self.Len()) + element = (*common.ListElement)(ptr) + atomic.AddUint64(&Self.lengthWait, ^(uint64(element.L)< Date: Sat, 9 Nov 2019 23:24:26 +0800 Subject: [PATCH 49/58] version --- lib/version/version.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/version/version.go b/lib/version/version.go index 4cc0532..1f14ef1 100644 --- a/lib/version/version.go +++ b/lib/version/version.go @@ -1,8 +1,8 @@ package version -const VERSION = "0.23.3" +const VERSION = "0.24.0" // Compulsory minimum version, Minimum downward compatibility to this version func GetVersion() string { - return "0.22.0" + return "0.24.0" } From bc1783cfb64c7e882eef7ac84580bb3bc7044971 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Sun, 10 Nov 2019 21:04:35 +0800 Subject: [PATCH 50/58] 64bit alignment, readme --- README.md | 28 ++++++++++++++++++++++++++++ lib/mux/conn.go | 6 +++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f56c32a..4a9ddd4 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务 * [获取用户真实ip](#获取用户真实ip) * [客户端地址显示](#客户端地址显示) * [客户端与服务端版本对比](#客户端与服务端版本对比) + * [Linux系统限制](#Linux系统限制) * [webAPI](#webAPI) * [贡献](#贡献) * [支持nps发展](#捐赠) @@ -144,6 +145,7 @@ nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务 ```shell ./npc -server=1.1.1.1:8284 -vkey=客户端的密钥 ``` +**注意:运行服务端后,请确保能从客户端设备上正常访问配置文件中所配置的`bridge_port`端口,telnet,netcat这类的来检查** ### 域名解析 @@ -441,6 +443,27 @@ server_ip=xxx ``` ./npc -config=npc配置文件路径 ``` +可自行添加systemd service,例如:`npc.service` +``` +[Unit] +Description=npc - convenient proxy server client +Documentation=https://github.com/cnlh/nps/ +After=network-online.target remote-fs.target nss-lookup.target +Wants=network-online.target + +[Service] +Type=simple +KillMode=process +Restart=always +RestartSec=15s +StandardOutput=append:/var/log/nps/npc.log +ExecStartPre=/bin/echo 'Starting npc' +ExecStopPost=/bin/echo 'Stopping npc' +ExecStart=/absolutely path to/npc -server=ip:port -vkey=web界面中显示的密钥 + +[Install] +WantedBy=multi-user.target +``` #### 配置文件说明 [示例配置文件](https://github.com/cnlh/nps/tree/master/conf/npc.conf) ##### 全局配置 @@ -909,6 +932,11 @@ LevelInformational->6 LevelDebug->7 ### 客户端与服务端版本对比 为了程序正常运行,客户端与服务端的核心版本必须一致,否则将导致客户端无法成功连接致服务端。 +### Linux系统限制 +默认情况下linux对连接数量有限制,对于性能好的机器完全可以调整内核参数以处理更多的连接。 +`tcp_max_syn_backlog` `somaxconn` +酌情调整参数,增强网络性能 + ## webAPI ### webAPI验证说明 diff --git a/lib/mux/conn.go b/lib/mux/conn.go index cb982e8..7d2e351 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -144,11 +144,11 @@ func (s *conn) SetWriteDeadline(t time.Time) error { } type window struct { + remainingWait uint64 // 64bit alignment off uint32 maxSize uint32 closeOp bool closeOpCh chan struct{} - remainingWait uint64 mux *Mux } @@ -178,11 +178,11 @@ func (Self *window) CloseWindow() { } type ReceiveWindow struct { + window bufQueue ReceiveWindowQueue element *common.ListElement count int8 once sync.Once - window } func (Self *ReceiveWindow) New(mux *Mux) { @@ -344,10 +344,10 @@ func (Self *ReceiveWindow) CloseWindow() { } type SendWindow struct { + window buf []byte setSizeCh chan struct{} timeout time.Time - window } func (Self *SendWindow) New(mux *Mux) { From 2ca84c912b32e73ddae30916aa191caa973c3a52 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Wed, 13 Nov 2019 23:33:02 +0800 Subject: [PATCH 51/58] fix mux auto disconnect, add mux new connection queue --- lib/mux/conn.go | 8 ++-- lib/mux/mux.go | 81 +++++++++++++++++--------------- lib/mux/queue.go | 119 ++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 149 insertions(+), 59 deletions(-) diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 7d2e351..23bc5d5 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -23,7 +23,7 @@ type conn struct { receiveWindow *ReceiveWindow sendWindow *SendWindow once sync.Once - label string + //label string } func NewConn(connId int32, mux *Mux, label ...string) *conn { @@ -36,9 +36,9 @@ func NewConn(connId int32, mux *Mux, label ...string) *conn { sendWindow: new(SendWindow), once: sync.Once{}, } - if len(label) > 0 { - c.label = label[0] - } + //if len(label) > 0 { + // c.label = label[0] + //} c.receiveWindow.New(mux) c.sendWindow.New(mux) //logm := &connLog{ diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 585c980..b64243f 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -14,21 +14,20 @@ import ( type Mux struct { net.Listener - conn net.Conn - connMap *connMap - newConnCh chan *conn - id int32 - closeChan chan struct{} - IsClose bool - pingOk int - latency float64 - bw *bandwidth - pingCh chan []byte - pingTimer *time.Timer - connType string - writeQueue PriorityQueue - //bufQueue BytesQueue - //sync.Mutex + conn net.Conn + connMap *connMap + newConnCh chan *conn + id int32 + closeChan chan struct{} + IsClose bool + pingOk int + latency float64 + bw *bandwidth + pingCh chan []byte + pingCheck bool + connType string + writeQueue PriorityQueue + newConnQueue ConnQueue } func NewMux(c net.Conn, connType string) *Mux { @@ -39,15 +38,14 @@ func NewMux(c net.Conn, connType string) *Mux { connMap: NewConnMap(), id: 0, closeChan: make(chan struct{}, 1), - newConnCh: make(chan *conn, 10), + newConnCh: make(chan *conn), bw: new(bandwidth), IsClose: false, connType: connType, pingCh: make(chan []byte), - pingTimer: time.NewTimer(15 * time.Second), } m.writeQueue.New() - //m.bufQueue.New() + m.newConnQueue.New() //read session by flag m.readSession() //ping @@ -101,6 +99,8 @@ func (s *Mux) sendInfo(flag uint8, id int32, data ...interface{}) { err = pack.NewPac(flag, id, data...) if err != nil { common.MuxPack.Put(pack) + logs.Error("mux: new pack err") + s.Close() return } s.writeQueue.Push(pack) @@ -124,7 +124,7 @@ func (s *Mux) packBuf() { err := pack.Pack(buffer) common.MuxPack.Put(pack) if err != nil { - logs.Warn("pack err", err) + logs.Error("mux: pack err", err) common.BuffPool.Put(buffer) break } @@ -134,7 +134,7 @@ func (s *Mux) packBuf() { n, err := buffer.WriteTo(s.conn) //common.BuffPool.Put(buffer) if err != nil || int(n) != l { - logs.Warn("close from write session fail ", err, n, l) + logs.Error("mux: close from write session fail ", err, n, l) s.Close() break } @@ -170,21 +170,23 @@ func (s *Mux) ping() { for { if s.IsClose { ticker.Stop() - if !s.pingTimer.Stop() { - <-s.pingTimer.C - } break } select { case <-ticker.C: } + if s.pingCheck { + logs.Error("mux: ping time out") + s.Close() + // more than 5 seconds not receive the ping return package, + // mux conn is damaged, maybe a packet drop, close it + break + } now, _ := time.Now().UTC().MarshalText() s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, now) - if !s.pingTimer.Stop() { - <-s.pingTimer.C - } - s.pingTimer.Reset(15 * time.Second) + s.pingCheck = true if s.pingOk > 10 && s.connType == "kcp" { + logs.Error("mux: kcp ping err") s.Close() break } @@ -203,12 +205,9 @@ func (s *Mux) pingReturn() { } select { case data = <-s.pingCh: + s.pingCheck = false case <-s.closeChan: break - case <-s.pingTimer.C: - logs.Error("mux: ping time out") - s.Close() - break } _ = now.UnmarshalText(data) latency := time.Now().UTC().Sub(now).Seconds() / 2 @@ -222,6 +221,15 @@ func (s *Mux) pingReturn() { } func (s *Mux) readSession() { + go func() { + var connection *conn + for { + connection = s.newConnQueue.Pop() + s.connMap.Set(connection.connId, connection) //it has been set before send ok + s.newConnCh <- connection + s.sendInfo(common.MUX_NEW_CONN_OK, connection.connId, nil) + } + }() go func() { pack := common.MuxPack.Get() var l uint16 @@ -233,18 +241,16 @@ func (s *Mux) readSession() { pack = common.MuxPack.Get() s.bw.StartRead() if l, err = pack.UnPack(s.conn); err != nil { + logs.Error("mux: read session unpack from connection err") + s.Close() break } s.bw.SetCopySize(l) s.pingOk = 0 switch pack.Flag { case common.MUX_NEW_CONN: //new connection - connection := NewConn(pack.Id, s, "npc ") - s.connMap.Set(pack.Id, connection) //it has been set before send ok - //go func(connection *conn) { - s.newConnCh <- connection - s.sendInfo(common.MUX_NEW_CONN_OK, connection.connId, nil) - //}(connection) + connection := NewConn(pack.Id, s) + s.newConnQueue.Push(connection) continue case common.MUX_PING_FLAG: //ping s.sendInfo(common.MUX_PING_RETURN, common.MUX_PING, pack.Content) @@ -261,6 +267,7 @@ func (s *Mux) readSession() { case common.MUX_NEW_MSG, common.MUX_NEW_MSG_PART: //new msg from remote connection err = s.newMsg(connection, pack) if err != nil { + logs.Error("mux: read session connection new msg err") connection.Close() } continue diff --git a/lib/mux/queue.go b/lib/mux/queue.go index 4790779..0bfea18 100644 --- a/lib/mux/queue.go +++ b/lib/mux/queue.go @@ -33,6 +33,14 @@ func (Self *PriorityQueue) New() { } func (Self *PriorityQueue) Push(packager *common.MuxPackager) { + //logs.Warn("push start") + Self.push(packager) + Self.cond.Broadcast() + //logs.Warn("push finish") + return +} + +func (Self *PriorityQueue) push(packager *common.MuxPackager) { switch packager.Flag { case common.MUX_PING_FLAG, common.MUX_PING_RETURN: Self.highestChain.pushHead(unsafe.Pointer(packager)) @@ -44,8 +52,6 @@ func (Self *PriorityQueue) Push(packager *common.MuxPackager) { default: Self.lowestChain.pushHead(unsafe.Pointer(packager)) } - Self.cond.Signal() - return } const maxStarving uint8 = 8 @@ -121,6 +127,72 @@ func (Self *PriorityQueue) Stop() { Self.cond.Broadcast() } +type ConnQueue struct { + chain *bufChain + starving uint8 + stop bool + cond *sync.Cond +} + +func (Self *ConnQueue) New() { + Self.chain = new(bufChain) + Self.chain.new(32) + locker := new(sync.Mutex) + Self.cond = sync.NewCond(locker) +} + +func (Self *ConnQueue) Push(connection *conn) { + Self.chain.pushHead(unsafe.Pointer(connection)) + Self.cond.Broadcast() + return +} + +func (Self *ConnQueue) Pop() (connection *conn) { + var iter bool + for { + connection = Self.pop() + if connection != nil { + return + } + if Self.stop { + return + } + if iter { + break + // trying to pop twice + } + iter = true + runtime.Gosched() + } + Self.cond.L.Lock() + defer Self.cond.L.Unlock() + for connection = Self.pop(); connection == nil; { + if Self.stop { + return + } + //logs.Warn("queue into wait") + Self.cond.Wait() + // wait for it with no more iter + connection = Self.pop() + //logs.Warn("queue wait finish", packager) + } + return +} + +func (Self *ConnQueue) pop() (connection *conn) { + ptr, ok := Self.chain.popTail() + if ok { + connection = (*conn)(ptr) + return + } + return +} + +func (Self *ConnQueue) Stop() { + Self.stop = true + Self.cond.Broadcast() +} + func NewListElement(buf []byte, l uint16, part bool) (element *common.ListElement, err error) { if uint16(len(buf)) != l { err = errors.New("ListElement: buf length not match") @@ -180,24 +252,12 @@ startPop: if !atomic.CompareAndSwapUint64(&Self.lengthWait, ptrs, Self.chain.head.pack(0, 1)) { goto startPop // another goroutine is pushing } - t := Self.timeout.Sub(time.Now()) - if t <= 0 { - t = time.Minute - } - timer := time.NewTimer(t) - defer timer.Stop() - //logs.Warn("queue into wait") - select { - case <-Self.readOp: - //logs.Warn("queue wait finish") - goto startPop - case <-Self.stopOp: - err = io.EOF - return - case <-timer.C: - err = errors.New("mux.queue: read time out") + err = Self.waitPush() + // there is no more data in queue, wait for it + if err != nil { return } + goto startPop // wait finish, trying to get the new status } // length is not zero, so try to pop for { @@ -223,6 +283,29 @@ func (Self *ReceiveWindowQueue) allowPop() (closed bool) { } } +func (Self *ReceiveWindowQueue) waitPush() (err error) { + //logs.Warn("wait push") + //defer logs.Warn("wait push finish") + t := Self.timeout.Sub(time.Now()) + if t <= 0 { + t = time.Second * 10 + } + timer := time.NewTimer(t) + defer timer.Stop() + //logs.Warn("queue into wait") + select { + case <-Self.readOp: + //logs.Warn("queue wait finish") + return nil + case <-Self.stopOp: + err = io.EOF + return + case <-timer.C: + err = errors.New("mux.queue: read time out") + return + } +} + func (Self *ReceiveWindowQueue) Len() (n uint32) { ptrs := atomic.LoadUint64(&Self.lengthWait) n, _ = Self.chain.head.unpack(ptrs) From aaf79b21f03f04309b1bc10580e4943f2b6b32a0 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Tue, 19 Nov 2019 23:43:52 +0800 Subject: [PATCH 52/58] fine mux connection ping calculation, increase connection waiting time --- README.md | 13 +++++ lib/mux/conn.go | 6 ++- lib/mux/mux.go | 130 +++++++++++++++++++++++++++++++++++++++-------- lib/mux/queue.go | 2 +- 4 files changed, 127 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 4a9ddd4..8988d5a 100644 --- a/README.md +++ b/README.md @@ -824,6 +824,19 @@ nps支持对客户端的隧道数量进行限制,该功能默认是关闭的 nps主要通信默认基于多路复用,无需开启。 +多路复用基于TCP滑动窗口原理设计,动态计算延迟以及带宽来算出应该往网络管道中打入的流量。 +由于主要通信大多采用TCP协议,并无法探测其实时丢包情况,对于产生丢包重传的情况,采用较大的宽容度, +5分钟的等待时间,超时将会关闭当前隧道连接并重新建立,这将会抛弃当前所有的连接。 +在Linux上,可以通过调节内核参数来适应不同应用场景。 + +对于需求大带宽又有一定的丢包的场景,可以保持默认参数不变,尽可能少抛弃连接 +高并发下可根据[Linux系统限制](#Linux系统限制) 调整 + +对于延迟敏感而又有一定丢包的场景,可以适当调整TCP重传次数 +`tcp_syn_retries`, `tcp_retries1`, `tcp_retries2` +高并发同上 +nps会在系统主动关闭连接的时候拿到报错,进而重新建立隧道连接 + ### 环境变量渲染 npc支持环境变量渲染以适应在某些特殊场景下的要求。 diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 23bc5d5..7bb88ae 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -3,6 +3,7 @@ package mux import ( "errors" "io" + "math" "net" "runtime" "sync" @@ -208,7 +209,8 @@ func (Self *ReceiveWindow) calcSize() { // calculating maximum receive window size if Self.count == 0 { //logs.Warn("ping, bw", Self.mux.latency, Self.bw.Get()) - n := uint32(2 * Self.mux.latency * Self.mux.bw.Get() * 1.5 / float64(Self.mux.connMap.Size())) + n := uint32(2 * math.Float64frombits(atomic.LoadUint64(&Self.mux.latency)) * + Self.mux.bw.Get() * 1.5 / float64(Self.mux.connMap.Size())) if n < 8192 { n = 8192 } @@ -471,7 +473,7 @@ start: func (Self *SendWindow) waitReceiveWindow() (err error) { t := Self.timeout.Sub(time.Now()) if t < 0 { - t = time.Minute + t = time.Minute * 5 } timer := time.NewTimer(t) defer timer.Stop() diff --git a/lib/mux/mux.go b/lib/mux/mux.go index b64243f..3872f7e 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -13,21 +13,22 @@ import ( ) type Mux struct { + latency uint64 // we store latency in bits, but it's float64 net.Listener - conn net.Conn - connMap *connMap - newConnCh chan *conn - id int32 - closeChan chan struct{} - IsClose bool - pingOk int - latency float64 - bw *bandwidth - pingCh chan []byte - pingCheck bool - connType string - writeQueue PriorityQueue - newConnQueue ConnQueue + conn net.Conn + connMap *connMap + newConnCh chan *conn + id int32 + closeChan chan struct{} + IsClose bool + pingOk int + counter *latencyCounter + bw *bandwidth + pingCh chan []byte + pingCheckTime uint32 + connType string + writeQueue PriorityQueue + newConnQueue ConnQueue } func NewMux(c net.Conn, connType string) *Mux { @@ -43,6 +44,7 @@ func NewMux(c net.Conn, connType string) *Mux { IsClose: false, connType: connType, pingCh: make(chan []byte), + counter: newLatencyCounter(), } m.writeQueue.New() m.newConnQueue.New() @@ -175,16 +177,16 @@ func (s *Mux) ping() { select { case <-ticker.C: } - if s.pingCheck { + if atomic.LoadUint32(&s.pingCheckTime) >= 60 { logs.Error("mux: ping time out") s.Close() - // more than 5 seconds not receive the ping return package, + // more than 5 minutes not receive the ping return package, // mux conn is damaged, maybe a packet drop, close it break } now, _ := time.Now().UTC().MarshalText() s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, now) - s.pingCheck = true + atomic.AddUint32(&s.pingCheckTime, 1) if s.pingOk > 10 && s.connType == "kcp" { logs.Error("mux: kcp ping err") s.Close() @@ -205,16 +207,17 @@ func (s *Mux) pingReturn() { } select { case data = <-s.pingCh: - s.pingCheck = false + atomic.StoreUint32(&s.pingCheckTime, 0) case <-s.closeChan: break } _ = now.UnmarshalText(data) latency := time.Now().UTC().Sub(now).Seconds() / 2 - if latency < 0.5 && latency > 0 { - s.latency = latency + if latency > 0 { + atomic.StoreUint64(&s.latency, math.Float64bits(s.counter.Latency(latency))) + // convert float64 to bits, store it atomic } - //logs.Warn("latency", s.latency) + //logs.Warn("latency", math.Float64frombits(atomic.LoadUint64(&s.latency))) common.WindowBuff.Put(data) } }() @@ -379,3 +382,88 @@ func (Self *bandwidth) Get() (bw float64) { } return Self.readBandwidth } + +const counterBits = 4 +const counterMask = 1<> counterBits) & counterMask) + // we set head is 4 bits + min = uint8(idxs & counterMask) + return +} + +func (Self *latencyCounter) pack(head, min uint8) uint8 { + return uint8(head< value { + min = head + } + head++ + Self.headMin = Self.pack(head, min) +} + +func (Self *latencyCounter) minimal() (min uint8) { + var val float64 + var i uint8 + for i = 0; i < counterMask; i++ { + if Self.buf[i] > 0 { + if val > Self.buf[i] { + val = Self.buf[i] + min = i + } + } + } + return +} + +func (Self *latencyCounter) Latency(value float64) (latency float64) { + Self.add(value) + _, min := Self.unpack(Self.headMin) + latency = Self.buf[min] * Self.countSuccess() + return +} + +const lossRatio = 1.6 + +func (Self *latencyCounter) countSuccess() (successRate float64) { + var success, loss, i uint8 + _, min := Self.unpack(Self.headMin) + for i = 0; i < counterMask; i++ { + if Self.buf[i] > lossRatio*Self.buf[min] && Self.buf[i] > 0 { + loss++ + } + if Self.buf[i] <= lossRatio*Self.buf[min] && Self.buf[i] > 0 { + success++ + } + } + // counting all the data in the ring buf, except zero + successRate = float64(success) / float64(loss+success) + return +} diff --git a/lib/mux/queue.go b/lib/mux/queue.go index 0bfea18..2fe8a44 100644 --- a/lib/mux/queue.go +++ b/lib/mux/queue.go @@ -288,7 +288,7 @@ func (Self *ReceiveWindowQueue) waitPush() (err error) { //defer logs.Warn("wait push finish") t := Self.timeout.Sub(time.Now()) if t <= 0 { - t = time.Second * 10 + t = time.Minute * 5 } timer := time.NewTimer(t) defer timer.Stop() From bfe08e5114e320fef84d67a6382a358f8254fe1f Mon Sep 17 00:00:00 2001 From: zhangzc <50092028+43280398@users.noreply.github.com> Date: Wed, 20 Nov 2019 11:47:55 +0800 Subject: [PATCH 53/58] Update util.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修改nginx代理转发后无法获取真实ip --- lib/common/util.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/common/util.go b/lib/common/util.go index 1f54a6f..9a60846 100755 --- a/lib/common/util.go +++ b/lib/common/util.go @@ -108,6 +108,9 @@ func ChangeHostAndHeader(r *http.Request, host string, header string, addr strin } } addr = strings.Split(addr, ":")[0] + if prior, ok := r.Header["X-Forwarded-For"]; ok { + addr = strings.Join(prior, ", ") + ", " + addr + } r.Header.Set("X-Forwarded-For", addr) r.Header.Set("X-Real-IP", addr) } From 9bb8230fc17e59101d397c16aef4562a481020a8 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Thu, 21 Nov 2019 23:53:06 +0800 Subject: [PATCH 54/58] fix several race condition, change slide window max size 2G to 32M, add buffer release --- lib/common/const.go | 3 ++- lib/mux/conn.go | 25 +++++++++++++++++- lib/mux/map.go | 63 +++++++++++++++++++++++---------------------- lib/mux/mux.go | 57 +++++++++++++++++++++++++++++++++------- lib/mux/queue.go | 40 ++++++++++++++++------------ 5 files changed, 129 insertions(+), 59 deletions(-) diff --git a/lib/common/const.go b/lib/common/const.go index f57ce4f..2fd5bb6 100644 --- a/lib/common/const.go +++ b/lib/common/const.go @@ -49,5 +49,6 @@ const ( MUX_PING_RETURN MUX_PING int32 = -1 MAXIMUM_SEGMENT_SIZE = PoolSizeWindow - MAXIMUM_WINDOW_SIZE = 1<<31 - 1 + MAXIMUM_WINDOW_SIZE = 1 << 25 // 1<<31-1 TCP slide window size is very large, + // we use 32M, reduce memory usage ) diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 7bb88ae..c94ab4d 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -210,7 +210,7 @@ func (Self *ReceiveWindow) calcSize() { if Self.count == 0 { //logs.Warn("ping, bw", Self.mux.latency, Self.bw.Get()) n := uint32(2 * math.Float64frombits(atomic.LoadUint64(&Self.mux.latency)) * - Self.mux.bw.Get() * 1.5 / float64(Self.mux.connMap.Size())) + Self.mux.bw.Get() / float64(Self.mux.connMap.Size())) if n < 8192 { n = 8192 } @@ -279,6 +279,9 @@ copyData: // on the first Read method invoked, Self.off and Self.element.l // both zero value common.ListElementPool.Put(Self.element) + if Self.closeOp { + return 0, io.EOF + } Self.element, err = Self.bufQueue.Pop() // if the queue is empty, Pop method will wait until one element push // into the queue successful, or timeout. @@ -343,6 +346,26 @@ func (Self *ReceiveWindow) Stop() { func (Self *ReceiveWindow) CloseWindow() { Self.window.CloseWindow() Self.Stop() + Self.release() +} + +func (Self *ReceiveWindow) release() { + //if Self.element != nil { + // if Self.element.Buf != nil { + // common.WindowBuff.Put(Self.element.Buf) + // } + // common.ListElementPool.Put(Self.element) + //} + for { + Self.element = Self.bufQueue.TryPop() + if Self.element == nil { + return + } + if Self.element.Buf != nil { + common.WindowBuff.Put(Self.element.Buf) + } + common.ListElementPool.Put(Self.element) + } // release resource } type SendWindow struct { diff --git a/lib/mux/map.go b/lib/mux/map.go index 8f07dee..86d09b5 100644 --- a/lib/mux/map.go +++ b/lib/mux/map.go @@ -2,32 +2,35 @@ package mux import ( "sync" - "time" ) type connMap struct { connMap map[int32]*conn - closeCh chan struct{} + //closeCh chan struct{} sync.RWMutex } func NewConnMap() *connMap { connMap := &connMap{ connMap: make(map[int32]*conn), - closeCh: make(chan struct{}), + //closeCh: make(chan struct{}), } - go connMap.clean() + //go connMap.clean() return connMap } func (s *connMap) Size() (n int) { - return len(s.connMap) + s.Lock() + n = len(s.connMap) + s.Unlock() + return } func (s *connMap) Get(id int32) (*conn, bool) { s.Lock() - defer s.Unlock() - if v, ok := s.connMap[id]; ok && v != nil { + v, ok := s.connMap[id] + s.Unlock() + if ok && v != nil { return v, true } return nil, false @@ -35,40 +38,38 @@ func (s *connMap) Get(id int32) (*conn, bool) { func (s *connMap) Set(id int32, v *conn) { s.Lock() - defer s.Unlock() s.connMap[id] = v + s.Unlock() } func (s *connMap) Close() { - s.Lock() - defer s.Unlock() + //s.closeCh <- struct{}{} // stop the clean goroutine first for _, v := range s.connMap { - v.isClose = true + v.Close() // close all the connections in the mux } - s.closeCh <- struct{}{} } func (s *connMap) Delete(id int32) { s.Lock() - defer s.Unlock() delete(s.connMap, id) + s.Unlock() } -func (s *connMap) clean() { - ticker := time.NewTimer(time.Minute * 1) - for { - select { - case <-ticker.C: - s.Lock() - for _, v := range s.connMap { - if v.isClose { - delete(s.connMap, v.connId) - } - } - s.Unlock() - case <-s.closeCh: - ticker.Stop() - return - } - } -} +//func (s *connMap) clean() { +// ticker := time.NewTimer(time.Minute * 1) +// for { +// select { +// case <-ticker.C: +// s.Lock() +// for _, v := range s.connMap { +// if v.isClose { +// delete(s.connMap, v.connId) +// } +// } +// s.Unlock() +// case <-s.closeCh: +// ticker.Stop() +// return +// } +// } +//} diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 3872f7e..8c4febb 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -122,6 +122,9 @@ func (s *Mux) packBuf() { } buffer.Reset() pack := s.writeQueue.Pop() + if s.IsClose { + break + } //buffer := common.BuffPool.Get() err := pack.Pack(buffer) common.MuxPack.Put(pack) @@ -218,7 +221,9 @@ func (s *Mux) pingReturn() { // convert float64 to bits, store it atomic } //logs.Warn("latency", math.Float64frombits(atomic.LoadUint64(&s.latency))) - common.WindowBuff.Put(data) + if cap(data) > 0 { + common.WindowBuff.Put(data) + } } }() } @@ -227,7 +232,13 @@ func (s *Mux) readSession() { go func() { var connection *conn for { + if s.IsClose { + break + } connection = s.newConnQueue.Pop() + if s.IsClose { + break // make sure that is closed + } s.connMap.Set(connection.connId, connection) //it has been set before send ok s.newConnCh <- connection s.sendInfo(common.MUX_NEW_CONN_OK, connection.connId, nil) @@ -287,9 +298,9 @@ func (s *Mux) readSession() { connection.sendWindow.SetSize(pack.Window, pack.ReadLength) continue case common.MUX_CONN_CLOSE: //close the connection - s.connMap.Delete(pack.Id) - //go func(connection *conn) { connection.closeFlag = true + //s.connMap.Delete(pack.Id) + //go func(connection *conn) { connection.receiveWindow.Stop() // close signal to receive window //}(connection) continue @@ -322,17 +333,42 @@ func (s *Mux) newMsg(connection *conn, pack *common.MuxPackager) (err error) { return } -func (s *Mux) Close() error { +func (s *Mux) Close() (err error) { logs.Warn("close mux") if s.IsClose { return errors.New("the mux has closed") } s.IsClose = true s.connMap.Close() + s.connMap = nil //s.bufQueue.Stop() s.closeChan <- struct{}{} close(s.newConnCh) - return s.conn.Close() + err = s.conn.Close() + s.release() + return +} + +func (s *Mux) release() { + for { + pack := s.writeQueue.TryPop() + if pack == nil { + break + } + if pack.BasePackager.Content != nil { + common.WindowBuff.Put(pack.BasePackager.Content) + } + common.MuxPack.Put(pack) + } + for { + connection := s.newConnQueue.TryPop() + if connection == nil { + break + } + connection = nil + } + s.writeQueue.Stop() + s.newConnQueue.Stop() } //get new connId as unique flag @@ -352,7 +388,7 @@ type bandwidth struct { readStart time.Time lastReadStart time.Time bufLength uint16 - readBandwidth float64 + readBandwidth uint64 // store in bits, but it's float64 } func (Self *bandwidth) StartRead() { @@ -371,16 +407,17 @@ func (Self *bandwidth) SetCopySize(n uint16) { func (Self *bandwidth) calcBandWidth() { t := Self.readStart.Sub(Self.lastReadStart) - Self.readBandwidth = float64(Self.bufLength) / t.Seconds() + atomic.StoreUint64(&Self.readBandwidth, math.Float64bits(float64(Self.bufLength)/t.Seconds())) Self.bufLength = 0 } func (Self *bandwidth) Get() (bw float64) { // The zero value, 0 for numeric types - if Self.readBandwidth <= 0 { - Self.readBandwidth = 100 + bw = math.Float64frombits(atomic.LoadUint64(&Self.readBandwidth)) + if bw <= 0 { + bw = 100 } - return Self.readBandwidth + return } const counterBits = 4 diff --git a/lib/mux/queue.go b/lib/mux/queue.go index 2fe8a44..2288e40 100644 --- a/lib/mux/queue.go +++ b/lib/mux/queue.go @@ -59,7 +59,7 @@ const maxStarving uint8 = 8 func (Self *PriorityQueue) Pop() (packager *common.MuxPackager) { var iter bool for { - packager = Self.pop() + packager = Self.TryPop() if packager != nil { return } @@ -75,20 +75,20 @@ func (Self *PriorityQueue) Pop() (packager *common.MuxPackager) { } Self.cond.L.Lock() defer Self.cond.L.Unlock() - for packager = Self.pop(); packager == nil; { + for packager = Self.TryPop(); packager == nil; { if Self.stop { return } //logs.Warn("queue into wait") Self.cond.Wait() // wait for it with no more iter - packager = Self.pop() + packager = Self.TryPop() //logs.Warn("queue wait finish", packager) } return } -func (Self *PriorityQueue) pop() (packager *common.MuxPackager) { +func (Self *PriorityQueue) TryPop() (packager *common.MuxPackager) { ptr, ok := Self.highestChain.popTail() if ok { packager = (*common.MuxPackager)(ptr) @@ -150,7 +150,7 @@ func (Self *ConnQueue) Push(connection *conn) { func (Self *ConnQueue) Pop() (connection *conn) { var iter bool for { - connection = Self.pop() + connection = Self.TryPop() if connection != nil { return } @@ -166,20 +166,20 @@ func (Self *ConnQueue) Pop() (connection *conn) { } Self.cond.L.Lock() defer Self.cond.L.Unlock() - for connection = Self.pop(); connection == nil; { + for connection = Self.TryPop(); connection == nil; { if Self.stop { return } //logs.Warn("queue into wait") Self.cond.Wait() // wait for it with no more iter - connection = Self.pop() + connection = Self.TryPop() //logs.Warn("queue wait finish", packager) } return } -func (Self *ConnQueue) pop() (connection *conn) { +func (Self *ConnQueue) TryPop() (connection *conn) { ptr, ok := Self.chain.popTail() if ok { connection = (*conn)(ptr) @@ -261,18 +261,26 @@ startPop: } // length is not zero, so try to pop for { - ptr, ok := Self.chain.popTail() - if ok { - //logs.Warn("window pop before", Self.Len()) - element = (*common.ListElement)(ptr) - atomic.AddUint64(&Self.lengthWait, ^(uint64(element.L)< Date: Sat, 23 Nov 2019 00:42:46 +0800 Subject: [PATCH 55/58] change some bandwidth calculation --- lib/common/pool.go | 2 +- lib/mux/conn.go | 22 +++++++++++++--------- lib/mux/mux.go | 32 +++++++++++++++++--------------- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/lib/common/pool.go b/lib/common/pool.go index 5d4da00..1f7a47e 100644 --- a/lib/common/pool.go +++ b/lib/common/pool.go @@ -10,7 +10,7 @@ const PoolSizeSmall = 100 const PoolSizeUdp = 1472 const PoolSizeCopy = 32 << 10 const PoolSizeBuffer = 4096 -const PoolSizeWindow = PoolSizeBuffer - 16 - 32 - 32 - 8 +const PoolSizeWindow = PoolSizeBuffer - 2 - 4 - 4 - 1 var BufPool = sync.Pool{ New: func() interface{} { diff --git a/lib/mux/conn.go b/lib/mux/conn.go index c94ab4d..1b7a920 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -190,7 +190,7 @@ func (Self *ReceiveWindow) New(mux *Mux) { // initial a window for receive Self.bufQueue.New() Self.element = common.ListElementPool.Get() - Self.maxSize = 4096 + Self.maxSize = common.MAXIMUM_SEGMENT_SIZE Self.mux = mux Self.window.New() } @@ -209,21 +209,25 @@ func (Self *ReceiveWindow) calcSize() { // calculating maximum receive window size if Self.count == 0 { //logs.Warn("ping, bw", Self.mux.latency, Self.bw.Get()) - n := uint32(2 * math.Float64frombits(atomic.LoadUint64(&Self.mux.latency)) * - Self.mux.bw.Get() / float64(Self.mux.connMap.Size())) - if n < 8192 { - n = 8192 + conns := Self.mux.connMap.Size() + n := uint32(math.Float64frombits(atomic.LoadUint64(&Self.mux.latency)) * + Self.mux.bw.Get() / float64(conns)) + if n < common.MAXIMUM_SEGMENT_SIZE*2 { + n = common.MAXIMUM_SEGMENT_SIZE * 2 } bufLen := Self.bufQueue.Len() if n < bufLen { n = bufLen } + if n < Self.maxSize/2 { + n = Self.maxSize / 2 + } // set the minimal size if n > 2*Self.maxSize { n = 2 * Self.maxSize } - if n > common.MAXIMUM_WINDOW_SIZE { - n = common.MAXIMUM_WINDOW_SIZE + if n > (common.MAXIMUM_WINDOW_SIZE / uint32(conns)) { + n = common.MAXIMUM_WINDOW_SIZE / uint32(conns) } // set the maximum size //logs.Warn("n", n) @@ -377,8 +381,8 @@ type SendWindow struct { func (Self *SendWindow) New(mux *Mux) { Self.setSizeCh = make(chan struct{}) - Self.maxSize = 4096 - atomic.AddUint64(&Self.remainingWait, uint64(4096)<= 16384 { + if Self.bufLength >= 3072000 { Self.lastReadStart, Self.readStart = Self.readStart, time.Now() Self.calcBandWidth() } } func (Self *bandwidth) SetCopySize(n uint16) { - Self.bufLength += n + Self.bufLength += uint32(n) } func (Self *bandwidth) calcBandWidth() { @@ -417,6 +418,7 @@ func (Self *bandwidth) Get() (bw float64) { if bw <= 0 { bw = 100 } + //logs.Warn(bw) return } From 32e3d411ad1d5287433e43becb9827e07324fcb9 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Sun, 24 Nov 2019 21:19:25 +0800 Subject: [PATCH 56/58] change initial window size --- lib/mux/conn.go | 10 +++++----- lib/mux/mux.go | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/mux/conn.go b/lib/mux/conn.go index 1b7a920..f665248 100644 --- a/lib/mux/conn.go +++ b/lib/mux/conn.go @@ -190,7 +190,7 @@ func (Self *ReceiveWindow) New(mux *Mux) { // initial a window for receive Self.bufQueue.New() Self.element = common.ListElementPool.Get() - Self.maxSize = common.MAXIMUM_SEGMENT_SIZE + Self.maxSize = common.MAXIMUM_SEGMENT_SIZE * 10 Self.mux = mux Self.window.New() } @@ -212,8 +212,8 @@ func (Self *ReceiveWindow) calcSize() { conns := Self.mux.connMap.Size() n := uint32(math.Float64frombits(atomic.LoadUint64(&Self.mux.latency)) * Self.mux.bw.Get() / float64(conns)) - if n < common.MAXIMUM_SEGMENT_SIZE*2 { - n = common.MAXIMUM_SEGMENT_SIZE * 2 + if n < common.MAXIMUM_SEGMENT_SIZE*10 { + n = common.MAXIMUM_SEGMENT_SIZE * 10 } bufLen := Self.bufQueue.Len() if n < bufLen { @@ -381,8 +381,8 @@ type SendWindow struct { func (Self *SendWindow) New(mux *Mux) { Self.setSizeCh = make(chan struct{}) - Self.maxSize = common.MAXIMUM_SEGMENT_SIZE - atomic.AddUint64(&Self.remainingWait, uint64(common.MAXIMUM_SEGMENT_SIZE)<= 3072000 { + if Self.bufLength >= common.MAXIMUM_SEGMENT_SIZE*300 { Self.lastReadStart, Self.readStart = Self.readStart, time.Now() Self.calcBandWidth() } From 78ebeba1bbd47ebf1f6cce7985d38b8e1041c5f9 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Wed, 27 Nov 2019 22:46:34 +0800 Subject: [PATCH 57/58] minor bug fix, docker --- Dockerfile.npc | 10 ++++++++++ Dockerfile.nps | 11 +++++++++++ README.md | 7 ++++++- lib/conn/listener.go | 7 +++++++ lib/mux/mux.go | 14 +++++++------- lib/mux/queue.go | 2 +- 6 files changed, 42 insertions(+), 9 deletions(-) create mode 100755 Dockerfile.npc create mode 100755 Dockerfile.nps diff --git a/Dockerfile.npc b/Dockerfile.npc new file mode 100755 index 0000000..ae6715a --- /dev/null +++ b/Dockerfile.npc @@ -0,0 +1,10 @@ +FROM golang as builder +WORKDIR /go/src/github.com/cnlh/nps +COPY . . +RUN go get -d -v ./... +RUN CGO_ENABLED=0 go build -ldflags="-w -s -extldflags -static" ./cmd/npc/npc.go + +FROM scratch +COPY --from=builder /go/src/github.com/cnlh/nps/npc / +VOLUME /conf +ENTRYPOINT ["/npc"] diff --git a/Dockerfile.nps b/Dockerfile.nps new file mode 100755 index 0000000..698ced9 --- /dev/null +++ b/Dockerfile.nps @@ -0,0 +1,11 @@ +FROM golang as builder +WORKDIR /go/src/github.com/cnlh/nps +COPY . . +RUN go get -d -v ./... +RUN CGO_ENABLED=0 go build -ldflags="-w -s -extldflags -static" ./cmd/nps/nps.go + +FROM scratch +COPY --from=builder /go/src/github.com/cnlh/nps/nps / +COPY --from=builder /go/src/github.com/cnlh/nps/web /web +VOLUME /conf +CMD ["/nps"] diff --git a/README.md b/README.md index 8988d5a..ba93cb5 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务 * [安装](#安装) * [编译安装](#源码安装) * [release安装](#release安装) + * [docker安装](#docker安装) * [使用示例(以web主控模式为主)](#使用示例) * [统一准备工作](#统一准备工作(必做)) * [http|https域名解析](#域名解析) @@ -121,7 +122,7 @@ nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务 ## 安装 -### releases安装 +### release安装 > [releases](https://github.com/cnlh/nps/releases) 下载对应的系统版本即可,服务端和客户端是单独的 @@ -134,6 +135,10 @@ nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务 > go build cmd/npc/npc.go +### docker安装 +> [server](https://hub.docker.com/r/ffdfgdfg/nps) +> [client](https://hub.docker.com/r/ffdfgdfg/npc) + ## 使用示例 ### 统一准备工作(必做) diff --git a/lib/conn/listener.go b/lib/conn/listener.go index f80e01d..bd8e443 100644 --- a/lib/conn/listener.go +++ b/lib/conn/listener.go @@ -43,9 +43,16 @@ func Accept(l net.Listener, f func(c net.Conn)) { if strings.Contains(err.Error(), "use of closed network connection") { break } + if strings.Contains(err.Error(), "the mux has closed") { + break + } logs.Warn(err) continue } + if c == nil { + logs.Warn("nil connection") + break + } go f(c) } } diff --git a/lib/mux/mux.go b/lib/mux/mux.go index 6c9c7fd..a43510a 100644 --- a/lib/mux/mux.go +++ b/lib/mux/mux.go @@ -21,7 +21,7 @@ type Mux struct { id int32 closeChan chan struct{} IsClose bool - pingOk int + pingOk uint32 counter *latencyCounter bw *bandwidth pingCh chan []byte @@ -101,7 +101,7 @@ func (s *Mux) sendInfo(flag uint8, id int32, data ...interface{}) { err = pack.NewPac(flag, id, data...) if err != nil { common.MuxPack.Put(pack) - logs.Error("mux: new pack err") + logs.Error("mux: new pack err", err) s.Close() return } @@ -191,12 +191,12 @@ func (s *Mux) ping() { now, _ := time.Now().UTC().MarshalText() s.sendInfo(common.MUX_PING_FLAG, common.MUX_PING, now) atomic.AddUint32(&s.pingCheckTime, 1) - if s.pingOk > 10 && s.connType == "kcp" { + if atomic.LoadUint32(&s.pingOk) > 10 && s.connType == "kcp" { logs.Error("mux: kcp ping err") s.Close() break } - s.pingOk++ + atomic.AddUint32(&s.pingOk, 1) } }() } @@ -256,12 +256,12 @@ func (s *Mux) readSession() { pack = common.MuxPack.Get() s.bw.StartRead() if l, err = pack.UnPack(s.conn); err != nil { - logs.Error("mux: read session unpack from connection err") + logs.Error("mux: read session unpack from connection err", err) s.Close() break } s.bw.SetCopySize(l) - s.pingOk = 0 + atomic.StoreUint32(&s.pingOk, 0) switch pack.Flag { case common.MUX_NEW_CONN: //new connection connection := NewConn(pack.Id, s) @@ -282,7 +282,7 @@ func (s *Mux) readSession() { case common.MUX_NEW_MSG, common.MUX_NEW_MSG_PART: //new msg from remote connection err = s.newMsg(connection, pack) if err != nil { - logs.Error("mux: read session connection new msg err") + logs.Error("mux: read session connection new msg err", err) connection.Close() } continue diff --git a/lib/mux/queue.go b/lib/mux/queue.go index 2288e40..212563c 100644 --- a/lib/mux/queue.go +++ b/lib/mux/queue.go @@ -209,10 +209,10 @@ func NewListElement(buf []byte, l uint16, part bool) (element *common.ListElemen } type ReceiveWindowQueue struct { + lengthWait uint64 chain *bufChain stopOp chan struct{} readOp chan struct{} - lengthWait uint64 timeout time.Time } From f352ee8f398bff2f9367acc65c5a6cc95e89d101 Mon Sep 17 00:00:00 2001 From: ffdfgdfg Date: Thu, 28 Nov 2019 21:21:16 +0800 Subject: [PATCH 58/58] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 38 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..041b570 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Opening '...' +2. Click on '....' +3. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots or logs** +Add screenshots or logs to help explain your problem. + +**Server (please complete the following information):** + - OS: [e.g. Centos, Windows] + - ARCH: [e.g. Amd64, Arm] + - Tunnel [e.g. TCP, HTTP] + - Version [e.g. 0.24.0] + +**Client (please complete the following information):** + - OS: [e.g. Centos, Windows] + - ARCH: [e.g. Amd64, Arm] + - Tunnel [e.g. TCP, HTTP] + - Version [e.g. 0.24.0] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..11fc491 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here.