diff --git a/.gitignore b/.gitignore index 0b71a3e..26db932 100644 --- a/.gitignore +++ b/.gitignore @@ -86,3 +86,4 @@ third-lib # binary files bin +public diff --git a/Makefile b/Makefile index 61b76ad..3c860c8 100644 --- a/Makefile +++ b/Makefile @@ -10,11 +10,11 @@ cproxy_clean: $(MAKE) -C proxy_c clean goproxy_clean: - $(MAKE) -C proxy_go clean + $(MAKE) -C proxy clean cproxy: $(MAKE) -C proxy_c goproxy: - $(MAKE) -C proxy_go build + $(MAKE) -C proxy build diff --git a/proxy_go/.idea/.gitignore b/proxy/.idea/.gitignore similarity index 100% rename from proxy_go/.idea/.gitignore rename to proxy/.idea/.gitignore diff --git a/proxy_go/.idea/encodings.xml b/proxy/.idea/encodings.xml similarity index 100% rename from proxy_go/.idea/encodings.xml rename to proxy/.idea/encodings.xml diff --git a/proxy_go/.idea/misc.xml b/proxy/.idea/misc.xml similarity index 100% rename from proxy_go/.idea/misc.xml rename to proxy/.idea/misc.xml diff --git a/proxy_go/.idea/modules.xml b/proxy/.idea/modules.xml similarity index 100% rename from proxy_go/.idea/modules.xml rename to proxy/.idea/modules.xml diff --git a/proxy_go/.idea/selfcare_proxy_go.iml b/proxy/.idea/selfcare_proxy_go.iml similarity index 100% rename from proxy_go/.idea/selfcare_proxy_go.iml rename to proxy/.idea/selfcare_proxy_go.iml diff --git a/proxy_go/.idea/vcs.xml b/proxy/.idea/vcs.xml similarity index 100% rename from proxy_go/.idea/vcs.xml rename to proxy/.idea/vcs.xml diff --git a/proxy_go/.project b/proxy/.project similarity index 100% rename from proxy_go/.project rename to proxy/.project diff --git a/proxy_go/Makefile b/proxy/Makefile similarity index 100% rename from proxy_go/Makefile rename to proxy/Makefile diff --git a/proxy_go/MsgDef/canal.go b/proxy/MsgDef/canal.go similarity index 100% rename from proxy_go/MsgDef/canal.go rename to proxy/MsgDef/canal.go diff --git a/proxy_go/MsgDef/msg_struct.go b/proxy/MsgDef/msg_struct.go similarity index 100% rename from proxy_go/MsgDef/msg_struct.go rename to proxy/MsgDef/msg_struct.go diff --git a/proxy_go/Nmysql/alert_sms.go b/proxy/Nmysql/alert_sms.go similarity index 100% rename from proxy_go/Nmysql/alert_sms.go rename to proxy/Nmysql/alert_sms.go diff --git a/proxy_go/Nmysql/create_acct.go b/proxy/Nmysql/create_acct.go similarity index 100% rename from proxy_go/Nmysql/create_acct.go rename to proxy/Nmysql/create_acct.go diff --git a/proxy_go/Nmysql/map.go b/proxy/Nmysql/map.go similarity index 100% rename from proxy_go/Nmysql/map.go rename to proxy/Nmysql/map.go diff --git a/proxy_go/Nmysql/mysql_db.go b/proxy/Nmysql/mysql_db.go similarity index 100% rename from proxy_go/Nmysql/mysql_db.go rename to proxy/Nmysql/mysql_db.go diff --git a/proxy_go/Nmysql/provision.go b/proxy/Nmysql/provision.go similarity index 100% rename from proxy_go/Nmysql/provision.go rename to proxy/Nmysql/provision.go diff --git a/proxy_go/Nmysql/smcli_cmd.go b/proxy/Nmysql/smcli_cmd.go similarity index 100% rename from proxy_go/Nmysql/smcli_cmd.go rename to proxy/Nmysql/smcli_cmd.go diff --git a/proxy_go/Nmysql/update_plan_usage.go b/proxy/Nmysql/update_plan_usage.go similarity index 100% rename from proxy_go/Nmysql/update_plan_usage.go rename to proxy/Nmysql/update_plan_usage.go diff --git a/proxy_go/Nmysql/user_status.go b/proxy/Nmysql/user_status.go similarity index 100% rename from proxy_go/Nmysql/user_status.go rename to proxy/Nmysql/user_status.go diff --git a/proxy_go/Nredis/acctount.go b/proxy/Nredis/acctount.go similarity index 100% rename from proxy_go/Nredis/acctount.go rename to proxy/Nredis/acctount.go diff --git a/proxy_go/Nredis/alert_sms.go b/proxy/Nredis/alert_sms.go similarity index 100% rename from proxy_go/Nredis/alert_sms.go rename to proxy/Nredis/alert_sms.go diff --git a/proxy_go/Nredis/bundleclr.go b/proxy/Nredis/bundleclr.go similarity index 100% rename from proxy_go/Nredis/bundleclr.go rename to proxy/Nredis/bundleclr.go diff --git a/proxy_go/Nredis/canal_info.go b/proxy/Nredis/canal_info.go similarity index 100% rename from proxy_go/Nredis/canal_info.go rename to proxy/Nredis/canal_info.go diff --git a/proxy_go/Nredis/create_acct.go b/proxy/Nredis/create_acct.go similarity index 100% rename from proxy_go/Nredis/create_acct.go rename to proxy/Nredis/create_acct.go diff --git a/proxy_go/Nredis/holiday.go b/proxy/Nredis/holiday.go similarity index 100% rename from proxy_go/Nredis/holiday.go rename to proxy/Nredis/holiday.go diff --git a/proxy_go/Nredis/plan_expiry.go b/proxy/Nredis/plan_expiry.go similarity index 100% rename from proxy_go/Nredis/plan_expiry.go rename to proxy/Nredis/plan_expiry.go diff --git a/proxy_go/Nredis/rds_client.go b/proxy/Nredis/rds_client.go similarity index 100% rename from proxy_go/Nredis/rds_client.go rename to proxy/Nredis/rds_client.go diff --git a/proxy_go/Nrestful/alert_sms.go b/proxy/Nrestful/alert_sms.go similarity index 100% rename from proxy_go/Nrestful/alert_sms.go rename to proxy/Nrestful/alert_sms.go diff --git a/proxy_go/Nrestful/decode_udp.go b/proxy/Nrestful/decode_udp.go similarity index 100% rename from proxy_go/Nrestful/decode_udp.go rename to proxy/Nrestful/decode_udp.go diff --git a/proxy_go/Nrestful/error_code.go b/proxy/Nrestful/error_code.go similarity index 100% rename from proxy_go/Nrestful/error_code.go rename to proxy/Nrestful/error_code.go diff --git a/proxy_go/Nrestful/handle_ocs_msg.go b/proxy/Nrestful/handle_ocs_msg.go similarity index 100% rename from proxy_go/Nrestful/handle_ocs_msg.go rename to proxy/Nrestful/handle_ocs_msg.go diff --git a/proxy_go/Nrestful/handle_port.go b/proxy/Nrestful/handle_port.go similarity index 100% rename from proxy_go/Nrestful/handle_port.go rename to proxy/Nrestful/handle_port.go diff --git a/proxy_go/Nrestful/rest_msg.go b/proxy/Nrestful/rest_msg.go similarity index 100% rename from proxy_go/Nrestful/rest_msg.go rename to proxy/Nrestful/rest_msg.go diff --git a/proxy_go/Nrestful/rest_response.go b/proxy/Nrestful/rest_response.go similarity index 100% rename from proxy_go/Nrestful/rest_response.go rename to proxy/Nrestful/rest_response.go diff --git a/proxy_go/Nrestful/rest_router.go b/proxy/Nrestful/rest_router.go similarity index 100% rename from proxy_go/Nrestful/rest_router.go rename to proxy/Nrestful/rest_router.go diff --git a/proxy_go/Nrestful/udp_msg.go b/proxy/Nrestful/udp_msg.go similarity index 100% rename from proxy_go/Nrestful/udp_msg.go rename to proxy/Nrestful/udp_msg.go diff --git a/proxy_go/Nrestful/udp_routers.go b/proxy/Nrestful/udp_routers.go similarity index 100% rename from proxy_go/Nrestful/udp_routers.go rename to proxy/Nrestful/udp_routers.go diff --git a/proxy_go/Readme.txt b/proxy/Readme.txt similarity index 94% rename from proxy_go/Readme.txt rename to proxy/Readme.txt index 8e86483..3d8b7cb 100644 --- a/proxy_go/Readme.txt +++ b/proxy/Readme.txt @@ -57,7 +57,7 @@ sudo apt install libhiredis-dev log: output: file level: info #log - path: /var/log/proxy_go.log + path: /var/log/proxy.log maxAge: 120 rotationTime: 3 mysqlDb: diff --git a/proxy_go/TelnetShellServer/shell_server.go b/proxy/TelnetShellServer/shell_server.go similarity index 100% rename from proxy_go/TelnetShellServer/shell_server.go rename to proxy/TelnetShellServer/shell_server.go diff --git a/proxy/canal/canal.go b/proxy/canal/canal.go new file mode 100644 index 0000000..3571f6c --- /dev/null +++ b/proxy/canal/canal.go @@ -0,0 +1,194 @@ +package canal + +import ( + "github.com/go-mysql-org/go-mysql/canal" + "github.com/go-mysql-org/go-mysql/mysql" + "github.com/go-mysql-org/go-mysql/replication" + mdb "proxy/Nmysql" + rds "proxy/Nredis" + "proxy/config" + + //"github.com/siddontang/go-log/log" + //"strconv" + + "proxy/logger" +) + +type MyEventHandler struct { + canal.DummyEventHandler +} + +// 监听数据记录 +func (h *MyEventHandler) OnRow(e *canal.RowsEvent) error { + logger.CanalLog.Infof("OnRow: %s.%s %s %v", e.Table.Schema, e.Table.Name, e.Action, e.Rows) + + /*if !config.Config.CanalServer.Standalone && rds.CheckIfRdbMaster() == false { + logger.CanalLog.Warnf("not stand alone, and change to Slave!") + cnl.Close() + return nil + }*/ + c := ParseAndFilterBinLog(e) + updateRedisTable(c) + for columnIndex, curColumn := range e.Table.Columns { + logger.CanalLog.Debugf("row info: %v %v %v", curColumn.Name, columnIndex, e.Rows[len(e.Rows)-1][columnIndex]) + } + //cnl.Close()// if slave + return nil +} + +// 创建,更改,重命名或者删除表时触发,通常会需要清除与表相关的数据,如缓存。 It will be called before OnDDL. +func (h *MyEventHandler) OnTableChanged(header *replication.EventHeader, schema string, table string) error { + logger.CanalLog.Infof("OnTableChanged: %s %s", schema, table) + return nil +} + +// 监听binlog日志的变化文件与记录的位置 +func (h *MyEventHandler) OnPosSynced(header *replication.EventHeader, pos mysql.Position, set mysql.GTIDSet, force bool) error { + // if force == true, 立即同步位置 + rds.RdbSetBinLogPos(pos.Name, pos.Pos) + logger.CanalLog.Infof("OnPosSynced: Name[%v] Pos[%v], force[%t]", pos.Name, pos.Pos, force) + return nil +} + +// 当产生新的binlog日志后触发(在达到内存的使用限制后(默认为1GB),会开启另一个文件,每个新文件的名称后都会有一个增量.) +func (h *MyEventHandler) OnRotate(header *replication.EventHeader, r *replication.RotateEvent) error { + // record := fmt.Sprintf("On Rotate: %v \n", &mysql.Position{Name: string(r.NextLogName), Pos: uint32(r.Position)}) + // binlog的记录位置,新binlog的文件名 + logger.CanalLog.Infof("On Rotate: Pos[%v] NextLogName[%v] \n", r.Position, r.NextLogName) + return nil +} + +// Create alter drop truncate(删除当前表再新建一个一模一样的表结构) +func (h *MyEventHandler) OnDDL(header *replication.EventHeader, nextPos mysql.Position, queryEvent *replication.QueryEvent) error { + // binlog日志的变化文件与记录的位置 + logger.CanalLog.Infof("OnDDL: Name[%v] Pos[%v]\n", nextPos.Name, nextPos.Pos) + logger.CanalLog.Infof("%v\n %v\n %v\n %v\n %v\n", + queryEvent.ExecutionTime, // 猜是执行时间,但测试显示0 + string(queryEvent.Schema), // 库名 + string(queryEvent.Query), // 变更的sql语句 + string(queryEvent.StatusVars[:]), //测试显示乱码 + queryEvent.SlaveProxyID) // 从库代理ID? + return nil +} + +func (h *MyEventHandler) String() string { + return "MyEventHandler" +} + +var cnl *canal.Canal +func StartMyCanal(addr string, username string, password string) { + cfg := canal.NewDefaultConfig() + cfg.Addr = addr //"192.168.1.211:3306" + cfg.User = username + cfg.Password = password + // We only care table canal_test in test db + cfg.Dump.TableDB = "boss" + cfg.Dump.Tables = []string{"tb_prd_ofr_detail_inst_551", + "tb_bil_tariff", "tb_prd_ofr", "tb_bil_evt_pricing_strategy", "config_area", + "tb_bil_pricing_area", "ratable_history", "tb_bil_holiday_rel", "tb_bil_holiday"}//, "tb_prd_prd_inst_551"} + cfg.IncludeTableRegex = make([]string, 0, 1) + cfg.IncludeTableRegex = append(cfg.IncludeTableRegex, "boss\\.tb_prd_prd_inst_551") + cfg.IncludeTableRegex = append(cfg.IncludeTableRegex, "boss\\.tb_prd_ofr_detail_inst_551") + cfg.IncludeTableRegex = append(cfg.IncludeTableRegex, "boss\\.tb_bil_tariff") + cfg.IncludeTableRegex = append(cfg.IncludeTableRegex, "boss\\.tb_prd_ofr") + cfg.IncludeTableRegex = append(cfg.IncludeTableRegex, "boss\\.tb_bil_evt_pricing_strategy") + cfg.IncludeTableRegex = append(cfg.IncludeTableRegex, "boss\\.config_area") + cfg.IncludeTableRegex = append(cfg.IncludeTableRegex, "boss\\.tb_bil_pricing_area") + cfg.IncludeTableRegex = append(cfg.IncludeTableRegex, "boss\\.ratable_history") + cfg.IncludeTableRegex = append(cfg.IncludeTableRegex, "boss\\.tb_bil_holiday_rel") + cfg.IncludeTableRegex = append(cfg.IncludeTableRegex, "boss\\.tb_bil_holiday") + if config.Config.CronCfg.Enabled && config.Config.CronCfg.NtfSms != "" { + cfg.IncludeTableRegex = append(cfg.IncludeTableRegex, "boss\\.tb_sms_info") + } + if config.Config.Rest.Enabled { + cfg.Dump.Tables = append(cfg.Dump.Tables, "tb_sync_mobile") + cfg.IncludeTableRegex = append(cfg.IncludeTableRegex, "boss\\.tb_sync_mobile") + } + + c, err := canal.NewCanal(cfg) + if err != nil { + logger.CanalLog.Errorf("NewCanal, err: %v", err) + return + } + + // Register a handler to handle RowsEvent + c.SetEventHandler(&MyEventHandler{}) + + var pos *mysql.Position + if config.Config.CanalServer.Reinit { + pos = QueryBinLogPos(c) + if pos == nil { + logger.CanalLog.Errorln("fail to get binlog position.") + return + } + + logger.CanalLog.Infoln("start to sync mysql DB.") + CurState = "loading" + if config.Config.CanalServer.FlushBeforeInit { + rds.ClrTariffAndBundle() + } + _ = mdb.LoadAcctTblFromMysql() + _ = mdb.LoadAlertSmsFromMysql() + //_ = mdb.LoadCreateAcctFromMysql() + config.Config.CanalServer.Reinit = false + config.SavePcfCfg() + logger.CanalLog.Infoln("finish sync mysql DB...") + CurState = "synchronize" + } else { + ret := rds.RdbGetBinLogPos() + if ret == nil { + logger.CanalLog.Warnln("fail to get redis binlog position, query current position from mysql.") + pos = QueryBinLogPos(c) + if pos == nil { + logger.CanalLog.Errorln("fail to get binlog position.") + return + } + } else { + pos = &mysql.Position{Name: ret.File, Pos: ret.Position} + } + } + + // Start canal + cnl = c + logger.CanalLog.Infof("Go run") + err = c.RunFrom(*pos) + if err != nil { + logger.CanalLog.Errorf("RunFrom err: %v", err) + } else { + logger.CanalLog.Warnf("Canal exit!!!!!!") + c.Close() + } + + /* 从头开始监听 + err = c.Run() + if err != nil { + logger.CanalLog.Infof("Run err: %v", err) + }*/ + + // mysql-bin.000004, 1027 + // startPos := mysql.Position{Name: "mysql-bin.000004", Pos: 1027} + // c.RunFrom(startPos) +} + +func QueryBinLogPos(c *canal.Canal) *mysql.Position { + var pos mysql.Position + ret, err := c.Execute("SHOW MASTER STATUS;") + if err != nil { + logger.CanalLog.Errorf("SHOW MASTER STATUS err: %v", err) + return nil + } + pos.Name, err = ret.Resultset.GetStringByName(0, "File") + if err != nil { + logger.CanalLog.Errorf("Get binlog file name err: %v", err) + return nil + } + posTmp, err := ret.Resultset.GetUintByName(0, "Position") + if err != nil { + logger.CanalLog.Errorf("Get binlog position err: %v", err) + return nil + } + pos.Pos = uint32(posTmp) + logger.CanalLog.Infof("Current Position: %v", pos) + rds.RdbSetBinLogPos(pos.Name, pos.Pos) + return &pos +} diff --git a/proxy_go/canal/canal.go b/proxy/canal/canal.go.bak similarity index 100% rename from proxy_go/canal/canal.go rename to proxy/canal/canal.go.bak diff --git a/proxy_go/canal/client.go b/proxy/canal/client.go similarity index 100% rename from proxy_go/canal/client.go rename to proxy/canal/client.go diff --git a/proxy_go/canal/client_fsm.go b/proxy/canal/client_fsm.go similarity index 100% rename from proxy_go/canal/client_fsm.go rename to proxy/canal/client_fsm.go diff --git a/proxy_go/canal/msg.go b/proxy/canal/msg.go similarity index 100% rename from proxy_go/canal/msg.go rename to proxy/canal/msg.go diff --git a/proxy_go/canal/sync_redis.go b/proxy/canal/sync_redis.go similarity index 100% rename from proxy_go/canal/sync_redis.go rename to proxy/canal/sync_redis.go diff --git a/proxy_go/conf/config.yaml b/proxy/conf/config.yaml similarity index 100% rename from proxy_go/conf/config.yaml rename to proxy/conf/config.yaml diff --git a/proxy_go/config/config.go b/proxy/config/config.go similarity index 100% rename from proxy_go/config/config.go rename to proxy/config/config.go diff --git a/proxy_go/cron/cron.go b/proxy/cron/cron.go similarity index 100% rename from proxy_go/cron/cron.go rename to proxy/cron/cron.go diff --git a/proxy/go.sum b/proxy/go.sum new file mode 100644 index 0000000..a32ff6d --- /dev/null +++ b/proxy/go.sum @@ -0,0 +1,176 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ= +github.com/antonfisher/nested-logrus-formatter v1.3.1/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= +github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-mysql-org/go-mysql v1.11.0 h1:Y0ooXu2UtbjsgpfjFBXZEvidEl1q8n0ESxej0zZ78Zc= +github.com/go-mysql-org/go-mysql v1.11.0/go.mod h1:y/7aggbs+Io8rPVerIjTe1+nMgt8q5tBIxIc+qQnE0k= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= +github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI= +github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= +github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/ircop/tclient v0.0.0-20180908074649-f30684f28b0f h1:p7j1sjVHXwjJpr8fYjzInUGTmK9rYXgcQPiXjpawl/c= +github.com/ircop/tclient v0.0.0-20180908074649-f30684f28b0f/go.mod h1:d111ZaRuwWWPIw3+gL48/SD8Pj9P6qBS5scMGWFt6/I= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pingcap/errors v0.11.5-0.20240311024730-e056997136bb h1:3pSi4EDG6hg0orE1ndHkXvX6Qdq2cZn8gAPir8ymKZk= +github.com/pingcap/errors v0.11.5-0.20240311024730-e056997136bb/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg= +github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86 h1:tdMsjOqUR7YXHoBitzdebTvOjs/swniBTOLy5XiMtuE= +github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86/go.mod h1:exzhVYca3WRtd6gclGNErRWb1qEgff3LYta0LvRmON4= +github.com/pingcap/log v1.1.1-0.20230317032135-a0d097d16e22 h1:2SOzvGvE8beiC1Y4g9Onkvu6UmuBBOeWRGQEjJaT/JY= +github.com/pingcap/log v1.1.1-0.20230317032135-a0d097d16e22/go.mod h1:DWQW5jICDR7UJh4HtxXSM20Churx4CQL0fwL/SoOSA4= +github.com/pingcap/tidb/pkg/parser v0.0.0-20241118164214-4f047be191be h1:t5EkCmZpxLCig5GQA0AZG47aqsuL5GTsJeeUD+Qfies= +github.com/pingcap/tidb/pkg/parser v0.0.0-20241118164214-4f047be191be/go.mod h1:Hju1TEWZvrctQKbztTRwXH7rd41Yq0Pgmq4PrEKcq7o= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/reiver/go-oi v1.0.0 h1:nvECWD7LF+vOs8leNGV/ww+F2iZKf3EYjYZ527turzM= +github.com/reiver/go-oi v1.0.0/go.mod h1:RrDBct90BAhoDTxB1fenZwfykqeGvhI6LsNfStJoEkI= +github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e h1:quuzZLi72kkJjl+f5AQ93FMcadG19WkS7MO6TXFOSas= +github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e/go.mod h1:+5vNVvEWwEIx86DB9Ke/+a5wBI464eDRo3eF0LcfpWg= +github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= +github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07 h1:oI+RNwuC9jF2g2lP0u0cVEEZrc/AYBCuFdvwrLWM/6Q= +github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07/go.mod h1:yFdBgwXP24JziuRl2NMUahT7nGLNOKi1SIiFxMttVD4= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/withlin/canal-go v1.1.2 h1:ugAjPPXB1g6sePQLei/l7eaZ57ioJSo87/+z4++H2hY= +github.com/withlin/canal-go v1.1.2/go.mod h1:VlapEcKekyXd7luA6QzflxbisrYzSLAjpRqzLcgr+zk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= +golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/proxy_go/logger/logger.go b/proxy/logger/logger.go similarity index 100% rename from proxy_go/logger/logger.go rename to proxy/logger/logger.go diff --git a/proxy_go/main.go b/proxy/main.go similarity index 100% rename from proxy_go/main.go rename to proxy/main.go diff --git a/proxy_go/provision/provision.go b/proxy/provision/provision.go similarity index 100% rename from proxy_go/provision/provision.go rename to proxy/provision/provision.go diff --git a/proxy_go/redis/client.go b/proxy/redis/client.go similarity index 100% rename from proxy_go/redis/client.go rename to proxy/redis/client.go diff --git a/proxy_go/public/logger_conf@v1.0.0/.gitignore b/proxy/util/logger_conf/.gitignore similarity index 100% rename from proxy_go/public/logger_conf@v1.0.0/.gitignore rename to proxy/util/logger_conf/.gitignore diff --git a/proxy_go/public/logger_conf@v1.0.0/.golangci.yml b/proxy/util/logger_conf/.golangci.yml similarity index 100% rename from proxy_go/public/logger_conf@v1.0.0/.golangci.yml rename to proxy/util/logger_conf/.golangci.yml diff --git a/proxy_go/public/logger_conf@v1.0.0/LICENSE.txt b/proxy/util/logger_conf/LICENSE.txt similarity index 100% rename from proxy_go/public/logger_conf@v1.0.0/LICENSE.txt rename to proxy/util/logger_conf/LICENSE.txt diff --git a/proxy_go/util/logger_conf/conf.go b/proxy/util/logger_conf/conf.go similarity index 100% rename from proxy_go/util/logger_conf/conf.go rename to proxy/util/logger_conf/conf.go diff --git a/proxy_go/public/logger_util@v1.0.0/.gitignore b/proxy/util/logger_util/.gitignore similarity index 100% rename from proxy_go/public/logger_util@v1.0.0/.gitignore rename to proxy/util/logger_util/.gitignore diff --git a/proxy_go/public/logger_util@v1.0.0/.golangci.yml b/proxy/util/logger_util/.golangci.yml similarity index 100% rename from proxy_go/public/logger_util@v1.0.0/.golangci.yml rename to proxy/util/logger_util/.golangci.yml diff --git a/proxy_go/public/logger_util@v1.0.0/CHANGELOG.md b/proxy/util/logger_util/CHANGELOG.md similarity index 100% rename from proxy_go/public/logger_util@v1.0.0/CHANGELOG.md rename to proxy/util/logger_util/CHANGELOG.md diff --git a/proxy_go/public/logger_util@v1.0.0/LICENSE.txt b/proxy/util/logger_util/LICENSE.txt similarity index 100% rename from proxy_go/public/logger_util@v1.0.0/LICENSE.txt rename to proxy/util/logger_util/LICENSE.txt diff --git a/proxy_go/public/logger_util@v1.0.0/log_level.go b/proxy/util/logger_util/log_level.go similarity index 100% rename from proxy_go/public/logger_util@v1.0.0/log_level.go rename to proxy/util/logger_util/log_level.go diff --git a/proxy_go/util/logger_util/logger_util.go b/proxy/util/logger_util/logger_util.go similarity index 100% rename from proxy_go/util/logger_util/logger_util.go rename to proxy/util/logger_util/logger_util.go diff --git a/proxy_go/public/logger_util@v1.0.0/version/version.go b/proxy/util/logger_util/version/version.go similarity index 100% rename from proxy_go/public/logger_util@v1.0.0/version/version.go rename to proxy/util/logger_util/version/version.go diff --git a/proxy_go/go.sum b/proxy_go/go.sum deleted file mode 100644 index ffb3beb..0000000 --- a/proxy_go/go.sum +++ /dev/null @@ -1,248 +0,0 @@ -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/antonfisher/nested-logrus-formatter v1.3.0 h1:8zixYquU1Odk+vzAaAQPAdRh1ZjmUXNQ1T+dUBvlhVo= -github.com/antonfisher/nested-logrus-formatter v1.3.0/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cznic/golex v0.0.0-20181122101858-9c343928389c/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc= -github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= -github.com/cznic/parser v0.0.0-20160622100904-31edd927e5b1/go.mod h1:2B43mz36vGZNZEwkWi8ayRSSUXLfjL8OkbzwW4NcPMM= -github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ= -github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc= -github.com/cznic/y v0.0.0-20170802143616-045f81c6662a/go.mod h1:1rk5VM7oSnA4vjp+hrLQ3HWHa+Y4yPCa3/CsJrcNnvs= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/go-mysql-org/go-mysql v1.6.0 h1:19B5fojzZcri/1wj9G/1+ws8RJ3N6rJs2X5c/+kBLuQ= -github.com/go-mysql-org/go-mysql v1.6.0/go.mod h1:GX0clmylJLdZEYAojPCDTCvwZxbTBrke93dV55715u0= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= -github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/go-redis/redis/v8 v8.11.0 h1:O1Td0mQ8UFChQ3N9zFQqo6kTU2cJ+/it88gDB+zg0wo= -github.com/go-redis/redis/v8 v8.11.0/go.mod h1:DLomh7y2e3ggQXQLd1YgmvIfecPJoFl7WU5SOQ/r06M= -github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ircop/tclient v0.0.0-20180908074649-f30684f28b0f h1:p7j1sjVHXwjJpr8fYjzInUGTmK9rYXgcQPiXjpawl/c= -github.com/ircop/tclient v0.0.0-20180908074649-f30684f28b0f/go.mod h1:d111ZaRuwWWPIw3+gL48/SD8Pj9P6qBS5scMGWFt6/I= -github.com/jmoiron/sqlx v1.3.3 h1:j82X0bf7oQ27XeqxicSZsTU5suPwKElg3oyxNn43iTk= -github.com/jmoiron/sqlx v1.3.3/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= -github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4= -github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ= -github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= -github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8 h1:USx2/E1bX46VG32FIw034Au6seQ2fY9NEILmNh/UlQg= -github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8/go.mod h1:B1+S9LNcuMyLH/4HMTViQOJevkGiik3wW2AN9zb2fNQ= -github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= -github.com/pingcap/errors v0.11.5-0.20201029093017-5a7df2af2ac7/go.mod h1:G7x87le1poQzLB/TqvTJI2ILrSgobnq4Ut7luOwvfvI= -github.com/pingcap/errors v0.11.5-0.20201126102027-b0a155152ca3 h1:LllgC9eGfqzkfubMgjKIDyZYaa609nNWAyNZtpy2B3M= -github.com/pingcap/errors v0.11.5-0.20201126102027-b0a155152ca3/go.mod h1:G7x87le1poQzLB/TqvTJI2ILrSgobnq4Ut7luOwvfvI= -github.com/pingcap/log v0.0.0-20200511115504-543df19646ad/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= -github.com/pingcap/log v0.0.0-20210317133921-96f4fcab92a4 h1:ERrF0fTuIOnwfGbt71Ji3DKbOEaP189tjym50u8gpC8= -github.com/pingcap/log v0.0.0-20210317133921-96f4fcab92a4/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= -github.com/pingcap/parser v0.0.0-20210415081931-48e7f467fd74 h1:FkVEC3Fck3fD16hMObMl/IWs72jR9FmqPn0Bdf728Sk= -github.com/pingcap/parser v0.0.0-20210415081931-48e7f467fd74/go.mod h1:xZC8I7bug4GJ5KtHhgAikjTfU4kBv1Sbo3Pf1MZ6lVw= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/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/reiver/go-oi v1.0.0 h1:nvECWD7LF+vOs8leNGV/ww+F2iZKf3EYjYZ527turzM= -github.com/reiver/go-oi v1.0.0/go.mod h1:RrDBct90BAhoDTxB1fenZwfykqeGvhI6LsNfStJoEkI= -github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e h1:quuzZLi72kkJjl+f5AQ93FMcadG19WkS7MO6TXFOSas= -github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e/go.mod h1:+5vNVvEWwEIx86DB9Ke/+a5wBI464eDRo3eF0LcfpWg= -github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= -github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec h1:6ncX5ko6B9LntYM0YBRXkiSaZMmLYeZ/NWcmeB43mMY= -github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 h1:xT+JlYxNGqyT+XcU8iUrN18JYed2TvG9yN5ULG2jATM= -github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= -github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07/go.mod h1:yFdBgwXP24JziuRl2NMUahT7nGLNOKi1SIiFxMttVD4= -github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed h1:KMgQoLJGCq1IoZpLZE3AIffh9veYWoVlsvA4ib55TMM= -github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed/go.mod h1:yFdBgwXP24JziuRl2NMUahT7nGLNOKi1SIiFxMttVD4= -github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go v1.2.1 h1:dz+JxTe7GZQdErTo7SREc1jQj/hFP1k7jyIAwODoW+k= -github.com/ugorji/go v1.2.1/go.mod h1:cSVypSfTLm2o9fKxXvQgn3rMmkPXovcWor6Qn5tbFmI= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ugorji/go/codec v1.2.1 h1:/TRfW3XKkvWvmAYyCUaQlhoCDGjcvNR8xVVA/l5p/jQ= -github.com/ugorji/go/codec v1.2.1/go.mod h1:s/WxCRi46t8rA+fowL40EnmD7ec0XhR7ZypxeBNdzsM= -github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= -github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/withlin/canal-go v1.1.1 h1:eEcX/184K9tIny6krZi2NGXN111cyINzTPRNTfr83Fg= -github.com/withlin/canal-go v1.1.1/go.mod h1:dIyy0yorJ7CfPnVh8sYqkBItyqTQNTxPftE3fBJTkmY= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= -go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= -go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9 h1:sYNJzB4J8toYPQTM6pAkcmBRgw9SnQKP9oXCHfgy604= -golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/proxy_go/public/go-oi@v1.0.0/LICENSE b/proxy_go/public/go-oi@v1.0.0/LICENSE deleted file mode 100644 index aeef12f..0000000 --- a/proxy_go/public/go-oi@v1.0.0/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2016 Charles Iliya Krempeaux :: http://changelog.ca/ - -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/proxy_go/public/go-oi@v1.0.0/README.md b/proxy_go/public/go-oi@v1.0.0/README.md deleted file mode 100644 index 94fa42e..0000000 --- a/proxy_go/public/go-oi@v1.0.0/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# go-oi - -Package **oi** provides useful tools to be used with the Go programming language's standard "io" package. - -For example, did you know that when you call the `Write` method on something that fits the `io.Writer` -interface, that it is possible that not everything was be written?! - -I.e., that a _**short write**_ happened. - -That just doing the following is (in general) **not** enough: -``` -n, err := writer.Write(p) -``` - -That, for example, you should be checking if `err == io.ErrShortWrite`, and then maybe calling the `Write` -method again but only with what didn't get written. - -For a simple example of this (that actually is **not** sufficient to solve this problem, but illustrates -the direction you would need to go to solve this problem is): -``` -n, err := w.Write(p) - -if io.ErrShortWrite == err { - n2, err2 := w.Write(p[n:]) -} -``` - -Note that the second call to the `Write` method passed `p[n:]` (instead of just `p`), to account for the `n` bytes -already being written (with the first call to the `Write` method). - -A more "production quality" version of this would likely be in a loop, but such that that the loop had "guards" -against looping forever, and also possibly looping for "too long". - -Well package **oi** provides tools that helps you deal with this and other problems. For example, you -can handle a _**short write**_ with the following **oi** func: -``` -n, err := oi.LongWrite(writer, p) -``` - - -## Documention - -Online documentation, which includes examples, can be found at: http://godoc.org/github.com/reiver/go-oi - -[![GoDoc](https://godoc.org/github.com/reiver/go-oi?status.svg)](https://godoc.org/github.com/reiver/go-oi) - - -## Example -``` -import ( - "github.com/reiver/go-oi" -) - -// ... - -p := []byte("It is important that this message be written!!!") - -n, err := oi.LongWrite(writer, p) -if nil != err { - //@TODO: Handle error. - return -} - -``` diff --git a/proxy_go/public/go-oi@v1.0.0/doc.go b/proxy_go/public/go-oi@v1.0.0/doc.go deleted file mode 100644 index 1b3a555..0000000 --- a/proxy_go/public/go-oi@v1.0.0/doc.go +++ /dev/null @@ -1,39 +0,0 @@ -/* -Package oi provides useful tools to be used with Go's standard "io" package. - -For example, did you know that when you call the Write method on something that fits the io.Writer -interface, that it is possible that not everything was be written?! - -I.e., that a 'short write' happened. - -That just doing the following is (in general) not enough: - - n, err := writer.Write(p) - -That, for example, you should be checking if "err == io.ErrShortWrite", and then maybe calling the Write -method again but only with what didn't get written. - -For a simple example of this (that actually is not sufficient to solve this problem, but illustrates -the direction you would need to go to solve this problem is): - - n, err := w.Write(p) - - if io.ErrShortWrite == err { - n2, err2 := w.Write(p[n:]) - } - -Note that the second call to the Write method passed "p[n:]" (instead of just "p"), to account for the "n" bytes -already being written (with the first call to the `Write` method). - -A more "production quality" version of this would likely be in a loop, but such that that the loop had "guards" -against looping forever, and also possibly looping for "too long". - - -Well package oi provides tools that helps you deal with this and other problems. For example, you -can handle a 'short write' with the following oi func: -``` -n, err := oi.LongWrite(writer, p) -``` - -*/ -package oi diff --git a/proxy_go/public/go-oi@v1.0.0/longwrite.go b/proxy_go/public/go-oi@v1.0.0/longwrite.go deleted file mode 100644 index 27e7234..0000000 --- a/proxy_go/public/go-oi@v1.0.0/longwrite.go +++ /dev/null @@ -1,39 +0,0 @@ -package oi - - -import ( - "io" -) - - -// LongWrite tries to write the bytes from 'p' to the writer 'w', such that it deals -// with "short writes" where w.Write would return an error of io.ErrShortWrite and -// n < len(p). -// -// Note that LongWrite still could return the error io.ErrShortWrite; but this -// would only be after trying to handle the io.ErrShortWrite a number of times, and -// then eventually giving up. -func LongWrite(w io.Writer, p []byte) (int64, error) { - - numWritten := int64(0) - for { -//@TODO: Should check to make sure this doesn't get stuck in an infinite loop writting nothing! - n, err := w.Write(p) - numWritten += int64(n) - if nil != err && io.ErrShortWrite != err { - return numWritten, err - } - - if !(n < len(p)) { - break - } - - p = p[n:] - - if len(p) < 1 { - break - } - } - - return numWritten, nil -} diff --git a/proxy_go/public/go-oi@v1.0.0/longwrite_test.go b/proxy_go/public/go-oi@v1.0.0/longwrite_test.go deleted file mode 100644 index 031671f..0000000 --- a/proxy_go/public/go-oi@v1.0.0/longwrite_test.go +++ /dev/null @@ -1,195 +0,0 @@ -package oi - - -import ( - "github.com/reiver/go-oi/test" - - "errors" - "testing" -) - - -func TestLongWrite(t *testing.T) { - - tests := []struct{ - String string - }{ - { - String: "", - }, - - - - { - String: "apple", - }, - { - String: "banana", - }, - { - String: "cherry", - }, - - - - { - String: "Hello world!", - }, - - - - { - String: "😁😂😃😄😅😆😉😊😋😌😍😏😒😓😔😖😘😚😜😝😞😠😡😢😣😤😥😨😩😪😫😭😰😱😲😳😵😷", - }, - - - - { - String: "0123456789", - }, - { - String: "٠١٢٣٤٥٦٧٨٩", // Arabic-Indic Digits - }, - { - String: "۰۱۲۳۴۵۶۷۸۹", // Extended Arabic-Indic Digits - }, - - - - { - String: "Ⅰ Ⅱ Ⅲ Ⅳ Ⅴ Ⅵ Ⅶ Ⅷ Ⅸ Ⅹ Ⅺ Ⅻ Ⅼ Ⅽ Ⅾ Ⅿ", - }, - { - String: "ⅰ ⅱ ⅲ ⅳ ⅴ ⅵ ⅶ ⅷ ⅸ ⅹ ⅺ ⅻ ⅼ ⅽ ⅾ ⅿ", - }, - { - String: "ↀ ↁ ↂ Ↄ ↄ ↅ ↆ ↇ ↈ", - }, - } - - - for testNumber, test := range tests { - - p := []byte(test.String) - - var writer oitest.ShortWriter - n, err := LongWrite(&writer, p) - if nil != err { - t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %q; for %q.", testNumber, err, err.Error(), test.String) - continue - } - if expected, actual := int64(len([]byte(test.String))), n; expected != actual { - t.Errorf("For test #%d, expected %d, but actually got %d; for %q.", testNumber, expected, actual, test.String) - continue - } - if expected, actual := test.String, writer.String(); expected != actual { - t.Errorf("For test #%d, expected %q, but actually got %q", testNumber, expected, actual) - continue - } - } -} - - -func TestLongWriteExpectError(t *testing.T) { - - tests := []struct{ - String string - Expected string - Writes []int - Err error - }{ - { - String: "apple", - Expected: "appl", - Writes: []int{2,2}, - Err: errors.New("Crabapple!"), - }, - { - String: "apple", - Expected: "appl", - Writes: []int{2,2,0}, - Err: errors.New("Crabapple!!"), - }, - - - - { - String: "banana", - Expected: "banan", - Writes: []int{2,3}, - Err: errors.New("bananananananana!"), - }, - { - String: "banana", - Expected: "banan", - Writes: []int{2,3,0}, - Err: errors.New("bananananananananananananana!!!"), - }, - - - - { - String: "cherry", - Expected: "cher", - Writes: []int{1,1,1,1}, - Err: errors.New("C.H.E.R.R.Y."), - }, - { - String: "cherry", - Expected: "cher", - Writes: []int{1,1,1,1,0}, - Err: errors.New("C_H_E_R_R_Y"), - }, - - - - { - String: "Hello world!", - Expected: "Hello world", - Writes: []int{1,2,3,5}, - Err: errors.New("Welcome!"), - }, - { - String: "Hello world!", - Expected: "Hello world", - Writes: []int{1,2,3,5,0}, - Err: errors.New("WeLcOmE!!!"), - }, - - - - { - String: " ", - Expected: " ", - Writes: []int{1,2,3,5,8,13}, - Err: errors.New("Space, the final frontier"), - }, - { - String: " ", - Expected: " ", - Writes: []int{1,2,3,5,8,13,0}, - Err: errors.New("Space, the final frontier"), - }, - } - - for testNumber, test := range tests { - - p := []byte(test.String) - - writer := oitest.NewWritesThenErrorWriter(test.Err, test.Writes...) - n, err := LongWrite(writer, p) - if nil == err { - t.Errorf("For test #%d, expected to get an error, but actually did not get one: %v; for %q.", testNumber, err, test.String) - continue - } - if expected, actual := test.Err, err; expected != actual { - t.Errorf("For test #%d, expected to get error (%T) %q, but actually got (%T) %q; for %q.", testNumber, expected, expected.Error(), actual, actual.Error(), test.String) - continue - } - if expected, actual := int64(len(test.Expected)), n; expected != actual { - t.Errorf("For test #%d, expected number of bytes written to be %d = len(%q), but actually was %d = len(%q); for %q.", testNumber, expected, test.Expected, actual, writer.String(), test.String) - continue - } - } - -} diff --git a/proxy_go/public/go-oi@v1.0.0/longwritebyte.go b/proxy_go/public/go-oi@v1.0.0/longwritebyte.go deleted file mode 100644 index 022e418..0000000 --- a/proxy_go/public/go-oi@v1.0.0/longwritebyte.go +++ /dev/null @@ -1,28 +0,0 @@ -package oi - - -import ( - "io" -) - - -// LongWriteByte trys to write the byte from 'b' to the writer 'w', such that it deals -// with "short writes" where w.Write would return an error of io.ErrShortWrite and -// n < 1. -// -// Note that LongWriteByte still could return the error io.ErrShortWrite; but this -// would only be after trying to handle the io.ErrShortWrite a number of times, and -// then eventually giving up. -func LongWriteByte(w io.Writer, b byte) error { - var buffer [1]byte - p := buffer[:] - - buffer[0] = b - - numWritten, err := LongWrite(w, p) - if 1 != numWritten { - return io.ErrShortWrite - } - - return err -} diff --git a/proxy_go/public/go-oi@v1.0.0/longwritebyte_test.go b/proxy_go/public/go-oi@v1.0.0/longwritebyte_test.go deleted file mode 100644 index 4694f5f..0000000 --- a/proxy_go/public/go-oi@v1.0.0/longwritebyte_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package oi - - -import ( - "github.com/reiver/go-oi/test" - - "testing" -) - - -func TestLongWriteByte(t *testing.T) { - - tests := []struct{ - Byte byte - }{} - - for b := byte(' '); b <= byte('/'); b++ { - test := struct { - Byte byte - }{ - Byte:b, - } - - tests = append(tests, test) - } - - for b := byte('0'); b <= byte('9'); b++ { - test := struct { - Byte byte - }{ - Byte:b, - } - - tests = append(tests, test) - } - - for b := byte(':'); b <= byte('@'); b++ { - test := struct { - Byte byte - }{ - Byte:b, - } - - tests = append(tests, test) - } - - for b := byte('A'); b <= byte('Z'); b++ { - test := struct { - Byte byte - }{ - Byte:b, - } - - tests = append(tests, test) - } - - for b := byte('['); b <= byte('`'); b++ { - test := struct { - Byte byte - }{ - Byte:b, - } - - tests = append(tests, test) - } - - for b := byte('a'); b <= byte('z'); b++ { - test := struct { - Byte byte - }{ - Byte:b, - } - - tests = append(tests, test) - } - - for b := byte('{'); b <= byte('~'); b++ { - test := struct { - Byte byte - }{ - Byte:b, - } - - tests = append(tests, test) - } - - - for testNumber, test := range tests { - - var writer oitest.ShortWriter - err := LongWriteByte(&writer, test.Byte) - if nil != err { - t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %q; for %d (%q).", testNumber, err, err.Error(), test.Byte, string(test.Byte)) - continue - } - if expected, actual := string(test.Byte), writer.String(); expected != actual { - t.Errorf("For test #%d, expected %q, but actually got %q", testNumber, expected, actual) - continue - } - } -} diff --git a/proxy_go/public/go-oi@v1.0.0/longwritestring.go b/proxy_go/public/go-oi@v1.0.0/longwritestring.go deleted file mode 100644 index 504097a..0000000 --- a/proxy_go/public/go-oi@v1.0.0/longwritestring.go +++ /dev/null @@ -1,39 +0,0 @@ -package oi - - -import ( - "io" -) - - -// LongWriteString tries to write the bytes from 's' to the writer 'w', such that it deals -// with "short writes" where w.Write (or w.WriteString) would return an error of io.ErrShortWrite -// and n < len(s). -// -// Note that LongWriteString still could return the error io.ErrShortWrite; but this -// would only be after trying to handle the io.ErrShortWrite a number of times, and -// then eventually giving up. -func LongWriteString(w io.Writer, s string) (int64, error) { - - numWritten := int64(0) - for { -//@TODO: Should check to make sure this doesn't get stuck in an infinite loop writting nothing! - n, err := io.WriteString(w, s) - numWritten += int64(n) - if nil != err && io.ErrShortWrite != err { - return numWritten, err - } - - if !(n < len(s)) { - break - } - - s = s[n:] - - if len(s) < 1 { - break - } - } - - return numWritten, nil -} diff --git a/proxy_go/public/go-oi@v1.0.0/longwritestring_test.go b/proxy_go/public/go-oi@v1.0.0/longwritestring_test.go deleted file mode 100644 index a86e768..0000000 --- a/proxy_go/public/go-oi@v1.0.0/longwritestring_test.go +++ /dev/null @@ -1,191 +0,0 @@ -package oi - - -import ( - "github.com/reiver/go-oi/test" - - "errors" - "testing" -) - - -func TestLongWriteString(t *testing.T) { - - tests := []struct{ - String string - }{ - { - String: "", - }, - - - - { - String: "apple", - }, - { - String: "banana", - }, - { - String: "cherry", - }, - - - - { - String: "Hello world!", - }, - - - - { - String: "😁😂😃😄😅😆😉😊😋😌😍😏😒😓😔😖😘😚😜😝😞😠😡😢😣😤😥😨😩😪😫😭😰😱😲😳😵😷", - }, - - - - { - String: "0123456789", - }, - { - String: "٠١٢٣٤٥٦٧٨٩", // Arabic-Indic Digits - }, - { - String: "۰۱۲۳۴۵۶۷۸۹", // Extended Arabic-Indic Digits - }, - - - - { - String: "Ⅰ Ⅱ Ⅲ Ⅳ Ⅴ Ⅵ Ⅶ Ⅷ Ⅸ Ⅹ Ⅺ Ⅻ Ⅼ Ⅽ Ⅾ Ⅿ", - }, - { - String: "ⅰ ⅱ ⅲ ⅳ ⅴ ⅵ ⅶ ⅷ ⅸ ⅹ ⅺ ⅻ ⅼ ⅽ ⅾ ⅿ", - }, - { - String: "ↀ ↁ ↂ Ↄ ↄ ↅ ↆ ↇ ↈ", - }, - } - - - for testNumber, test := range tests { - - var writer oitest.ShortWriter - n, err := LongWriteString(&writer, test.String) - if nil != err { - t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %q; for %q.", testNumber, err, err.Error(), test.String) - continue - } - if expected, actual := int64(len([]byte(test.String))), n; expected != actual { - t.Errorf("For test #%d, expected %d, but actually got %d; for %q.", testNumber, expected, actual, test.String) - continue - } - if expected, actual := test.String, writer.String(); expected != actual { - t.Errorf("For test #%d, expected %q, but actually got %q", testNumber, expected, actual) - continue - } - } -} - - -func TestLongWriteStringExpectError(t *testing.T) { - - tests := []struct{ - String string - Expected string - Writes []int - Err error - }{ - { - String: "apple", - Expected: "appl", - Writes: []int{2,2}, - Err: errors.New("Crabapple!"), - }, - { - String: "apple", - Expected: "appl", - Writes: []int{2,2,0}, - Err: errors.New("Crabapple!!"), - }, - - - - { - String: "banana", - Expected: "banan", - Writes: []int{2,3}, - Err: errors.New("bananananananana!"), - }, - { - String: "banana", - Expected: "banan", - Writes: []int{2,3,0}, - Err: errors.New("bananananananananananananana!!!"), - }, - - - - { - String: "cherry", - Expected: "cher", - Writes: []int{1,1,1,1}, - Err: errors.New("C.H.E.R.R.Y."), - }, - { - String: "cherry", - Expected: "cher", - Writes: []int{1,1,1,1,0}, - Err: errors.New("C_H_E_R_R_Y"), - }, - - - - { - String: "Hello world!", - Expected: "Hello world", - Writes: []int{1,2,3,5}, - Err: errors.New("Welcome!"), - }, - { - String: "Hello world!", - Expected: "Hello world", - Writes: []int{1,2,3,5,0}, - Err: errors.New("WeLcOmE!!!"), - }, - - - - { - String: " ", - Expected: " ", - Writes: []int{1,2,3,5,8,13}, - Err: errors.New("Space, the final frontier"), - }, - { - String: " ", - Expected: " ", - Writes: []int{1,2,3,5,8,13,0}, - Err: errors.New("Space, the final frontier"), - }, - } - - for testNumber, test := range tests { - - writer := oitest.NewWritesThenErrorWriter(test.Err, test.Writes...) - n, err := LongWriteString(writer, test.String) - if nil == err { - t.Errorf("For test #%d, expected to get an error, but actually did not get one: %v; for %q.", testNumber, err, test.String) - continue - } - if expected, actual := test.Err, err; expected != actual { - t.Errorf("For test #%d, expected to get error (%T) %q, but actually got (%T) %q; for %q.", testNumber, expected, expected.Error(), actual, actual.Error(), test.String) - continue - } - if expected, actual := int64(len(test.Expected)), n; expected != actual { - t.Errorf("For test #%d, expected number of bytes written to be %d = len(%q), but actually was %d = len(%q); for %q.", testNumber, expected, test.Expected, actual, writer.String(), test.String) - continue - } - } - -} diff --git a/proxy_go/public/go-oi@v1.0.0/test/doc.go b/proxy_go/public/go-oi@v1.0.0/test/doc.go deleted file mode 100644 index ae6c1cf..0000000 --- a/proxy_go/public/go-oi@v1.0.0/test/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -/* -Package oitest provides useful tools to be used for testing implementations of interfaces in Go's standard "io" package. - -*/ -package oitest diff --git a/proxy_go/public/go-oi@v1.0.0/test/randomness.go b/proxy_go/public/go-oi@v1.0.0/test/randomness.go deleted file mode 100644 index 4906ec7..0000000 --- a/proxy_go/public/go-oi@v1.0.0/test/randomness.go +++ /dev/null @@ -1,12 +0,0 @@ -package oitest - - -import ( - "math/rand" - "time" -) - - -var ( - randomness = rand.New(rand.NewSource( time.Now().UTC().UnixNano() )) -) diff --git a/proxy_go/public/go-oi@v1.0.0/test/short_writer.go b/proxy_go/public/go-oi@v1.0.0/test/short_writer.go deleted file mode 100644 index 49ad704..0000000 --- a/proxy_go/public/go-oi@v1.0.0/test/short_writer.go +++ /dev/null @@ -1,80 +0,0 @@ -package oitest - - -import ( - "bytes" - "io" -) - - -// ShortWriter is useful for testing things that makes use of -// or accept an io.Writer. -// -// In particular, it is useful to see if that thing can handle -// an io.Writer that does a "short write". -// -// A "short write" is the case when a call like: -// -// n, err := w.Write(p) -// -// Returns an n < len(p) and err == io.ErrShortWrite. -// -// A thing that can "handle" this situation might try -// writing again, but only what didn't get written. -// -// For a simple example of this: -// -// n, err := w.Write(p) -// -// if io.ErrShortWrite == err { -// n2, err2 := w.Write(p[n:]) -// } -// -// Note that the second call to the Write method passed -// 'p[n:]' (instead of just 'p'), to account for 'n' bytes -// already written (with the first call to the Write -// method). -// -// A more "production quality" version of this would likely -// be in a loop, but such that that loop had "guards" against -// looping forever, and also possibly looping for "too long". -type ShortWriter struct { - buffer bytes.Buffer -} - - -// Write makes it so ShortWriter fits the io.Writer interface. -// -// ShortWriter's version of Write will "short write" if len(p) >= 2, -// else it will -func (w *ShortWriter) Write(p []byte) (int, error) { - if len(p) < 1 { - return 0, nil - } - - m := 1 - if limit := len(p)-1; limit > 1 { - m += randomness.Intn(len(p)-1) - } - - n, err := w.buffer.Write(p[:m]) - - err = nil - if n < len(p) { - err = io.ErrShortWrite - } - - return n, err -} - - -// Returns what was written to the ShortWriter as a []byte. -func (w ShortWriter) Bytes() []byte { - return w.buffer.Bytes() -} - - -// Returns what was written to the ShortWriter as a string. -func (w ShortWriter) String() string { - return w.buffer.String() -} diff --git a/proxy_go/public/go-oi@v1.0.0/test/writes_then_error_writer.go b/proxy_go/public/go-oi@v1.0.0/test/writes_then_error_writer.go deleted file mode 100644 index 2a482f1..0000000 --- a/proxy_go/public/go-oi@v1.0.0/test/writes_then_error_writer.go +++ /dev/null @@ -1,96 +0,0 @@ -package oitest - - -import ( - "bytes" - "io" -) - - -// WritesThenErrorWriter is useful for testing things that makes -// use of or accept an io.Writer. -// -// In particular, it is useful to see if that thing can handle -// an io.Writer that does a "short write". -// -// A "short write" is the case when a call like: -// -// n, err := w.Write(p) -// -// Returns an n < len(p) and err == io.ErrShortWrite. -// -// A thing that can "handle" this situation might try -// writing again, but only what didn't get written. -// -// For a simple example of this: -// -// n, err := w.Write(p) -// -// if io.ErrShortWrite == err { -// n2, err2 := w.Write(p[n:]) -// } -// -// Note that the second call to the Write method passed -// 'p[n:]' (instead of just 'p'), to account for 'n' bytes -// already written (with the first call to the Write -// method). -// -// A more "production quality" version of this would likely -// be in a loop, but such that that loop had "guards" against -// looping forever, and also possibly looping for "too long". -type WritesThenErrorWriter struct { - buffer bytes.Buffer - err error - numbersWritten []int - writeNumber int -} - - -// NewWritesThenErrorWriter returns a new *WritesThenErrorWriter. -func NewWritesThenErrorWriter(err error, numbersWritten ...int) *WritesThenErrorWriter { - - slice := make([]int, len(numbersWritten)) - copy(slice, numbersWritten) - - writer := WritesThenErrorWriter{ - err:err, - numbersWritten:slice, - writeNumber:0, - } - - return &writer -} - - -// Write makes it so *WritesThenErrorWriter fits the io.Writer interface. -// -// *WritesThenErrorWriter's version of Write will "short write" all but -// the last call to write, where it will return the specified error (which -// could, of course, be nil, if that was specified). -func (writer *WritesThenErrorWriter) Write(p []byte) (int, error) { - - m := writer.numbersWritten[writer.writeNumber] - - writer.buffer.Write(p[:m]) - - writer.writeNumber++ - - if len(writer.numbersWritten) == writer.writeNumber { - return m, writer.err - } - - return m, io.ErrShortWrite -} - - -// Returns what was written to the ShortWriter as a []byte. -func (w WritesThenErrorWriter) Bytes() []byte { - return w.buffer.Bytes() -} - - -// Returns what was written to the ShortWriter as a string. -func (w WritesThenErrorWriter) String() string { - return w.buffer.String() -} - diff --git a/proxy_go/public/go-oi@v1.0.0/writenopcloser.go b/proxy_go/public/go-oi@v1.0.0/writenopcloser.go deleted file mode 100644 index 20a1eef..0000000 --- a/proxy_go/public/go-oi@v1.0.0/writenopcloser.go +++ /dev/null @@ -1,38 +0,0 @@ -package oi - - -import ( - "io" -) - - -// WriteNopCloser takes an io.Writer and returns an io.WriteCloser where -// calling the Write method on the returned io.WriterCloser calls the -// Write method on the io.Writer it received, but whre calling the Close -// method on the returned io.WriterCloser does "nothing" (i.e., is a "nop"). -// -// This is useful in cases where an io.WriteCloser is expected, but you -// only have an io.Writer (where closing doesn't make sense) and you -// need to make your io.Writer fit. (I.e., you need an adaptor.) -func WriteNopCloser(w io.Writer) io.WriteCloser { - wc := internalWriteNopCloser{ - writer:w, - } - - return &wc -} - - -type internalWriteNopCloser struct { - writer io.Writer -} - - -func (wc * internalWriteNopCloser) Write(p []byte) (n int, err error) { - return wc.writer.Write(p) -} - - -func (wc * internalWriteNopCloser) Close() error { - return nil -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/LICENSE b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/LICENSE deleted file mode 100644 index aeef12f..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2016 Charles Iliya Krempeaux :: http://changelog.ca/ - -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/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/README.md b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/README.md deleted file mode 100644 index 0083f06..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/README.md +++ /dev/null @@ -1,252 +0,0 @@ -# go-telnet - -Package **telnet** provides TELNET and TELNETS client and server implementations, for the Go programming language. - - -The **telnet** package provides an API in a style similar to the "net/http" library that is part of the Go standard library, including support for "middleware". - - -(TELNETS is *secure TELNET*, with the TELNET protocol over a secured TLS (or SSL) connection.) - - -## Documention - -Online documentation, which includes examples, can be found at: http://godoc.org/github.com/reiver/go-telnet - -[![GoDoc](https://godoc.org/github.com/reiver/go-telnet?status.svg)](https://godoc.org/github.com/reiver/go-telnet) - - -## Very Simple TELNET Server Example - -A very very simple TELNET server is shown in the following code. - -This particular TELNET server just echos back to the user anything they "submit" to the server. - -(By default, a TELNET client does *not* send anything to the server until the [Enter] key is pressed. -"Submit" means typing something and then pressing the [Enter] key.) - -``` -package main - -import ( - "github.com/reiver/go-telnet" -) - -func main() { - - var handler telnet.Handler = telnet.EchoHandler - - err := telnet.ListenAndServe(":5555", handler) - if nil != err { - //@TODO: Handle this error better. - panic(err) - } -} - -``` - -If you wanted to test out this very very simple TELNET server, if you were on the same computer it was -running, you could connect to it using the bash command: -``` -telnet localhost 5555 -``` -(Note that we use the same TCP port number -- "5555" -- as we had in our code. That is important, as the -value used by your TELNET server and the value used by your TELNET client **must** match.) - - -## Very Simple (Secure) TELNETS Server Example - -TELNETS is the secure version of TELNET. - -The code to make a TELNETS server is very similar to the code to make a TELNET server. -(The difference between we use the `telnet.ListenAndServeTLS` func instead of the -`telnet.ListenAndServe` func.) - -``` -package main - -import ( - "github.com/reiver/go-telnet" -) - -func main() { - - var handler telnet.Handler = telnet.EchoHandler - - err := telnet.ListenAndServeTLS(":5555", "cert.pem", "key.pem", handler) - if nil != err { - //@TODO: Handle this error better. - panic(err) - } -} - -``` - -If you wanted to test out this very very simple TELNETS server, get the `telnets` client program from here: -https://github.com/reiver/telnets - - -## TELNET Client Example: -``` -package main - -import ( - "github.com/reiver/go-telnet" -) - -func main() { - var caller telnet.Caller = telnet.StandardCaller - - //@TOOD: replace "example.net:5555" with address you want to connect to. - telnet.DialToAndCall("example.net:5555", caller) -} -``` - - -## TELNETS Client Example: -``` -package main - -import ( - "github.com/reiver/go-telnet" - - "crypto/tls" -) - -func main() { - //@TODO: Configure the TLS connection here, if you need to. - tlsConfig := &tls.Config{} - - var caller telnet.Caller = telnet.StandardCaller - - //@TOOD: replace "example.net:5555" with address you want to connect to. - telnet.DialToAndCallTLS("example.net:5555", caller, tlsConfig) -} -``` - - -## TELNET Shell Server Example - -A more useful TELNET servers can be made using the `"github.com/reiver/go-telnet/telsh"` sub-package. - -For example: -``` -package main - - -import ( - "github.com/reiver/go-oi" - "github.com/reiver/go-telnet" - "github.com/reiver/go-telnet/telsh" - - "io" - "time" -) - - - -func fiveHandler(stdin io.ReadCloser, stdout io.WriteCloser, stderr io.WriteCloser, args ...string) error { - oi.LongWriteString(stdout, "The number FIVE looks like this: 5\r\n") - - return nil -} - -func fiveProducer(ctx telnet.Context, name string, args ...string) telsh.Handler{ - return telsh.PromoteHandlerFunc(fiveHandler) -} - - - -func danceHandler(stdin io.ReadCloser, stdout io.WriteCloser, stderr io.WriteCloser, args ...string) error { - for i:=0; i<20; i++ { - oi.LongWriteString(stdout, "\r⠋") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠙") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠹") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠸") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠼") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠴") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠦") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠧") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠇") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠏") - time.Sleep(50*time.Millisecond) - } - oi.LongWriteString(stdout, "\r \r\n") - - return nil -} - -func danceProducer(ctx telnet.Context, name string, args ...string) telsh.Handler{ - - return telsh.PromoteHandlerFunc(danceHandler) -} - - -func main() { - - shellHandler := telsh.NewShellHandler() - - shellHandler.WelcomeMessage = ` - __ __ ______ _ _____ ____ __ __ ______ - \ \ / /| ____|| | / ____| / __ \ | \/ || ____| - \ \ /\ / / | |__ | | | | | | | || \ / || |__ - \ \/ \/ / | __| | | | | | | | || |\/| || __| - \ /\ / | |____ | |____ | |____ | |__| || | | || |____ - \/ \/ |______||______| \_____| \____/ |_| |_||______| - -` - - - // Register the "five" command. - commandName := "five" - commandProducer := telsh.ProducerFunc(fiveProducer) - - shellHandler.Register(commandName, commandProducer) - - - - // Register the "dance" command. - commandName = "dance" - commandProducer = telsh.ProducerFunc(danceProducer) - - shellHandler.Register(commandName, commandProducer) - - - - shellHandler.Register("dance", telsh.ProducerFunc(danceProducer)) - - addr := ":5555" - if err := telnet.ListenAndServe(addr, shellHandler); nil != err { - panic(err) - } -} -``` - -TELNET servers made using the `"github.com/reiver/go-telnet/telsh"` sub-package will often be more useful -as it makes it easier for you to create a *shell* interface. - - -# More Information - -There is a lot more information about documentation on all this here: http://godoc.org/github.com/reiver/go-telnet - -(You should really read those.) - diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/caller.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/caller.go deleted file mode 100644 index 7895514..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/caller.go +++ /dev/null @@ -1,18 +0,0 @@ -package telnet - - -// A Caller represents the client end of a TELNET (or TELNETS) connection. -// -// Writing data to the Writer passed as an argument to the CallTELNET method -// will send data to the TELNET (or TELNETS) server. -// -// Reading data from the Reader passed as an argument to the CallTELNET method -// will receive data from the TELNET server. -// -// The Writer's Write method sends "escaped" TELNET (and TELNETS) data. -// -// The Reader's Read method "un-escapes" TELNET (and TELNETS) data, and filters -// out TELNET (and TELNETS) command sequences. -type Caller interface { - CallTELNET(Context, Writer, Reader) -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/client.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/client.go deleted file mode 100644 index 39b4d89..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/client.go +++ /dev/null @@ -1,100 +0,0 @@ -package telnet - - -import ( - "crypto/tls" -) - - -func DialAndCall(caller Caller) error { - conn, err := Dial() - if nil != err { - return err - } - - client := &Client{Caller:caller} - - return client.Call(conn) -} - - -func DialToAndCall(srvAddr string, caller Caller) error { - conn, err := DialTo(srvAddr) - if nil != err { - return err - } - - client := &Client{Caller:caller} - - return client.Call(conn) -} - - -func DialAndCallTLS(caller Caller, tlsConfig *tls.Config) error { - conn, err := DialTLS(tlsConfig) - if nil != err { - return err - } - - client := &Client{Caller:caller} - - return client.Call(conn) -} - -func DialToAndCallTLS(srvAddr string, caller Caller, tlsConfig *tls.Config) error { - conn, err := DialToTLS(srvAddr, tlsConfig) - if nil != err { - return err - } - - client := &Client{Caller:caller} - - return client.Call(conn) -} - - -type Client struct { - Caller Caller - - Logger Logger -} - - -func (client *Client) Call(conn *Conn) error { - - logger := client.logger() - - - caller := client.Caller - if nil == caller { - logger.Debug("Defaulted caller to StandardCaller.") - caller = StandardCaller - } - - - var ctx Context = NewContext().InjectLogger(logger) - - var w Writer = conn - var r Reader = conn - - caller.CallTELNET(ctx, w, r) - conn.Close() - - - return nil -} - - -func (client *Client) logger() Logger { - logger := client.Logger - if nil == logger { - logger = internalDiscardLogger{} - } - - return logger -} - - -func (client *Client) SetAuth(username string) { -//@TODO: ################################################# -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/conn.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/conn.go deleted file mode 100644 index 31a9659..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/conn.go +++ /dev/null @@ -1,148 +0,0 @@ -package telnet - - -import ( - "crypto/tls" - "net" -) - - -type Conn struct { - conn interface { - Read(b []byte) (n int, err error) - Write(b []byte) (n int, err error) - Close() error - LocalAddr() net.Addr - RemoteAddr() net.Addr - } - dataReader *internalDataReader - dataWriter *internalDataWriter -} - - -// Dial makes a (un-secure) TELNET client connection to the system's 'loopback address' -// (also known as "localhost" or 127.0.0.1). -// -// If a secure connection is desired, use `DialTLS` instead. -func Dial() (*Conn, error) { - return DialTo("") -} - -// DialTo makes a (un-secure) TELNET client connection to the the address specified by -// 'addr'. -// -// If a secure connection is desired, use `DialToTLS` instead. -func DialTo(addr string) (*Conn, error) { - - const network = "tcp" - - if "" == addr { - addr = "127.0.0.1:telnet" - } - - conn, err := net.Dial(network, addr) - if nil != err { - return nil, err - } - - dataReader := newDataReader(conn) - dataWriter := newDataWriter(conn) - - clientConn := Conn{ - conn:conn, - dataReader:dataReader, - dataWriter:dataWriter, - } - - return &clientConn, nil -} - - -// DialTLS makes a (secure) TELNETS client connection to the system's 'loopback address' -// (also known as "localhost" or 127.0.0.1). -func DialTLS(tlsConfig *tls.Config) (*Conn, error) { - return DialToTLS("", tlsConfig) -} - -// DialToTLS makes a (secure) TELNETS client connection to the the address specified by -// 'addr'. -func DialToTLS(addr string, tlsConfig *tls.Config) (*Conn, error) { - - const network = "tcp" - - if "" == addr { - addr = "127.0.0.1:telnets" - } - - conn, err := tls.Dial(network, addr, tlsConfig) - if nil != err { - return nil, err - } - - dataReader := newDataReader(conn) - dataWriter := newDataWriter(conn) - - clientConn := Conn{ - conn:conn, - dataReader:dataReader, - dataWriter:dataWriter, - } - - return &clientConn, nil -} - - - -// Close closes the client connection. -// -// Typical usage might look like: -// -// telnetsClient, err = telnet.DialToTLS(addr, tlsConfig) -// if nil != err { -// //@TODO: Handle error. -// return err -// } -// defer telnetsClient.Close() -func (clientConn *Conn) Close() error { - return clientConn.conn.Close() -} - - -// Read receives `n` bytes sent from the server to the client, -// and "returns" into `p`. -// -// Note that Read can only be used for receiving TELNET (and TELNETS) data from the server. -// -// TELNET (and TELNETS) command codes cannot be received using this method, as Read deals -// with TELNET (and TELNETS) "unescaping", and (when appropriate) filters out TELNET (and TELNETS) -// command codes. -// -// Read makes Client fit the io.Reader interface. -func (clientConn *Conn) Read(p []byte) (n int, err error) { - return clientConn.dataReader.Read(p) -} - - -// Write sends `n` bytes from 'p' to the server. -// -// Note that Write can only be used for sending TELNET (and TELNETS) data to the server. -// -// TELNET (and TELNETS) command codes cannot be sent using this method, as Write deals with -// TELNET (and TELNETS) "escaping", and will properly "escape" anything written with it. -// -// Write makes Conn fit the io.Writer interface. -func (clientConn *Conn) Write(p []byte) (n int, err error) { - return clientConn.dataWriter.Write(p) -} - - -// LocalAddr returns the local network address. -func (clientConn *Conn) LocalAddr() net.Addr { - return clientConn.conn.LocalAddr() -} - - -// RemoteAddr returns the remote network address. -func (clientConn *Conn) RemoteAddr() net.Addr { - return clientConn.conn.RemoteAddr() -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/context.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/context.go deleted file mode 100644 index 0f8ba94..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/context.go +++ /dev/null @@ -1,31 +0,0 @@ -package telnet - - -type Context interface { - Logger() Logger - - InjectLogger(Logger) Context -} - - -type internalContext struct { - logger Logger -} - - -func NewContext() Context { - ctx := internalContext{} - - return &ctx -} - - -func (ctx *internalContext) Logger() Logger { - return ctx.logger -} - -func (ctx *internalContext) InjectLogger(logger Logger) Context { - ctx.logger = logger - - return ctx -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/data_reader.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/data_reader.go deleted file mode 100644 index 6367df1..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/data_reader.go +++ /dev/null @@ -1,173 +0,0 @@ -package telnet - - -import ( - "bufio" - "errors" - "io" -) - - -var ( - errCorrupted = errors.New("Corrupted") -) - - -// An internalDataReader deals with "un-escaping" according to the TELNET protocol. -// -// In the TELNET protocol byte value 255 is special. -// -// The TELNET protocol calls byte value 255: "IAC". Which is short for "interpret as command". -// -// The TELNET protocol also has a distinction between 'data' and 'commands'. -// -//(DataReader is targetted toward TELNET 'data', not TELNET 'commands'.) -// -// If a byte with value 255 (=IAC) appears in the data, then it must be escaped. -// -// Escaping byte value 255 (=IAC) in the data is done by putting 2 of them in a row. -// -// So, for example: -// -// []byte{255} -> []byte{255, 255} -// -// Or, for a more complete example, if we started with the following: -// -// []byte{1, 55, 2, 155, 3, 255, 4, 40, 255, 30, 20} -// -// ... TELNET escaping would produce the following: -// -// []byte{1, 55, 2, 155, 3, 255, 255, 4, 40, 255, 255, 30, 20} -// -// (Notice that each "255" in the original byte array became 2 "255"s in a row.) -// -// DataReader deals with "un-escaping". In other words, it un-does what was shown -// in the examples. -// -// So, for example, it does this: -// -// []byte{255, 255} -> []byte{255} -// -// And, for example, goes from this: -// -// []byte{1, 55, 2, 155, 3, 255, 255, 4, 40, 255, 255, 30, 20} -// -// ... to this: -// -// []byte{1, 55, 2, 155, 3, 255, 4, 40, 255, 30, 20} -type internalDataReader struct { - wrapped io.Reader - buffered *bufio.Reader -} - - -// newDataReader creates a new DataReader reading from 'r'. -func newDataReader(r io.Reader) *internalDataReader { - buffered := bufio.NewReader(r) - - reader := internalDataReader{ - wrapped:r, - buffered:buffered, - } - - return &reader -} - - -// Read reads the TELNET escaped data from the wrapped io.Reader, and "un-escapes" it into 'data'. -func (r *internalDataReader) Read(data []byte) (n int, err error) { - - const IAC = 255 - - const SB = 250 - const SE = 240 - - const WILL = 251 - const WONT = 252 - const DO = 253 - const DONT = 254 - - p := data - - for len(p) > 0 { - var b byte - - b, err = r.buffered.ReadByte() - if nil != err { - return n, err - } - - if IAC == b { - var peeked []byte - - peeked, err = r.buffered.Peek(1) - if nil != err { - return n, err - } - - switch peeked[0] { - case WILL, WONT, DO, DONT: - _, err = r.buffered.Discard(2) - if nil != err { - return n, err - } - case IAC: - p[0] = IAC - n++ - p = p[1:] - - _, err = r.buffered.Discard(1) - if nil != err { - return n, err - } - case SB: - for { - var b2 byte - b2, err = r.buffered.ReadByte() - if nil != err { - return n, err - } - - if IAC == b2 { - peeked, err = r.buffered.Peek(1) - if nil != err { - return n, err - } - - if IAC == peeked[0] { - _, err = r.buffered.Discard(1) - if nil != err { - return n, err - } - } - - if SE == peeked[0] { - _, err = r.buffered.Discard(1) - if nil != err { - return n, err - } - break - } - } - } - case SE: - _, err = r.buffered.Discard(1) - if nil != err { - return n, err - } - default: - // If we get in here, this is not following the TELNET protocol. -//@TODO: Make a better error. - err = errCorrupted - return n, err - } - } else { - - p[0] = b - n++ - p = p[1:] - } - } - - return n, nil -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/data_reader_test.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/data_reader_test.go deleted file mode 100644 index f1d942d..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/data_reader_test.go +++ /dev/null @@ -1,353 +0,0 @@ -package telnet - - -import ( - "bytes" - "io" - - "testing" -) - - -func TestDataReader(t *testing.T) { - - tests := []struct{ - Bytes []byte - Expected []byte - }{ - { - Bytes: []byte{}, - Expected: []byte{}, - }, - - - - { - Bytes: []byte("a"), - Expected: []byte("a"), - }, - { - Bytes: []byte("b"), - Expected: []byte("b"), - }, - { - Bytes: []byte("c"), - Expected: []byte("c"), - }, - - - - { - Bytes: []byte("apple"), - Expected: []byte("apple"), - }, - { - Bytes: []byte("banana"), - Expected: []byte("banana"), - }, - { - Bytes: []byte("cherry"), - Expected: []byte("cherry"), - }, - - - - { - Bytes: []byte("apple banana cherry"), - Expected: []byte("apple banana cherry"), - }, - - - - { - Bytes: []byte{255,255}, - Expected: []byte{255}, - }, - { - Bytes: []byte{255,255,255,255}, - Expected: []byte{255,255}, - }, - { - Bytes: []byte{255,255,255,255,255,255}, - Expected: []byte{255,255,255}, - }, - { - Bytes: []byte{255,255,255,255,255,255,255,255}, - Expected: []byte{255,255,255,255}, - }, - { - Bytes: []byte{255,255,255,255,255,255,255,255,255,255}, - Expected: []byte{255,255,255,255,255}, - }, - - - - { - Bytes: []byte("apple\xff\xffbanana\xff\xffcherry"), - Expected: []byte("apple\xffbanana\xffcherry"), - }, - { - Bytes: []byte("\xff\xffapple\xff\xffbanana\xff\xffcherry\xff\xff"), - Expected: []byte("\xffapple\xffbanana\xffcherry\xff"), - }, - - - - - { - Bytes: []byte("apple\xff\xff\xff\xffbanana\xff\xff\xff\xffcherry"), - Expected: []byte("apple\xff\xffbanana\xff\xffcherry"), - }, - { - Bytes: []byte("\xff\xff\xff\xffapple\xff\xff\xff\xffbanana\xff\xff\xff\xffcherry\xff\xff\xff\xff"), - Expected: []byte("\xff\xffapple\xff\xffbanana\xff\xffcherry\xff\xff"), - }, - - - - { - Bytes: []byte{255,251,24}, // IAC WILL TERMINAL-TYPE - Expected: []byte{}, - }, - { - Bytes: []byte{255,252,24}, // IAC WON'T TERMINAL-TYPE - Expected: []byte{}, - }, - { - Bytes: []byte{255,253,24}, // IAC DO TERMINAL-TYPE - Expected: []byte{}, - }, - { - Bytes: []byte{255,254,24}, // IAC DON'T TERMINAL-TYPE - Expected: []byte{}, - }, - - - - { - Bytes: []byte{67, 255,251,24}, // 'C' IAC WILL TERMINAL-TYPE - Expected: []byte{67}, - }, - { - Bytes: []byte{67, 255,252,24}, // 'C' IAC WON'T TERMINAL-TYPE - Expected: []byte{67}, - }, - { - Bytes: []byte{67, 255,253,24}, // 'C' IAC DO TERMINAL-TYPE - Expected: []byte{67}, - }, - { - Bytes: []byte{67, 255,254,24}, // 'C' IAC DON'T TERMINAL-TYPE - Expected: []byte{67}, - }, - - - - { - Bytes: []byte{255,251,24, 68}, // IAC WILL TERMINAL-TYPE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{255,252,24, 68}, // IAC WON'T TERMINAL-TYPE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{255,253,24, 68}, // IAC DO TERMINAL-TYPE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{255,254,24, 68}, // IAC DON'T TERMINAL-TYPE 'D' - Expected: []byte{68}, - }, - - - { - Bytes: []byte{67, 255,251,24, 68}, // 'C' IAC WILL TERMINAL-TYPE 'D' - Expected: []byte{67,68}, - }, - { - Bytes: []byte{67, 255,252,24, 68}, // 'C' IAC WON'T TERMINAL-TYPE 'D' - Expected: []byte{67,68}, - }, - { - Bytes: []byte{67, 255,253,24, 68}, // 'C' IAC DO TERMINAL-TYPE 'D' - Expected: []byte{67,68}, - }, - { - Bytes: []byte{67, 255,254,24, 68}, // 'C' IAC DON'T TERMINAL-TYPE 'D' - Expected: []byte{67,68}, - }, - - - - { - Bytes: []byte{255, 250, 24, 1, 255, 240}, // IAC SB TERMINAL-TYPE SEND IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{255, 250, 24, 0, 68,69,67,45,86,84,53,50 ,255, 240}, // IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE - Expected: []byte{}, - }, - - - - { - Bytes: []byte{67, 255, 250, 24, 1, 255, 240}, // 'C' IAC SB TERMINAL-TYPE SEND IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{67, 255, 250, 24, 0, 68,69,67,45,86,84,53,50 ,255, 240}, // 'C' IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE - Expected: []byte{67}, - }, - - - - { - Bytes: []byte{255, 250, 24, 1, 255, 240, 68}, // IAC SB TERMINAL-TYPE SEND IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{255, 250, 24, 0, 68,69,67,45,86,84,53,50 ,255, 240, 68}, // IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE 'D' - Expected: []byte{68}, - }, - - - - { - Bytes: []byte{67, 255, 250, 24, 1, 255, 240, 68}, // 'C' IAC SB TERMINAL-TYPE SEND IAC SE 'D' - Expected: []byte{67, 68}, - }, - { - Bytes: []byte{67, 255, 250, 24, 0, 68,69,67,45,86,84,53,50 ,255, 240, 68}, // 'C' IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE 'D' - Expected: []byte{67, 68}, - }, - - - - { - Bytes: []byte{255,250, 0,1,2,3,4,5,6,7,8,9,10,11,12,13 ,255,240}, // IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,250, 0,1,2,3,4,5,6,7,8,9,10,11,12,13 ,255,240}, // 'C' IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{255,250, 0,1,2,3,4,5,6,7,8,9,10,11,12,13 ,255,240, 68}, // IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{67, 255,250, 0,1,2,3,4,5,6,7,8,9,10,11,12,13 ,255,240, 68}, // 'C' IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE 'D' - Expected: []byte{67,68}, - }, - - - -//@TODO: Is this correct? Can IAC appear between thee 'IAC SB' and ''IAC SE'?... and if "yes", do escaping rules apply? - { - Bytes: []byte{ 255,250, 255,255,240 ,255,240}, // IAC SB 255 255 240 IAC SE = IAC SB IAC IAC SE IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,250, 255,255,240 ,255,240}, // 'C' IAC SB 255 255 240 IAC SE = IAC SB IAC IAC SE IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{ 255,250, 255,255,240 ,255,240, 68}, // IAC SB 255 255 240 IAC SE = IAC SB IAC IAC SE IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{67, 255,250, 255,255,240 ,255,240, 68}, // 'C' IAC SB 255 255 240 IAC SE = IAC SB IAC IAC SE IAC SE 'D' - Expected: []byte{67,68}, - }, - - - -//@TODO: Is this correct? Can IAC appear between thee 'IAC SB' and ''IAC SE'?... and if "yes", do escaping rules apply? - { - Bytes: []byte{ 255,250, 71,255,255,240 ,255,240}, // IAC SB 'G' 255 255 240 IAC SE = IAC SB 'G' IAC IAC SE IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,250, 71,255,255,240 ,255,240}, // 'C' IAC SB 'G' 255 255 240 IAC SE = IAC SB 'G' IAC IAC SE IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{ 255,250, 71,255,255,240 ,255,240, 68}, // IAC SB 'G' 255 255 240 IAC SE = IAC SB 'G' IAC IAC SE IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{67, 255,250, 71,255,255,240 ,255,240, 68}, // 'C' IAC SB 'G' 255 255 240 IAC SE = IAC 'G' SB IAC IAC SE IAC SE 'D' - Expected: []byte{67,68}, - }, - - - -//@TODO: Is this correct? Can IAC appear between thee 'IAC SB' and ''IAC SE'?... and if "yes", do escaping rules apply? - { - Bytes: []byte{ 255,250, 255,255,240,72 ,255,240}, // IAC SB 255 255 240 'H' IAC SE = IAC SB IAC IAC SE 'H' IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,250, 255,255,240,72 ,255,240}, // 'C' IAC SB 255 255 240 'H' IAC SE = IAC SB IAC IAC SE 'H' IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{ 255,250, 255,255,240,72 ,255,240, 68}, // IAC SB 255 255 240 'H' IAC SE = IAC SB IAC IAC SE 'H' IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{67, 255,250, 255,255,240,72 ,255,240, 68}, // 'C' IAC SB 255 255 240 'H' IAC SE = IAC SB IAC IAC SE 'H' IAC SE 'D' - Expected: []byte{67,68}, - }, - - - -//@TODO: Is this correct? Can IAC appear between thee 'IAC SB' and ''IAC SE'?... and if "yes", do escaping rules apply? - { - Bytes: []byte{ 255,250, 71,255,255,240,72 ,255,240}, // IAC SB 'G' 255 255 240 'H' IAC SE = IAC SB 'G' IAC IAC SE 'H' IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,250, 71,255,255,240,72 ,255,240}, // 'C' IAC SB 'G' 255 255 240 'H' IAC SE = IAC SB 'G' IAC IAC SE 'H' IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{ 255,250, 71,255,255,240,72 ,255,240, 68}, // IAC SB 'G' 255 255 240 'H' IAC SE = IAC SB 'G' IAC IAC SE 'H' IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{67, 255,250, 71,255,255,240,72 ,255,240, 68}, // 'C' IAC SB 'G' 255 255 240 'H' IAC SE = IAC 'G' SB IAC IAC SE 'H' IAC SE 'D' - Expected: []byte{67,68}, - }, - - - } - -//@TODO: Add random tests. - - - for testNumber, test := range tests { - - subReader := bytes.NewReader(test.Bytes) - - reader := newDataReader(subReader) - - buffer := make([]byte, 2*len(test.Bytes)) - n, err := reader.Read(buffer) - if nil != err && io.EOF != err { - t.Errorf("For test #%d, did not expected an error, but actually got one: (%T) %v; for %q -> %q.", testNumber, err, err, string(test.Bytes), string(test.Expected)) - continue - } - - if expected, actual := len(test.Expected), n; expected != actual { - t.Errorf("For test #%d, expected %d, but actually got %d (and %q); for %q -> %q.", testNumber, expected, actual, string(buffer[:n]), string(test.Bytes), string(test.Expected)) - continue - } - - if expected, actual := string(test.Expected), string(buffer[:n]); expected != actual { - t.Errorf("For test #%d, expected %q, but actually got %q; for %q -> %q.", testNumber, expected, actual, string(test.Bytes), string(test.Expected)) - continue - } - } -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/data_writer.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/data_writer.go deleted file mode 100644 index af99557..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/data_writer.go +++ /dev/null @@ -1,142 +0,0 @@ -package telnet - - -import ( - "github.com/reiver/go-oi" - - "bytes" - "errors" - "io" -) - - -var iaciac []byte = []byte{255, 255} - -var errOverflow = errors.New("Overflow") -var errPartialIACIACWrite = errors.New("Partial IAC IAC write.") - - -// An internalDataWriter deals with "escaping" according to the TELNET (and TELNETS) protocol. -// -// In the TELNET (and TELNETS) protocol byte value 255 is special. -// -// The TELNET (and TELNETS) protocol calls byte value 255: "IAC". Which is short for "interpret as command". -// -// The TELNET (and TELNETS) protocol also has a distinction between 'data' and 'commands'. -// -//(DataWriter is targetted toward TELNET (and TELNETS) 'data', not TELNET (and TELNETS) 'commands'.) -// -// If a byte with value 255 (=IAC) appears in the data, then it must be escaped. -// -// Escaping byte value 255 (=IAC) in the data is done by putting 2 of them in a row. -// -// So, for example: -// -// []byte{255} -> []byte{255, 255} -// -// Or, for a more complete example, if we started with the following: -// -// []byte{1, 55, 2, 155, 3, 255, 4, 40, 255, 30, 20} -// -// ... TELNET escaping would produce the following: -// -// []byte{1, 55, 2, 155, 3, 255, 255, 4, 40, 255, 255, 30, 20} -// -// (Notice that each "255" in the original byte array became 2 "255"s in a row.) -// -// internalDataWriter takes care of all this for you, so you do not have to do it. -type internalDataWriter struct { - wrapped io.Writer -} - - -// newDataWriter creates a new internalDataWriter writing to 'w'. -// -// 'w' receives what is written to the *internalDataWriter but escaped according to -// the TELNET (and TELNETS) protocol. -// -// I.e., byte 255 (= IAC) gets encoded as 255, 255. -// -// For example, if the following it written to the *internalDataWriter's Write method: -// -// []byte{1, 55, 2, 155, 3, 255, 4, 40, 255, 30, 20} -// -// ... then (conceptually) the following is written to 'w's Write method: -// -// []byte{1, 55, 2, 155, 3, 255, 255, 4, 40, 255, 255, 30, 20} -// -// (Notice that each "255" in the original byte array became 2 "255"s in a row.) -// -// *internalDataWriter takes care of all this for you, so you do not have to do it. -func newDataWriter(w io.Writer) *internalDataWriter { - writer := internalDataWriter{ - wrapped:w, - } - - return &writer -} - - -// Write writes the TELNET (and TELNETS) escaped data for of the data in 'data' to the wrapped io.Writer. -func (w *internalDataWriter) Write(data []byte) (n int, err error) { - var n64 int64 - - n64, err = w.write64(data) - n = int(n64) - if int64(n) != n64 { - panic(errOverflow) - } - - return n, err -} - - -func (w *internalDataWriter) write64(data []byte) (n int64, err error) { - - if len(data) <= 0 { - return 0, nil - } - - const IAC = 255 - - var buffer bytes.Buffer - for _, datum := range data { - - if IAC == datum { - - if buffer.Len() > 0 { - var numWritten int64 - - numWritten, err = oi.LongWrite(w.wrapped, buffer.Bytes()) - n += numWritten - if nil != err { - return n, err - } - buffer.Reset() - } - - - var numWritten int64 - //@TODO: Should we worry about "iaciac" potentially being modified by the .Write()? - numWritten, err = oi.LongWrite(w.wrapped, iaciac) - if int64(len(iaciac)) != numWritten { - //@TODO: Do we really want to panic() here? - panic(errPartialIACIACWrite) - } - n += 1 - if nil != err { - return n, err - } - } else { - buffer.WriteByte(datum) // The returned error is always nil, so we ignore it. - } - } - - if buffer.Len() > 0 { - var numWritten int64 - numWritten, err = oi.LongWrite(w.wrapped, buffer.Bytes()) - n += numWritten - } - - return n, err -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/data_writer_test.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/data_writer_test.go deleted file mode 100644 index 0a3e199..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/data_writer_test.go +++ /dev/null @@ -1,116 +0,0 @@ -package telnet - - -import ( - "bytes" - - "testing" -) - - -func TestDataWriter(t *testing.T) { - - tests := []struct{ - Bytes []byte - Expected []byte - }{ - { - Bytes: []byte{}, - Expected: []byte{}, - }, - - - - { - Bytes: []byte("apple"), - Expected: []byte("apple"), - }, - { - Bytes: []byte("banana"), - Expected: []byte("banana"), - }, - { - Bytes: []byte("cherry"), - Expected: []byte("cherry"), - }, - - - - { - Bytes: []byte("apple banana cherry"), - Expected: []byte("apple banana cherry"), - }, - - - - { - Bytes: []byte{255}, - Expected: []byte{255,255}, - }, - { - Bytes: []byte{255,255}, - Expected: []byte{255,255,255,255}, - }, - { - Bytes: []byte{255,255,255}, - Expected: []byte{255,255,255,255,255,255}, - }, - { - Bytes: []byte{255,255,255,255}, - Expected: []byte{255,255,255,255,255,255,255,255}, - }, - { - Bytes: []byte{255,255,255,255,255}, - Expected: []byte{255,255,255,255,255,255,255,255,255,255}, - }, - - - - { - Bytes: []byte("apple\xffbanana\xffcherry"), - Expected: []byte("apple\xff\xffbanana\xff\xffcherry"), - }, - { - Bytes: []byte("\xffapple\xffbanana\xffcherry\xff"), - Expected: []byte("\xff\xffapple\xff\xffbanana\xff\xffcherry\xff\xff"), - }, - - - - - { - Bytes: []byte("apple\xff\xffbanana\xff\xffcherry"), - Expected: []byte("apple\xff\xff\xff\xffbanana\xff\xff\xff\xffcherry"), - }, - { - Bytes: []byte("\xff\xffapple\xff\xffbanana\xff\xffcherry\xff\xff"), - Expected: []byte("\xff\xff\xff\xffapple\xff\xff\xff\xffbanana\xff\xff\xff\xffcherry\xff\xff\xff\xff"), - }, - } - -//@TODO: Add random tests. - - - for testNumber, test := range tests { - - subWriter := new(bytes.Buffer) - - writer := newDataWriter(subWriter) - - n, err := writer.Write(test.Bytes) - if nil != err { - t.Errorf("For test #%d, did not expected an error, but actually got one: (%T) %v; for %q -> %q.", testNumber, err, err, string(test.Bytes), string(test.Expected)) - continue - } - - if expected, actual := len(test.Bytes), n; expected != actual { - t.Errorf("For test #%d, expected %d, but actually got %d; for %q -> %q.", testNumber, expected, actual, string(test.Bytes), string(test.Expected)) - continue - } - - if expected, actual := string(test.Expected), subWriter.String(); expected != actual { - t.Errorf("For test #%d, expected %q, but actually got %q; for %q -> %q.", testNumber, expected, actual, string(test.Bytes), string(test.Expected)) - continue - } - } -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/discard_logger.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/discard_logger.go deleted file mode 100644 index c334926..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/discard_logger.go +++ /dev/null @@ -1,21 +0,0 @@ -package telnet - - -type internalDiscardLogger struct{} - -func (internalDiscardLogger) Debug(...interface{}) {} -func (internalDiscardLogger) Debugf(string, ...interface{}) {} -func (internalDiscardLogger) Debugln(...interface{}) {} - -func (internalDiscardLogger) Error(...interface{}) {} -func (internalDiscardLogger) Errorf(string, ...interface{}) {} -func (internalDiscardLogger) Errorln(...interface{}) {} - -func (internalDiscardLogger) Trace(...interface{}) {} -func (internalDiscardLogger) Tracef(string, ...interface{}) {} -func (internalDiscardLogger) Traceln(...interface{}) {} - -func (internalDiscardLogger) Warn(...interface{}) {} -func (internalDiscardLogger) Warnf(string, ...interface{}) {} -func (internalDiscardLogger) Warnln(...interface{}) {} - diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/doc.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/doc.go deleted file mode 100644 index 2d3681f..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/doc.go +++ /dev/null @@ -1,450 +0,0 @@ -/* -Package telnet provides TELNET and TELNETS client and server implementations -in a style similar to the "net/http" library that is part of the Go standard library, -including support for "middleware"; TELNETS is secure TELNET, with the TELNET protocol -over a secured TLS (or SSL) connection. - - -Example TELNET Server - -ListenAndServe starts a (un-secure) TELNET server with a given address and handler. - - handler := telnet.EchoHandler - - err := telnet.ListenAndServe(":23", handler) - if nil != err { - panic(err) - } - - -Example TELNETS Server - -ListenAndServeTLS starts a (secure) TELNETS server with a given address and handler, -using the specified "cert.pem" and "key.pem" files. - - handler := telnet.EchoHandler - - err := telnet.ListenAndServeTLS(":992", "cert.pem", "key.pem", handler) - if nil != err { - panic(err) - } - - -Example TELNET Client: - -DialToAndCall creates a (un-secure) TELNET client, which connects to a given address using the specified caller. - - package main - - import ( - "github.com/reiver/go-telnet" - ) - - func main() { - var caller telnet.Caller = telnet.StandardCaller - - //@TOOD: replace "example.net:23" with address you want to connect to. - telnet.DialToAndCall("example.net:23", caller) - } - - -Example TELNETS Client: - -DialToAndCallTLS creates a (secure) TELNETS client, which connects to a given address using the specified caller. - - package main - - import ( - "github.com/reiver/go-telnet" - - "crypto/tls" - ) - - func main() { - //@TODO: Configure the TLS connection here, if you need to. - tlsConfig := &tls.Config{} - - var caller telnet.Caller = telnet.StandardCaller - - //@TOOD: replace "example.net:992" with address you want to connect to. - telnet.DialToAndCallTLS("example.net:992", caller, tlsConfig) - } - - -TELNET vs TELNETS - -If you are communicating over the open Internet, you should be using (the secure) TELNETS protocol and ListenAndServeTLS. - -If you are communicating just on localhost, then using just (the un-secure) TELNET protocol and telnet.ListenAndServe may be OK. - -If you are not sure which to use, use TELNETS and ListenAndServeTLS. - - -Example TELNET Shell Server - -The previous 2 exaple servers were very very simple. Specifically, they just echoed back whatever -you submitted to it. - -If you typed: - - Apple Banana Cherry\r\n - -... it would send back: - - Apple Banana Cherry\r\n - -(Exactly the same data you sent it.) - -A more useful TELNET server can be made using the "github.com/reiver/go-telnet/telsh" sub-package. - -The `telsh` sub-package provides "middleware" that enables you to create a "shell" interface (also -called a "command line interface" or "CLI") which most people would expect when using TELNET OR TELNETS. - -For example: - - - package main - - - import ( - "github.com/reiver/go-oi" - "github.com/reiver/go-telnet" - "github.com/reiver/go-telnet/telsh" - - "time" - ) - - - func main() { - - shellHandler := telsh.NewShellHandler() - - commandName := "date" - shellHandler.Register(commandName, danceProducer) - - commandName = "animate" - shellHandler.Register(commandName, animateProducer) - - addr := ":23" - if err := telnet.ListenAndServe(addr, shellHandler); nil != err { - panic(err) - } - } - -Note that in the example, so far, we have registered 2 commands: `date` and `animate`. - -For this to actually work, we need to have code for the `date` and `animate` commands. - -The actual implemenation for the `date` command could be done like the following: - - func dateHandlerFunc(stdin io.ReadCloser, stdout io.WriteCloser, stderr io.WriteCloser, args ...string) error { - const layout = "Mon Jan 2 15:04:05 -0700 MST 2006" - s := time.Now().Format(layout) - - if _, err := oi.LongWriteString(stdout, s); nil != err { - return err - } - - return nil - } - - - func dateProducerFunc(ctx telnet.Context, name string, args ...string) telsh.Handler{ - return telsh.PromoteHandlerFunc(dateHandler) - } - - - var dateProducer = ProducerFunc(dateProducerFunc) - -Note that your "real" work is in the `dateHandlerFunc` func. - -And the actual implementation for the `animate` command could be done as follows: - - func animateHandlerFunc(stdin io.ReadCloser, stdout io.WriteCloser, stderr io.WriteCloser, args ...string) error { - - for i:=0; i<20; i++ { - oi.LongWriteString(stdout, "\r⠋") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠙") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠹") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠸") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠼") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠴") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠦") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠧") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠇") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠏") - time.Sleep(50*time.Millisecond) - } - oi.LongWriteString(stdout, "\r \r\n") - - return nil - } - - - func animateProducerFunc(ctx telnet.Context, name string, args ...string) telsh.Handler{ - return telsh.PromoteHandlerFunc(animateHandler) - } - - - var animateProducer = ProducerFunc(animateProducerFunc) - -Again, note that your "real" work is in the `animateHandlerFunc` func. - -Generating PEM Files - -If you are using the telnet.ListenAndServeTLS func or the telnet.Server.ListenAndServeTLS method, you will need to -supply "cert.pem" and "key.pem" files. - -If you do not already have these files, the Go soure code contains a tool for generating these files for you. - -It can be found at: - - $GOROOT/src/crypto/tls/generate_cert.go - -So, for example, if your `$GOROOT` is the "/usr/local/go" directory, then it would be at: - - /usr/local/go/src/crypto/tls/generate_cert.go - -If you run the command: - - go run $GOROOT/src/crypto/tls/generate_cert.go --help - -... then you get the help information for "generate_cert.go". - -Of course, you would replace or set `$GOROOT` with whatever your path actually is. Again, for example, -if your `$GOROOT` is the "/usr/local/go" directory, then it would be: - - go run /usr/local/go/src/crypto/tls/generate_cert.go --help - -To demonstrate the usage of "generate_cert.go", you might run the following to generate certificates -that were bound to the hosts `127.0.0.1` and `localhost`: - - go run /usr/local/go/src/crypto/tls/generate_cert.go --ca --host='127.0.0.1,localhost' - - -If you are not sure where "generate_cert.go" is on your computer, on Linux and Unix based systems, you might -be able to find the file with the command: - - locate /src/crypto/tls/generate_cert.go - -(If it finds it, it should output the full path to this file.) - - -Example TELNET Client - -You can make a simple (un-secure) TELNET client with code like the following: - - package main - - - import ( - "github.com/reiver/go-telnet" - ) - - - func main() { - var caller telnet.Caller = telnet.StandardCaller - - //@TOOD: replace "example.net:5555" with address you want to connect to. - telnet.DialToAndCall("example.net:5555", caller) - } - - -Example TELNETS Client - -You can make a simple (secure) TELNETS client with code like the following: - - package main - - - import ( - "github.com/reiver/go-telnet" - ) - - - func main() { - var caller telnet.Caller = telnet.StandardCaller - - //@TOOD: replace "example.net:5555" with address you want to connect to. - telnet.DialToAndCallTLS("example.net:5555", caller) - } - - -TELNET Story - -The TELNET protocol is best known for providing a means of connecting to a remote computer, using a (text-based) shell interface, and being able to interact with it, (more or less) as if you were sitting at that computer. - -(Shells are also known as command-line interfaces or CLIs.) - -Although this was the original usage of the TELNET protocol, it can be (and is) used for other purposes as well. - - -The Era - -The TELNET protocol came from an era in computing when text-based shell interface where the common way of interacting with computers. - -The common interface for computers during this era was a keyboard and a monochromatic (i.e., single color) text-based monitors called "video terminals". - -(The word "video" in that era of computing did not refer to things such as movies. But instead was meant to contrast it with paper. In particular, the teletype machines, which were typewriter like devices that had a keyboard, but instead of having a monitor had paper that was printed onto.) - - -Early Office Computers - -In that era, in the early days of office computers, it was rare that an individual would have a computer at their desk. (A single computer was much too expensive.) - -Instead, there would be a single central computer that everyone would share. The style of computer used (for the single central shared computer) was called a "mainframe". - -What individuals would have at their desks, instead of their own compuer, would be some type of video terminal. - -The different types of video terminals had named such as: - -• VT52 - -• VT100 - -• VT220 - -• VT240 - -("VT" in those named was short for "video terminal".) - - -Teletype - -To understand this era, we need to go back a bit in time to what came before it: teletypes. - - -Terminal Codes - -Terminal codes (also sometimes called 'terminal control codes') are used to issue various kinds of commands -to the terminal. - -(Note that 'terminal control codes' are a completely separate concept for 'TELNET commands', -and the two should NOT be conflated or confused.) - -The most common types of 'terminal codes' are the 'ANSI escape codes'. (Although there are other types too.) - - -ANSI Escape Codes - -ANSI escape codes (also sometimes called 'ANSI escape sequences') are a common type of 'terminal code' used -to do things such as: - -• moving the cursor, - -• erasing the display, - -• erasing the line, - -• setting the graphics mode, - -• setting the foregroup color, - -• setting the background color, - -• setting the screen resolution, and - -• setting keyboard strings. - - -Setting The Foreground Color With ANSI Escape Codes - -One of the abilities of ANSI escape codes is to set the foreground color. - -Here is a table showing codes for this: - - | ANSI Color | Go string | Go []byte | - | ------------ | ---------- | ----------------------------- | - | Black | "\x1b[30m" | []byte{27, '[', '3','0', 'm'} | - | Red | "\x1b[31m" | []byte{27, '[', '3','1', 'm'} | - | Green | "\x1b[32m" | []byte{27, '[', '3','2', 'm'} | - | Brown/Yellow | "\x1b[33m" | []byte{27, '[', '3','3', 'm'} | - | Blue | "\x1b[34m" | []byte{27, '[', '3','4', 'm'} | - | Magenta | "\x1b[35m" | []byte{27, '[', '3','5', 'm'} | - | Cyan | "\x1b[36m" | []byte{27, '[', '3','6', 'm'} | - | Gray/White | "\x1b[37m" | []byte{27, '[', '3','7', 'm'} | - -(Note that in the `[]byte` that the first `byte` is the number `27` (which -is the "escape" character) where the third and fouth characters are the -**not** number literals, but instead character literals `'3'` and whatever.) - - -Setting The Background Color With ANSI Escape Codes - -Another of the abilities of ANSI escape codes is to set the background color. - - | ANSI Color | Go string | Go []byte | - | ------------ | ---------- | ----------------------------- | - | Black | "\x1b[40m" | []byte{27, '[', '4','0', 'm'} | - | Red | "\x1b[41m" | []byte{27, '[', '4','1', 'm'} | - | Green | "\x1b[42m" | []byte{27, '[', '4','2', 'm'} | - | Brown/Yellow | "\x1b[43m" | []byte{27, '[', '4','3', 'm'} | - | Blue | "\x1b[44m" | []byte{27, '[', '4','4', 'm'} | - | Magenta | "\x1b[45m" | []byte{27, '[', '4','5', 'm'} | - | Cyan | "\x1b[46m" | []byte{27, '[', '4','6', 'm'} | - | Gray/White | "\x1b[47m" | []byte{27, '[', '4','7', 'm'} | - -(Note that in the `[]byte` that the first `byte` is the number `27` (which -is the "escape" character) where the third and fouth characters are the -**not** number literals, but instead character literals `'4'` and whatever.) - -Using ANSI Escape Codes - -In Go code, if I wanted to use an ANSI escape code to use a blue background, -a white foreground, and bold, I could do that with the ANSI escape code: - - "\x1b[44;37;1m" - -Note that that start with byte value 27, which we have encoded as hexadecimal -as \x1b. Followed by the '[' character. - -Coming after that is the sub-string "44", which is the code that sets our background color to blue. - -We follow that with the ';' character (which separates codes). - -And the after that comes the sub-string "37", which is the code that set our foreground color to white. - -After that, we follow with another ";" character (which, again, separates codes). - -And then we follow it the sub-string "1", which is the code that makes things bold. - -And finally, the ANSI escape sequence is finished off with the 'm' character. - -To show this in a more complete example, our `dateHandlerFunc` from before could incorporate ANSI escape sequences as follows: - - func dateHandlerFunc(stdin io.ReadCloser, stdout io.WriteCloser, stderr io.WriteCloser, args ...string) error { - const layout = "Mon Jan 2 15:04:05 -0700 MST 2006" - s := "\x1b[44;37;1m" + time.Now().Format(layout) + "\x1b[0m" - - if _, err := oi.LongWriteString(stdout, s); nil != err { - return err - } - - return nil - } - -Note that in that example, in addition to using the ANSI escape sequence "\x1b[44;37;1m" -to set the background color to blue, set the foreground color to white, and make it bold, -we also used the ANSI escape sequence "\x1b[0m" to reset the background and foreground colors -and boldness back to "normal". - -*/ -package telnet diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/echo_handler.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/echo_handler.go deleted file mode 100644 index 0401009..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/echo_handler.go +++ /dev/null @@ -1,33 +0,0 @@ -package telnet - - -import ( - "github.com/reiver/go-oi" -) - - -// EchoHandler is a simple TELNET server which "echos" back to the client any (non-command) -// data back to the TELNET client, it received from the TELNET client. -var EchoHandler Handler = internalEchoHandler{} - - -type internalEchoHandler struct{} - - -func (handler internalEchoHandler) ServeTELNET(ctx Context, w Writer, r Reader) { - - var buffer [1]byte // Seems like the length of the buffer needs to be small, otherwise will have to wait for buffer to fill up. - p := buffer[:] - - for { - n, err := r.Read(p) - - if n > 0 { - oi.LongWrite(w, p[:n]) - } - - if nil != err { - break - } - } -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/echo_handler_test.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/echo_handler_test.go deleted file mode 100644 index b5c3a10..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/echo_handler_test.go +++ /dev/null @@ -1,339 +0,0 @@ -package telnet - - -import ( - "bytes" - - "testing" -) - - -func TestEchoHandler(t *testing.T) { - - tests := []struct{ - Bytes []byte - Expected []byte - }{ - { - Bytes: []byte{}, - Expected: []byte{}, - }, - - - - { - Bytes: []byte("a"), - Expected: []byte("a"), - }, - { - Bytes: []byte("b"), - Expected: []byte("b"), - }, - { - Bytes: []byte("c"), - Expected: []byte("c"), - }, - - - - { - Bytes: []byte("apple"), - Expected: []byte("apple"), - }, - { - Bytes: []byte("banana"), - Expected: []byte("banana"), - }, - { - Bytes: []byte("cherry"), - Expected: []byte("cherry"), - }, - - - - { - Bytes: []byte("apple banana cherry"), - Expected: []byte("apple banana cherry"), - }, - - - - { - Bytes: []byte{255, 255}, - Expected: []byte{255, 255}, - }, - { - Bytes: []byte{255, 255, 255, 255}, - Expected: []byte{255, 255, 255, 255}, - }, - { - Bytes: []byte{255, 255, 255, 255, 255, 255}, - Expected: []byte{255, 255, 255, 255, 255, 255}, - }, - { - Bytes: []byte{255, 255, 255, 255, 255, 255, 255, 255}, - Expected: []byte{255, 255, 255, 255, 255, 255, 255, 255}, - }, - { - Bytes: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, - Expected: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, - }, - - - - { - Bytes: []byte("apple\xff\xffbanana\xff\xffcherry"), - Expected: []byte("apple\xff\xffbanana\xff\xffcherry"), - }, - { - Bytes: []byte("\xff\xffapple\xff\xffbanana\xff\xffcherry\xff\xff"), - Expected: []byte("\xff\xffapple\xff\xffbanana\xff\xffcherry\xff\xff"), - }, - - - - { - Bytes: []byte("apple\xff\xff\xff\xffbanana\xff\xff\xff\xffcherry"), - Expected: []byte("apple\xff\xff\xff\xffbanana\xff\xff\xff\xffcherry"), - }, - { - Bytes: []byte("\xff\xff\xff\xffapple\xff\xff\xff\xffbanana\xff\xff\xff\xffcherry\xff\xff\xff\xff"), - Expected: []byte("\xff\xff\xff\xffapple\xff\xff\xff\xffbanana\xff\xff\xff\xffcherry\xff\xff\xff\xff"), - }, - - - - { - Bytes: []byte{255,251,24}, // IAC WILL TERMINAL-TYPE - Expected: []byte{}, - }, - { - Bytes: []byte{255,252,24}, // IAC WON'T TERMINAL-TYPE - Expected: []byte{}, - }, - { - Bytes: []byte{255,253,24}, // IAC DO TERMINAL-TYPE - Expected: []byte{}, - }, - { - Bytes: []byte{255,254,24}, // IAC DON'T TERMINAL-TYPE - Expected: []byte{}, - }, - - - - { - Bytes: []byte{67, 255,251,24}, // 'C' IAC WILL TERMINAL-TYPE - Expected: []byte{67}, - }, - { - Bytes: []byte{67, 255,252,24}, // 'C' IAC WON'T TERMINAL-TYPE - Expected: []byte{67}, - }, - { - Bytes: []byte{67, 255,253,24}, // 'C' IAC DO TERMINAL-TYPE - Expected: []byte{67}, - }, - { - Bytes: []byte{67, 255,254,24}, // 'C' IAC DON'T TERMINAL-TYPE - Expected: []byte{67}, - }, - - - - { - Bytes: []byte{255,251,24, 68}, // IAC WILL TERMINAL-TYPE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{255,252,24, 68}, // IAC WON'T TERMINAL-TYPE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{255,253,24, 68}, // IAC DO TERMINAL-TYPE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{255,254,24, 68}, // IAC DON'T TERMINAL-TYPE 'D' - Expected: []byte{68}, - }, - - - { - Bytes: []byte{67, 255,251,24, 68}, // 'C' IAC WILL TERMINAL-TYPE 'D' - Expected: []byte{67,68}, - }, - { - Bytes: []byte{67, 255,252,24, 68}, // 'C' IAC WON'T TERMINAL-TYPE 'D' - Expected: []byte{67,68}, - }, - { - Bytes: []byte{67, 255,253,24, 68}, // 'C' IAC DO TERMINAL-TYPE 'D' - Expected: []byte{67,68}, - }, - { - Bytes: []byte{67, 255,254,24, 68}, // 'C' IAC DON'T TERMINAL-TYPE 'D' - Expected: []byte{67,68}, - }, - - - - { - Bytes: []byte{255, 250, 24, 1, 255, 240}, // IAC SB TERMINAL-TYPE SEND IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{255, 250, 24, 0, 68,69,67,45,86,84,53,50 ,255, 240}, // IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE - Expected: []byte{}, - }, - - - - { - Bytes: []byte{67, 255, 250, 24, 1, 255, 240}, // 'C' IAC SB TERMINAL-TYPE SEND IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{67, 255, 250, 24, 0, 68,69,67,45,86,84,53,50 ,255, 240}, // 'C' IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE - Expected: []byte{67}, - }, - - - - { - Bytes: []byte{255, 250, 24, 1, 255, 240, 68}, // IAC SB TERMINAL-TYPE SEND IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{255, 250, 24, 0, 68,69,67,45,86,84,53,50 ,255, 240, 68}, // IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE 'D' - Expected: []byte{68}, - }, - - - - { - Bytes: []byte{67, 255, 250, 24, 1, 255, 240, 68}, // 'C' IAC SB TERMINAL-TYPE SEND IAC SE 'D' - Expected: []byte{67, 68}, - }, - { - Bytes: []byte{67, 255, 250, 24, 0, 68,69,67,45,86,84,53,50 ,255, 240, 68}, // 'C' IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE 'D' - Expected: []byte{67, 68}, - }, - - - - { - Bytes: []byte{255,250, 0,1,2,3,4,5,6,7,8,9,10,11,12,13 ,255,240}, // IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,250, 0,1,2,3,4,5,6,7,8,9,10,11,12,13 ,255,240}, // 'C' IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{255,250, 0,1,2,3,4,5,6,7,8,9,10,11,12,13 ,255,240, 68}, // IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{67, 255,250, 0,1,2,3,4,5,6,7,8,9,10,11,12,13 ,255,240, 68}, // 'C' IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE 'D' - Expected: []byte{67,68}, - }, - - - -//@TODO: Is this correct? Can IAC appear between thee 'IAC SB' and ''IAC SE'?... and if "yes", do escaping rules apply? - { - Bytes: []byte{ 255,250, 255,255,240 ,255,240}, // IAC SB 255 255 240 IAC SE = IAC SB IAC IAC SE IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,250, 255,255,240 ,255,240}, // 'C' IAC SB 255 255 240 IAC SE = IAC SB IAC IAC SE IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{ 255,250, 255,255,240 ,255,240, 68}, // IAC SB 255 255 240 IAC SE = IAC SB IAC IAC SE IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{67, 255,250, 255,255,240 ,255,240, 68}, // 'C' IAC SB 255 255 240 IAC SE = IAC SB IAC IAC SE IAC SE 'D' - Expected: []byte{67,68}, - }, - - - -//@TODO: Is this correct? Can IAC appear between thee 'IAC SB' and ''IAC SE'?... and if "yes", do escaping rules apply? - { - Bytes: []byte{ 255,250, 71,255,255,240 ,255,240}, // IAC SB 'G' 255 255 240 IAC SE = IAC SB 'G' IAC IAC SE IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,250, 71,255,255,240 ,255,240}, // 'C' IAC SB 'G' 255 255 240 IAC SE = IAC SB 'G' IAC IAC SE IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{ 255,250, 71,255,255,240 ,255,240, 68}, // IAC SB 'G' 255 255 240 IAC SE = IAC SB 'G' IAC IAC SE IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{67, 255,250, 71,255,255,240 ,255,240, 68}, // 'C' IAC SB 'G' 255 255 240 IAC SE = IAC 'G' SB IAC IAC SE IAC SE 'D' - Expected: []byte{67,68}, - }, - - - -//@TODO: Is this correct? Can IAC appear between thee 'IAC SB' and ''IAC SE'?... and if "yes", do escaping rules apply? - { - Bytes: []byte{ 255,250, 255,255,240,72 ,255,240}, // IAC SB 255 255 240 'H' IAC SE = IAC SB IAC IAC SE 'H' IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,250, 255,255,240,72 ,255,240}, // 'C' IAC SB 255 255 240 'H' IAC SE = IAC SB IAC IAC SE 'H' IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{ 255,250, 255,255,240,72 ,255,240, 68}, // IAC SB 255 255 240 'H' IAC SE = IAC SB IAC IAC SE 'H' IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{67, 255,250, 255,255,240,72 ,255,240, 68}, // 'C' IAC SB 255 255 240 'H' IAC SE = IAC SB IAC IAC SE 'H' IAC SE 'D' - Expected: []byte{67,68}, - }, - - - -//@TODO: Is this correct? Can IAC appear between thee 'IAC SB' and ''IAC SE'?... and if "yes", do escaping rules apply? - { - Bytes: []byte{ 255,250, 71,255,255,240,72 ,255,240}, // IAC SB 'G' 255 255 240 'H' IAC SE = IAC SB 'G' IAC IAC SE 'H' IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,250, 71,255,255,240,72 ,255,240}, // 'C' IAC SB 'G' 255 255 240 'H' IAC SE = IAC SB 'G' IAC IAC SE 'H' IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{ 255,250, 71,255,255,240,72 ,255,240, 68}, // IAC SB 'G' 255 255 240 'H' IAC SE = IAC SB 'G' IAC IAC SE 'H' IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{67, 255,250, 71,255,255,240,72 ,255,240, 68}, // 'C' IAC SB 'G' 255 255 240 'H' IAC SE = IAC 'G' SB IAC IAC SE 'H' IAC SE 'D' - Expected: []byte{67,68}, - }, - } - - - for testNumber, test := range tests { - var ctx Context = nil - - var buffer bytes.Buffer - - writer := newDataWriter(&buffer) - reader := newDataReader( bytes.NewReader(test.Bytes) ) - - EchoHandler.ServeTELNET(ctx, writer, reader) - - if expected, actual := string(test.Expected), buffer.String(); expected != actual { - t.Errorf("For test #%d, expected %q, but actually got %q.", testNumber, expected, actual) - continue - } - } -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/handler.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/handler.go deleted file mode 100644 index 96f4420..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/handler.go +++ /dev/null @@ -1,18 +0,0 @@ -package telnet - - -// A Handler serves a TELNET (or TELNETS) connection. -// -// Writing data to the Writer passed as an argument to the ServeTELNET method -// will send data to the TELNET (or TELNETS) client. -// -// Reading data from the Reader passed as an argument to the ServeTELNET method -// will receive data from the TELNET client. -// -// The Writer's Write method sends "escaped" TELNET (and TELNETS) data. -// -// The Reader's Read method "un-escapes" TELNET (and TELNETS) data, and filters -// out TELNET (and TELNETS) command sequences. -type Handler interface { - ServeTELNET(Context, Writer, Reader) -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/logger.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/logger.go deleted file mode 100644 index 979c1f4..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/logger.go +++ /dev/null @@ -1,16 +0,0 @@ -package telnet - - -type Logger interface{ - Debug(...interface{}) - Debugf(string, ...interface{}) - - Error(...interface{}) - Errorf(string, ...interface{}) - - Trace(...interface{}) - Tracef(string, ...interface{}) - - Warn(...interface{}) - Warnf(string, ...interface{}) -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/reader.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/reader.go deleted file mode 100644 index 2e56176..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/reader.go +++ /dev/null @@ -1,6 +0,0 @@ -package telnet - - -type Reader interface { - Read([]byte) (int, error) -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/server.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/server.go deleted file mode 100644 index a63ff35..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/server.go +++ /dev/null @@ -1,191 +0,0 @@ -package telnet - - -import ( - "crypto/tls" - "net" -) - - -// ListenAndServe listens on the TCP network address `addr` and then spawns a call to the ServeTELNET -// method on the `handler` to serve each incoming connection. -// -// For a very simple example: -// -// package main -// -// import ( -// "github.com/reiver/go-telnet" -// ) -// -// func main() { -// -// //@TODO: In your code, you would probably want to use a different handler. -// var handler telnet.Handler = telnet.EchoHandler -// -// err := telnet.ListenAndServe(":5555", handler) -// if nil != err { -// //@TODO: Handle this error better. -// panic(err) -// } -// } -func ListenAndServe(addr string, handler Handler) error { - server := &Server{Addr: addr, Handler: handler} - return server.ListenAndServe() -} - - -// Serve accepts an incoming TELNET or TELNETS client connection on the net.Listener `listener`. -func Serve(listener net.Listener, handler Handler) error { - - server := &Server{Handler: handler} - return server.Serve(listener) -} - - -// A Server defines parameters of a running TELNET server. -// -// For a simple example: -// -// package main -// -// import ( -// "github.com/reiver/go-telnet" -// ) -// -// func main() { -// -// var handler telnet.Handler = telnet.EchoHandler -// -// server := &telnet.Server{ -// Addr:":5555", -// Handler:handler, -// } -// -// err := server.ListenAndServe() -// if nil != err { -// //@TODO: Handle this error better. -// panic(err) -// } -// } -type Server struct { - Addr string // TCP address to listen on; ":telnet" or ":telnets" if empty (when used with ListenAndServe or ListenAndServeTLS respectively). - Handler Handler // handler to invoke; telnet.EchoServer if nil - - TLSConfig *tls.Config // optional TLS configuration; used by ListenAndServeTLS. - - Logger Logger -} - -// ListenAndServe listens on the TCP network address 'server.Addr' and then spawns a call to the ServeTELNET -// method on the 'server.Handler' to serve each incoming connection. -// -// For a simple example: -// -// package main -// -// import ( -// "github.com/reiver/go-telnet" -// ) -// -// func main() { -// -// var handler telnet.Handler = telnet.EchoHandler -// -// server := &telnet.Server{ -// Addr:":5555", -// Handler:handler, -// } -// -// err := server.ListenAndServe() -// if nil != err { -// //@TODO: Handle this error better. -// panic(err) -// } -// } -func (server *Server) ListenAndServe() error { - - addr := server.Addr - if "" == addr { - addr = ":telnet" - } - - - listener, err := net.Listen("tcp", addr) - if nil != err { - return err - } - - - return server.Serve(listener) -} - - -// Serve accepts an incoming TELNET client connection on the net.Listener `listener`. -func (server *Server) Serve(listener net.Listener) error { - - defer listener.Close() - - - logger := server.logger() - - - handler := server.Handler - if nil == handler { -//@TODO: Should this be a "ShellHandler" instead, that gives a shell-like experience by default -// If this is changd, then need to change the comment in the "type Server struct" definition. - logger.Debug("Defaulted handler to EchoHandler.") - handler = EchoHandler - } - - - for { - // Wait for a new TELNET client connection. - logger.Debugf("Listening at %q.", listener.Addr()) - conn, err := listener.Accept() - if err != nil { -//@TODO: Could try to recover from certain kinds of errors. Maybe waiting a while before trying again. - return err - } - logger.Debugf("Received new connection from %q.", conn.RemoteAddr()) - - // Handle the new TELNET client connection by spawning - // a new goroutine. - go server.handle(conn, handler) - logger.Debugf("Spawned handler to handle connection from %q.", conn.RemoteAddr()) - } -} - -func (server *Server) handle(c net.Conn, handler Handler) { - defer c.Close() - - logger := server.logger() - - - defer func(){ - if r := recover(); nil != r { - if nil != logger { - logger.Errorf("Recovered from: (%T) %v", r, r) - } - } - }() - - var ctx Context = NewContext().InjectLogger(logger) - - var w Writer = newDataWriter(c) - var r Reader = newDataReader(c) - - handler.ServeTELNET(ctx, w, r) - c.Close() -} - - - -func (server *Server) logger() Logger { - logger := server.Logger - if nil == logger { - logger = internalDiscardLogger{} - } - - return logger -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/standard_caller.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/standard_caller.go deleted file mode 100644 index 17a9408..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/standard_caller.go +++ /dev/null @@ -1,93 +0,0 @@ -package telnet - - -import ( - "github.com/reiver/go-oi" - - "bufio" - "bytes" - "fmt" - "io" - "os" - - "time" -) - - -// StandardCaller is a simple TELNET client which sends to the server any data it gets from os.Stdin -// as TELNET (and TELNETS) data, and writes any TELNET (or TELNETS) data it receives from -// the server to os.Stdout, and writes any error it has to os.Stderr. -var StandardCaller Caller = internalStandardCaller{} - - -type internalStandardCaller struct{} - - -func (caller internalStandardCaller) CallTELNET(ctx Context, w Writer, r Reader) { - standardCallerCallTELNET(os.Stdin, os.Stdout, os.Stderr, ctx, w, r) -} - - -func standardCallerCallTELNET(stdin io.ReadCloser, stdout io.WriteCloser, stderr io.WriteCloser, ctx Context, w Writer, r Reader) { - - go func(writer io.Writer, reader io.Reader) { - - var buffer [1]byte // Seems like the length of the buffer needs to be small, otherwise will have to wait for buffer to fill up. - p := buffer[:] - - for { - // Read 1 byte. - n, err := reader.Read(p) - if n <= 0 && nil == err { - continue - } else if n <= 0 && nil != err { - break - } - - oi.LongWrite(writer, p) - } - }(stdout, r) - - - - var buffer bytes.Buffer - var p []byte - - var crlfBuffer [2]byte = [2]byte{'\r','\n'} - crlf := crlfBuffer[:] - - scanner := bufio.NewScanner(stdin) - scanner.Split(scannerSplitFunc) - - for scanner.Scan() { - buffer.Write(scanner.Bytes()) - buffer.Write(crlf) - - p = buffer.Bytes() - - n, err := oi.LongWrite(w, p) - if nil != err { - break - } - if expected, actual := int64(len(p)), n; expected != actual { - err := fmt.Errorf("Transmission problem: tried sending %d bytes, but actually only sent %d bytes.", expected, actual) - fmt.Fprint(stderr, err.Error()) - return - } - - - buffer.Reset() - } - - // Wait a bit to receive data from the server (that we would send to io.Stdout). - time.Sleep(3 * time.Millisecond) -} - - -func scannerSplitFunc(data []byte, atEOF bool) (advance int, token []byte, err error) { - if atEOF { - return 0, nil, nil - } - - return bufio.ScanLines(data, atEOF) -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/standard_caller_test.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/standard_caller_test.go deleted file mode 100644 index cfcd216..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/standard_caller_test.go +++ /dev/null @@ -1,974 +0,0 @@ -package telnet - - -import ( - "github.com/reiver/go-oi" - - "bytes" - "io/ioutil" - - "testing" -) - - -func TestStandardCallerFromClientToServer(t *testing.T) { - - tests := []struct{ - Bytes []byte - Expected []byte - }{ - { - Bytes: []byte{}, - Expected: []byte{}, - }, - - - - - - - { - Bytes: []byte("a"), - Expected: []byte(""), - }, - { - Bytes: []byte("b"), - Expected: []byte(""), - }, - { - Bytes: []byte("c"), - Expected: []byte(""), - }, - - - - { - Bytes: []byte("a\n"), - Expected: []byte("a\r\n"), - }, - { - Bytes: []byte("b\n"), - Expected: []byte("b\r\n"), - }, - { - Bytes: []byte("c\n"), - Expected: []byte("c\r\n"), - }, - - - - { - Bytes: []byte("a\nb\nc"), - Expected: []byte("a\r\nb\r\n"), - }, - - - - { - Bytes: []byte("a\nb\nc\n"), - Expected: []byte("a\r\nb\r\nc\r\n"), - }, - - - - - - - { - Bytes: []byte("apple"), - Expected: []byte(""), - }, - { - Bytes: []byte("banana"), - Expected: []byte(""), - }, - { - Bytes: []byte("cherry"), - Expected: []byte(""), - }, - - - - { - Bytes: []byte("apple\n"), - Expected: []byte("apple\r\n"), - }, - { - Bytes: []byte("banana\n"), - Expected: []byte("banana\r\n"), - }, - { - Bytes: []byte("cherry\n"), - Expected: []byte("cherry\r\n"), - }, - - - - - - - { - Bytes: []byte("apple\nbanana\ncherry"), - Expected: []byte("apple\r\nbanana\r\n"), - }, - - - - { - Bytes: []byte("apple\nbanana\ncherry\n"), - Expected: []byte("apple\r\nbanana\r\ncherry\r\n"), - }, - - - - - - - { - Bytes: []byte("apple banana cherry"), - Expected: []byte(""), - }, - - - - { - Bytes: []byte("apple banana cherry\n"), - Expected: []byte("apple banana cherry\r\n"), - }, - - - - - - - { - Bytes: []byte{255}, - Expected: []byte{}, - }, - { - Bytes: []byte{255, 255}, - Expected: []byte{}, - }, - { - Bytes: []byte{255, 255, 255}, - Expected: []byte{}, - }, - { - Bytes: []byte{255, 255, 255, 255}, - Expected: []byte{}, - }, - { - Bytes: []byte{255, 255, 255, 255, 255}, - Expected: []byte{}, - }, - { - Bytes: []byte{255, 255, 255, 255, 255, 255}, - Expected: []byte{}, - }, - { - Bytes: []byte{255, 255, 255, 255, 255, 255, 255}, - Expected: []byte{}, - }, - { - Bytes: []byte{255, 255, 255, 255, 255, 255, 255, 255}, - Expected: []byte{}, - }, - { - Bytes: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255}, - Expected: []byte{}, - }, - { - Bytes: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, - Expected: []byte{}, - }, - - - - { - Bytes: []byte{255, '\n'}, - Expected: []byte{255, 255, '\r', '\n'}, - }, - { - Bytes: []byte{255, 255, '\n'}, - Expected: []byte{255, 255, 255, 255, '\r', '\n'}, - }, - { - Bytes: []byte{255, 255, 255, '\n'}, - Expected: []byte{255, 255, 255, 255, 255, 255, '\r', '\n'}, - }, - { - Bytes: []byte{255, 255, 255, 255, '\n'}, - Expected: []byte{255, 255, 255, 255, 255, 255, 255, 255, '\r', '\n'}, - }, - { - Bytes: []byte{255, 255, 255, 255, 255, '\n'}, - Expected: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, '\r', '\n'}, - }, - { - Bytes: []byte{255, 255, 255, 255, 255, 255, '\n'}, - Expected: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, '\r', '\n'}, - }, - { - Bytes: []byte{255, 255, 255, 255, 255, 255, 255, '\n'}, - Expected: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, '\r', '\n'}, - }, - { - Bytes: []byte{255, 255, 255, 255, 255, 255, 255, 255, '\n'}, - Expected: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, '\r', '\n'}, - }, - { - Bytes: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, '\n'}, - Expected: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, '\r', '\n'}, - }, - { - Bytes: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, '\n'}, - Expected: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, '\r', '\n'}, - }, - - - - - - - { - Bytes: []byte("apple\xff\xffbanana\xff\xffcherry"), - Expected: []byte(""), - }, - { - Bytes: []byte("\xff\xffapple\xff\xffbanana\xff\xffcherry\xff\xff"), - Expected: []byte(""), - }, - - - - { - Bytes: []byte("apple\xffbanana\xffcherry\n"), - Expected: []byte("apple\xff\xffbanana\xff\xffcherry\r\n"), - }, - { - Bytes: []byte("\xffapple\xffbanana\xffcherry\xff\n"), - Expected: []byte("\xff\xffapple\xff\xffbanana\xff\xffcherry\xff\xff\r\n"), - }, - - - - { - Bytes: []byte("apple\xff\xff\xff\xffbanana\xff\xff\xff\xffcherry"), - Expected: []byte(""), - }, - { - Bytes: []byte("\xff\xff\xff\xffapple\xff\xff\xff\xffbanana\xff\xff\xff\xffcherry\xff\xff\xff\xff"), - Expected: []byte(""), - }, - - - - { - Bytes: []byte("apple\xff\xffbanana\xff\xffcherry\n"), - Expected: []byte("apple\xff\xff\xff\xffbanana\xff\xff\xff\xffcherry\r\n"), - }, - { - Bytes: []byte("\xff\xffapple\xff\xffbanana\xff\xffcherry\xff\xff\n"), - Expected: []byte("\xff\xff\xff\xffapple\xff\xff\xff\xffbanana\xff\xff\xff\xffcherry\xff\xff\xff\xff\r\n"), - }, - - - - - - - { - Bytes: []byte{255,251,24}, // IAC WILL TERMINAL-TYPE - Expected: []byte{}, - }, - { - Bytes: []byte{255,252,24}, // IAC WON'T TERMINAL-TYPE - Expected: []byte{}, - }, - { - Bytes: []byte{255,253,24}, // IAC DO TERMINAL-TYPE - Expected: []byte{}, - }, - { - Bytes: []byte{255,254,24}, // IAC DON'T TERMINAL-TYPE - Expected: []byte{}, - }, - - - - { - Bytes: []byte{ 255,251,24, '\n'}, // IAC WILL TERMINAL-TYPE '\n' - Expected: []byte{255,255,251,24,'\r','\n'}, - }, - { - Bytes: []byte{ 255,252,24, '\n'}, // IAC WON'T TERMINAL-TYPE '\n' - Expected: []byte{255,255,252,24,'\r','\n'}, - }, - { - Bytes: []byte{ 255,253,24, '\n'}, // IAC DO TERMINAL-TYPE '\n' - Expected: []byte{255,255,253,24,'\r','\n'}, - }, - { - Bytes: []byte{ 255,254,24, '\n'}, // IAC DON'T TERMINAL-TYPE '\n' - Expected: []byte{255,255,254,24,'\r','\n'}, - }, - - - - - - - { - Bytes: []byte{67, 255,251,24}, // 'C' IAC WILL TERMINAL-TYPE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,252,24}, // 'C' IAC WON'T TERMINAL-TYPE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,253,24}, // 'C' IAC DO TERMINAL-TYPE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,254,24}, // 'C' IAC DON'T TERMINAL-TYPE - Expected: []byte{}, - }, - - - - { - Bytes: []byte{67, 255,251,24, '\n'}, // 'C' IAC WILL TERMINAL-TYPE '\n' - Expected: []byte{67, 255,255,251,24, '\r','\n'}, - }, - { - Bytes: []byte{67, 255,252,24, '\n'}, // 'C' IAC WON'T TERMINAL-TYPE '\n' - Expected: []byte{67, 255,255,252,24, '\r','\n'}, - }, - { - Bytes: []byte{67, 255,253,24, '\n'}, // 'C' IAC DO TERMINAL-TYPE '\n' - Expected: []byte{67, 255,255,253,24, '\r','\n'}, - }, - { - Bytes: []byte{67, 255,254,24, '\n'}, // 'C' IAC DON'T TERMINAL-TYPE '\n' - Expected: []byte{67, 255,255,254,24, '\r','\n'}, - }, - - - - - - - { - Bytes: []byte{255,251,24, 68}, // IAC WILL TERMINAL-TYPE 'D' - Expected: []byte{}, - }, - { - Bytes: []byte{255,252,24, 68}, // IAC WON'T TERMINAL-TYPE 'D' - Expected: []byte{}, - }, - { - Bytes: []byte{255,253,24, 68}, // IAC DO TERMINAL-TYPE 'D' - Expected: []byte{}, - }, - { - Bytes: []byte{255,254,24, 68}, // IAC DON'T TERMINAL-TYPE 'D' - Expected: []byte{}, - }, - - - - { - Bytes: []byte{ 255,251,24, 68, '\n'}, // IAC WILL TERMINAL-TYPE 'D' '\n' - Expected: []byte{255,255,251,24, 68, '\r','\n'}, - }, - { - Bytes: []byte{ 255,252,24, 68, '\n'}, // IAC WON'T TERMINAL-TYPE 'D' '\n' - Expected: []byte{255,255,252,24, 68, '\r','\n'}, - }, - { - Bytes: []byte{ 255,253,24, 68, '\n'}, // IAC DO TERMINAL-TYPE 'D' '\n' - Expected: []byte{255,255,253,24, 68, '\r','\n'}, - }, - { - Bytes: []byte{ 255,254,24, 68, '\n'}, // IAC DON'T TERMINAL-TYPE 'D' '\n' - Expected: []byte{255,255,254,24, 68, '\r','\n'}, - }, - - - - - - - { - Bytes: []byte{67, 255,251,24, 68}, // 'C' IAC WILL TERMINAL-TYPE 'D' - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,252,24, 68}, // 'C' IAC WON'T TERMINAL-TYPE 'D' - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,253,24, 68}, // 'C' IAC DO TERMINAL-TYPE 'D' - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,254,24, 68}, // 'C' IAC DON'T TERMINAL-TYPE 'D' - Expected: []byte{}, - }, - - - - { - Bytes: []byte{67, 255,251,24, 68, '\n'}, // 'C' IAC WILL TERMINAL-TYPE 'D' '\n' - Expected: []byte{67, 255,255,251,24, 68, '\r','\n'}, - }, - { - Bytes: []byte{67, 255,252,24, 68, '\n'}, // 'C' IAC WON'T TERMINAL-TYPE 'D' '\n' - Expected: []byte{67, 255,255,252,24, 68, '\r','\n'}, - }, - { - Bytes: []byte{67, 255,253,24, 68, '\n'}, // 'C' IAC DO TERMINAL-TYPE 'D' '\n' - Expected: []byte{67, 255,255,253,24, 68, '\r','\n'}, - }, - { - Bytes: []byte{67, 255,254,24, 68, '\n'}, // 'C' IAC DON'T TERMINAL-TYPE 'D' '\n' - Expected: []byte{67, 255,255,254,24, 68, '\r','\n'}, - }, - - - - - - - { - Bytes: []byte{255, 250, 24, 1, 255, 240}, // IAC SB TERMINAL-TYPE SEND IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{255, 250, 24, 0, 68,69,67,45,86,84,53,50 ,255, 240}, // IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE - Expected: []byte{}, - }, - - - - { - Bytes: []byte{ 255, 250, 24, 1, 255, 240, '\n'}, // IAC SB TERMINAL-TYPE SEND IAC SE '\n' - Expected: []byte{255, 255, 250, 24, 1, 255, 255, 240, '\r','\n'}, - }, - { - Bytes: []byte{ 255, 250, 24, 0, 68,69,67,45,86,84,53,50, 255, 240, '\n'}, // IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE '\n' - Expected: []byte{255, 255, 250, 24, 0, 68,69,67,45,86,84,53,50, 255, 255, 240, '\r','\n'}, - }, - - - - - - - { - Bytes: []byte{67, 255, 250, 24, 1, 255, 240}, // 'C' IAC SB TERMINAL-TYPE SEND IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255, 250, 24, 0, 68,69,67,45,86,84,53,50 ,255, 240}, // 'C' IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE - Expected: []byte{}, - }, - - - - { - Bytes: []byte{67, 255, 250, 24, 1, 255, 240, '\n'}, // 'C' IAC SB TERMINAL-TYPE SEND IAC SE '\n' - Expected: []byte{67, 255, 255, 250, 24, 1, 255, 255, 240, '\r','\n'}, - }, - { - Bytes: []byte{67, 255, 250, 24, 0, 68,69,67,45,86,84,53,50, 255, 240, '\n'}, // 'C' IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE '\n' - Expected: []byte{67, 255, 255, 250, 24, 0, 68,69,67,45,86,84,53,50, 255, 255, 240, '\r','\n'}, - }, - - - - - - - { - Bytes: []byte{255, 250, 24, 1, 255, 240, 68}, // IAC SB TERMINAL-TYPE SEND IAC SE 'D' - Expected: []byte{}, - }, - { - Bytes: []byte{255, 250, 24, 0, 68,69,67,45,86,84,53,50 ,255, 240, 68}, // IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE 'D' - Expected: []byte{}, - }, - - - - { - Bytes: []byte{ 255, 250, 24, 1, 255, 240, 68, '\n'}, // IAC SB TERMINAL-TYPE SEND IAC SE 'D' '\n' - Expected: []byte{255, 255, 250, 24, 1, 255, 255, 240, 68, '\r','\n'}, - }, - { - Bytes: []byte{ 255, 250, 24, 0, 68,69,67,45,86,84,53,50, 255, 240, 68, '\n'}, // IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE 'D' '\n' - Expected: []byte{255, 255, 250, 24, 0, 68,69,67,45,86,84,53,50, 255, 255, 240, 68, '\r','\n'}, - }, - - - - - - - { - Bytes: []byte{67, 255, 250, 24, 1, 255, 240, 68}, // 'C' IAC SB TERMINAL-TYPE SEND IAC SE 'D' - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255, 250, 24, 0, 68,69,67,45,86,84,53,50 ,255, 240, 68}, // 'C' IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE 'D' - Expected: []byte{}, - }, - - - - { - Bytes: []byte{67, 255, 250, 24, 1, 255, 240, 68, '\n'}, // 'C' IAC SB TERMINAL-TYPE SEND IAC SE 'D' '\n' - Expected: []byte{67, 255, 255, 250, 24, 1, 255, 255, 240, 68, '\r','\n'}, - }, - { - Bytes: []byte{67, 255, 250, 24, 0, 68,69,67,45,86,84,53,50, 255, 240, 68, '\n'}, // 'C' IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE 'D' '\n' - Expected: []byte{67, 255, 255, 250, 24, 0, 68,69,67,45,86,84,53,50, 255, 255, 240, 68, '\r','\n'}, - }, - - - - - - - { - Bytes: []byte{ 255,250, 0,1,2,3,4,5,6,7,8,9, 10,11,12,13 ,255,240}, // IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE - Expected: []byte{255,255,250, 0,1,2,3,4,5,6,7,8,9,'\r',10}, - }, - { - Bytes: []byte{67, 255,250, 0,1,2,3,4,5,6,7,8,9, 10, 11,12,13 ,255,240}, // 'C' IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE - Expected: []byte{67, 255,255,250, 0,1,2,3,4,5,6,7,8,9,'\r',10}, - }, - { - Bytes: []byte{ 255,250, 0,1,2,3,4,5,6,7,8,9, 10,11,12,13 ,255,240, 68}, // IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE 'D' - Expected: []byte{255,255,250, 0,1,2,3,4,5,6,7,8,9,'\r',10}, - }, - { - Bytes: []byte{67, 255,250, 0,1,2,3,4,5,6,7,8,9, 10,11,12,13 ,255,240, 68}, // 'C' IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE 'D' - Expected: []byte{67, 255,255,250, 0,1,2,3,4,5,6,7,8,9,'\r',10}, - }, - - - - { - Bytes: []byte{ 255,250, 0,1,2,3,4,5,6,7,8,9, 10,11,12,13, 255,240, '\n'}, // IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE '\n' - Expected: []byte{255,255,250, 0,1,2,3,4,5,6,7,8,9,'\r',10,11,12,13, 255,255,240, '\r','\n'}, - }, - { - Bytes: []byte{67, 255,250, 0,1,2,3,4,5,6,7,8,9, 10,11,12, 13, 255,240, '\n'}, // 'C' IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE '\n' - Expected: []byte{67, 255,255,250, 0,1,2,3,4,5,6,7,8,9,'\r',10,11,12,13, 255,255,240, '\r','\n'}, - }, - { - Bytes: []byte{ 255,250, 0,1,2,3,4,5,6,7,8,9, 10,11,12,13, 255,240, 68, '\n'}, // IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE 'D' '\n' - Expected: []byte{255,255,250, 0,1,2,3,4,5,6,7,8,9,'\r',10,11,12,13, 255,255,240, 68, '\r','\n'}, - }, - { - Bytes: []byte{67, 255,250, 0,1,2,3,4,5,6,7,8,9, 10,11,12,13, 255,240, 68, '\n'}, // 'C' IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE 'D' '\n' - Expected: []byte{67, 255,255,250, 0,1,2,3,4,5,6,7,8,9,'\r',10,11,12,13, 255,255,240, 68, '\r','\n'}, - }, - } - - - for testNumber, test := range tests { - var stdinBuffer bytes.Buffer - var stdoutBuffer bytes.Buffer - var stderrBuffer bytes.Buffer - - stdinBuffer.Write(test.Bytes) // <----------------- The important difference between the 2 loops. - - stdin := ioutil.NopCloser(&stdinBuffer) - stdout := oi.WriteNopCloser(&stdoutBuffer) - stderr := oi.WriteNopCloser(&stderrBuffer) - - var ctx Context = nil - - var dataWriterBuffer bytes.Buffer - dataWriter := newDataWriter(&dataWriterBuffer) - - dataReader := newDataReader( bytes.NewReader([]byte{}) ) // <----------------- The important difference between the 2 loops. - - standardCallerCallTELNET(stdin, stdout, stderr, ctx, dataWriter, dataReader) - - - if expected, actual := string(test.Expected), dataWriterBuffer.String(); expected != actual { - t.Errorf("For test #%d, expected %q, but actually got %q; for %q.", testNumber, expected, actual, test.Bytes) - continue - } - - if expected, actual := "", stdoutBuffer.String(); expected != actual { - t.Errorf("For test #%d, expected %q, but actually got %q.", testNumber, expected, actual) - continue - } - - if expected, actual := "", stderrBuffer.String(); expected != actual { - t.Errorf("For test #%d, expected %q, but actually got %q.", testNumber, expected, actual) - continue - } - } -} - - - -func TestStandardCallerFromServerToClient(t *testing.T) { - - tests := []struct{ - Bytes []byte - Expected []byte - }{ - { - Bytes: []byte{}, - Expected: []byte{}, - }, - - - - { - Bytes: []byte("a"), - Expected: []byte("a"), - }, - { - Bytes: []byte("b"), - Expected: []byte("b"), - }, - { - Bytes: []byte("c"), - Expected: []byte("c"), - }, - - - - { - Bytes: []byte("apple"), - Expected: []byte("apple"), - }, - { - Bytes: []byte("banana"), - Expected: []byte("banana"), - }, - { - Bytes: []byte("cherry"), - Expected: []byte("cherry"), - }, - - - - { - Bytes: []byte("apple banana cherry"), - Expected: []byte("apple banana cherry"), - }, - - - - { - Bytes: []byte{255,255}, - Expected: []byte{255}, - }, - { - Bytes: []byte{255,255,255,255}, - Expected: []byte{255,255}, - }, - { - Bytes: []byte{255,255,255,255,255,255}, - Expected: []byte{255,255,255}, - }, - { - Bytes: []byte{255,255,255,255,255,255,255,255}, - Expected: []byte{255,255,255,255}, - }, - { - Bytes: []byte{255,255,255,255,255,255,255,255,255,255}, - Expected: []byte{255,255,255,255,255}, - }, - - - - { - Bytes: []byte("apple\xff\xffbanana\xff\xffcherry"), - Expected: []byte("apple\xffbanana\xffcherry"), - }, - { - Bytes: []byte("\xff\xffapple\xff\xffbanana\xff\xffcherry\xff\xff"), - Expected: []byte("\xffapple\xffbanana\xffcherry\xff"), - }, - - - - - { - Bytes: []byte("apple\xff\xff\xff\xffbanana\xff\xff\xff\xffcherry"), - Expected: []byte("apple\xff\xffbanana\xff\xffcherry"), - }, - { - Bytes: []byte("\xff\xff\xff\xffapple\xff\xff\xff\xffbanana\xff\xff\xff\xffcherry\xff\xff\xff\xff"), - Expected: []byte("\xff\xffapple\xff\xffbanana\xff\xffcherry\xff\xff"), - }, - - - - { - Bytes: []byte{255,251,24}, // IAC WILL TERMINAL-TYPE - Expected: []byte{}, - }, - { - Bytes: []byte{255,252,24}, // IAC WON'T TERMINAL-TYPE - Expected: []byte{}, - }, - { - Bytes: []byte{255,253,24}, // IAC DO TERMINAL-TYPE - Expected: []byte{}, - }, - { - Bytes: []byte{255,254,24}, // IAC DON'T TERMINAL-TYPE - Expected: []byte{}, - }, - - - - { - Bytes: []byte{67, 255,251,24}, // 'C' IAC WILL TERMINAL-TYPE - Expected: []byte{67}, - }, - { - Bytes: []byte{67, 255,252,24}, // 'C' IAC WON'T TERMINAL-TYPE - Expected: []byte{67}, - }, - { - Bytes: []byte{67, 255,253,24}, // 'C' IAC DO TERMINAL-TYPE - Expected: []byte{67}, - }, - { - Bytes: []byte{67, 255,254,24}, // 'C' IAC DON'T TERMINAL-TYPE - Expected: []byte{67}, - }, - - - - { - Bytes: []byte{255,251,24, 68}, // IAC WILL TERMINAL-TYPE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{255,252,24, 68}, // IAC WON'T TERMINAL-TYPE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{255,253,24, 68}, // IAC DO TERMINAL-TYPE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{255,254,24, 68}, // IAC DON'T TERMINAL-TYPE 'D' - Expected: []byte{68}, - }, - - - { - Bytes: []byte{67, 255,251,24, 68}, // 'C' IAC WILL TERMINAL-TYPE 'D' - Expected: []byte{67,68}, - }, - { - Bytes: []byte{67, 255,252,24, 68}, // 'C' IAC WON'T TERMINAL-TYPE 'D' - Expected: []byte{67,68}, - }, - { - Bytes: []byte{67, 255,253,24, 68}, // 'C' IAC DO TERMINAL-TYPE 'D' - Expected: []byte{67,68}, - }, - { - Bytes: []byte{67, 255,254,24, 68}, // 'C' IAC DON'T TERMINAL-TYPE 'D' - Expected: []byte{67,68}, - }, - - - - { - Bytes: []byte{255, 250, 24, 1, 255, 240}, // IAC SB TERMINAL-TYPE SEND IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{255, 250, 24, 0, 68,69,67,45,86,84,53,50 ,255, 240}, // IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE - Expected: []byte{}, - }, - - - - { - Bytes: []byte{67, 255, 250, 24, 1, 255, 240}, // 'C' IAC SB TERMINAL-TYPE SEND IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{67, 255, 250, 24, 0, 68,69,67,45,86,84,53,50 ,255, 240}, // 'C' IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE - Expected: []byte{67}, - }, - - - - { - Bytes: []byte{255, 250, 24, 1, 255, 240, 68}, // IAC SB TERMINAL-TYPE SEND IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{255, 250, 24, 0, 68,69,67,45,86,84,53,50 ,255, 240, 68}, // IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE 'D' - Expected: []byte{68}, - }, - - - - { - Bytes: []byte{67, 255, 250, 24, 1, 255, 240, 68}, // 'C' IAC SB TERMINAL-TYPE SEND IAC SE 'D' - Expected: []byte{67, 68}, - }, - { - Bytes: []byte{67, 255, 250, 24, 0, 68,69,67,45,86,84,53,50 ,255, 240, 68}, // 'C' IAC SB TERMINAL-TYPE IS "DEC-VT52" IAC SE 'D' - Expected: []byte{67, 68}, - }, - - - - { - Bytes: []byte{255,250, 0,1,2,3,4,5,6,7,8,9,10,11,12,13 ,255,240}, // IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,250, 0,1,2,3,4,5,6,7,8,9,10,11,12,13 ,255,240}, // 'C' IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{255,250, 0,1,2,3,4,5,6,7,8,9,10,11,12,13 ,255,240, 68}, // IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{67, 255,250, 0,1,2,3,4,5,6,7,8,9,10,11,12,13 ,255,240, 68}, // 'C' IAC SB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 IAC SE 'D' - Expected: []byte{67,68}, - }, - - - -//@TODO: Is this correct? Can IAC appear between thee 'IAC SB' and ''IAC SE'?... and if "yes", do escaping rules apply? - { - Bytes: []byte{ 255,250, 255,255,240 ,255,240}, // IAC SB 255 255 240 IAC SE = IAC SB IAC IAC SE IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,250, 255,255,240 ,255,240}, // 'C' IAC SB 255 255 240 IAC SE = IAC SB IAC IAC SE IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{ 255,250, 255,255,240 ,255,240, 68}, // IAC SB 255 255 240 IAC SE = IAC SB IAC IAC SE IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{67, 255,250, 255,255,240 ,255,240, 68}, // 'C' IAC SB 255 255 240 IAC SE = IAC SB IAC IAC SE IAC SE 'D' - Expected: []byte{67,68}, - }, - - - -//@TODO: Is this correct? Can IAC appear between thee 'IAC SB' and ''IAC SE'?... and if "yes", do escaping rules apply? - { - Bytes: []byte{ 255,250, 71,255,255,240 ,255,240}, // IAC SB 'G' 255 255 240 IAC SE = IAC SB 'G' IAC IAC SE IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,250, 71,255,255,240 ,255,240}, // 'C' IAC SB 'G' 255 255 240 IAC SE = IAC SB 'G' IAC IAC SE IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{ 255,250, 71,255,255,240 ,255,240, 68}, // IAC SB 'G' 255 255 240 IAC SE = IAC SB 'G' IAC IAC SE IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{67, 255,250, 71,255,255,240 ,255,240, 68}, // 'C' IAC SB 'G' 255 255 240 IAC SE = IAC 'G' SB IAC IAC SE IAC SE 'D' - Expected: []byte{67,68}, - }, - - - -//@TODO: Is this correct? Can IAC appear between thee 'IAC SB' and ''IAC SE'?... and if "yes", do escaping rules apply? - { - Bytes: []byte{ 255,250, 255,255,240,72 ,255,240}, // IAC SB 255 255 240 'H' IAC SE = IAC SB IAC IAC SE 'H' IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,250, 255,255,240,72 ,255,240}, // 'C' IAC SB 255 255 240 'H' IAC SE = IAC SB IAC IAC SE 'H' IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{ 255,250, 255,255,240,72 ,255,240, 68}, // IAC SB 255 255 240 'H' IAC SE = IAC SB IAC IAC SE 'H' IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{67, 255,250, 255,255,240,72 ,255,240, 68}, // 'C' IAC SB 255 255 240 'H' IAC SE = IAC SB IAC IAC SE 'H' IAC SE 'D' - Expected: []byte{67,68}, - }, - - - -//@TODO: Is this correct? Can IAC appear between thee 'IAC SB' and ''IAC SE'?... and if "yes", do escaping rules apply? - { - Bytes: []byte{ 255,250, 71,255,255,240,72 ,255,240}, // IAC SB 'G' 255 255 240 'H' IAC SE = IAC SB 'G' IAC IAC SE 'H' IAC SE - Expected: []byte{}, - }, - { - Bytes: []byte{67, 255,250, 71,255,255,240,72 ,255,240}, // 'C' IAC SB 'G' 255 255 240 'H' IAC SE = IAC SB 'G' IAC IAC SE 'H' IAC SE - Expected: []byte{67}, - }, - { - Bytes: []byte{ 255,250, 71,255,255,240,72 ,255,240, 68}, // IAC SB 'G' 255 255 240 'H' IAC SE = IAC SB 'G' IAC IAC SE 'H' IAC SE 'D' - Expected: []byte{68}, - }, - { - Bytes: []byte{67, 255,250, 71,255,255,240,72 ,255,240, 68}, // 'C' IAC SB 'G' 255 255 240 'H' IAC SE = IAC 'G' SB IAC IAC SE 'H' IAC SE 'D' - Expected: []byte{67,68}, - }, - - - } - - - - for testNumber, test := range tests { - var stdinBuffer bytes.Buffer - var stdoutBuffer bytes.Buffer - var stderrBuffer bytes.Buffer - - stdin := ioutil.NopCloser(&stdinBuffer) - stdout := oi.WriteNopCloser(&stdoutBuffer) - stderr := oi.WriteNopCloser(&stderrBuffer) - - var ctx Context = nil - - var dataWriterBuffer bytes.Buffer - dataWriter := newDataWriter(&dataWriterBuffer) - - dataReader := newDataReader( bytes.NewReader(test.Bytes) ) // <----------------- The important difference between the 2 loops. - - standardCallerCallTELNET(stdin, stdout, stderr, ctx, dataWriter, dataReader) - - - if expected, actual := "", dataWriterBuffer.String(); expected != actual { - t.Errorf("For test #%d, expected %q, but actually got %q; for %q.", testNumber, expected, actual, test.Bytes) - continue - } - - if expected, actual := string(test.Expected), stdoutBuffer.String(); expected != actual { - t.Errorf("For test #%d, expected %q, but actually got %q.", testNumber, expected, actual) - continue - } - - if expected, actual := "", stderrBuffer.String(); expected != actual { - t.Errorf("For test #%d, expected %q, but actually got %q.", testNumber, expected, actual) - continue - } - - } -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/discard_logger.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/discard_logger.go deleted file mode 100644 index b532f4a..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/discard_logger.go +++ /dev/null @@ -1,21 +0,0 @@ -package telsh - - -type internalDiscardLogger struct{} - -func (internalDiscardLogger) Debug(...interface{}) {} -func (internalDiscardLogger) Debugf(string, ...interface{}) {} -func (internalDiscardLogger) Debugln(...interface{}) {} - -func (internalDiscardLogger) Error(...interface{}) {} -func (internalDiscardLogger) Errorf(string, ...interface{}) {} -func (internalDiscardLogger) Errorln(...interface{}) {} - -func (internalDiscardLogger) Trace(...interface{}) {} -func (internalDiscardLogger) Tracef(string, ...interface{}) {} -func (internalDiscardLogger) Traceln(...interface{}) {} - -func (internalDiscardLogger) Warn(...interface{}) {} -func (internalDiscardLogger) Warnf(string, ...interface{}) {} -func (internalDiscardLogger) Warnln(...interface{}) {} - diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/doc.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/doc.go deleted file mode 100644 index 9ff8ea7..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/doc.go +++ /dev/null @@ -1,154 +0,0 @@ -/* -Package telsh provides "middleware" (for the telnet package) that can be used to implement a TELNET or TELNETS server -that provides a "shell" interface (also known as a "command-line interface" or "CLI"). - -Shell interfaces you may be familiar with include: "bash", "csh", "sh", "zsk", etc. - - -TELNET Server - -Here is an example usage: - - package main - - import ( - "github.com/reiver/go-oi" - "github.com/reiver/go-telnet" - "github.com/reiver/go-telnet/telsh" - - "io" - ) - - func main() { - - telnetHandler := telsh.NewShellHandler() - - if err := telnetHandler.RegisterElse( - telsh.ProducerFunc( - func(ctx telnet.Context, name string, args ...string) telsh.Handler { - return telsh.PromoteHandlerFunc( - func(stdin io.ReadCloser, stdout io.WriteCloser, stderr io.WriteCloser, args ...string) error { - oi.LongWrite(stdout, []byte{'w','a','t','?', '\r','\n'}) - - return nil - }, - ) - }, - ), - ); nil != err { - panic(err) - } - - if err := telnetHandler.Register("help", - telsh.ProducerFunc( - func(ctx telnet.Context, name string, args ...string) telsh.Handler { - return telsh.PromoteHandlerFunc( - func(stdin io.ReadCloser, stdout io.WriteCloser, stderr io.WriteCloser, args ...string) error { - oi.LongWrite(stdout, []byte{'r','t','f','m','!', '\r','\n'}) - - return nil - }, - ) - }, - ), - ); nil != err { - panic(err) - } - - err := telnet.ListenAndServe(":5555", telnetHandler) - if nil != err { - //@TODO: Handle this error better. - panic(err) - } - } - -Here is a more "unpacked" example: - - package main - - - import ( - "github.com/reiver/go-oi" - "github.com/reiver/go-telnet" - "github.com/reiver/go-telnet/telsh" - - "io" - "time" - ) - - - var ( - shellHandler = telsh.NewShellHandler() - ) - - - func init() { - - shellHandler.Register("dance", telsh.ProducerFunc(producer)) - - - shellHandler.WelcomeMessage = ` - __ __ ______ _ _____ ____ __ __ ______ - \ \ / /| ____|| | / ____| / __ \ | \/ || ____| - \ \ /\ / / | |__ | | | | | | | || \ / || |__ - \ \/ \/ / | __| | | | | | | | || |\/| || __| - \ /\ / | |____ | |____ | |____ | |__| || | | || |____ - \/ \/ |______||______| \_____| \____/ |_| |_||______| - - ` - } - - - func producer(ctx telnet.Context, name string, args ...string) telsh.Handler{ - return telsh.PromoteHandlerFunc(handler) - } - - - func handler(stdin io.ReadCloser, stdout io.WriteCloser, stderr io.WriteCloser, args ...string) error { - for i:=0; i<20; i++ { - oi.LongWriteString(stdout, "\r⠋") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠙") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠹") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠸") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠼") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠴") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠦") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠧") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠇") - time.Sleep(50*time.Millisecond) - - oi.LongWriteString(stdout, "\r⠏") - time.Sleep(50*time.Millisecond) - } - oi.LongWriteString(stdout, "\r \r\n") - - return nil - } - - - func main() { - - addr := ":5555" - if err := telnet.ListenAndServe(addr, shellHandler); nil != err { - panic(err) - } - } - -*/ -package telsh diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/handler.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/handler.go deleted file mode 100644 index 6ffef04..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/handler.go +++ /dev/null @@ -1,140 +0,0 @@ -package telsh - - -import ( - "io" -) - - -// Hander is an abstraction that represents a "running" shell "command". -// -// Contrast this with a Producer, which is is an abstraction that -// represents a shell "command". -// -// To use a metaphor, the differences between a Producer and a Handler, -// is like the difference between a program executable and actually running -// the program executable. -// -// Conceptually, anything that implements the Hander, and then has its Producer -// registered with ShellHandler.Register() will be available as a command. -// -// Note that Handler was intentionally made to be compatible with -// "os/exec", which is part of the Go standard library. -type Handler interface { - Run() error - - StdinPipe() (io.WriteCloser, error) - StdoutPipe() (io.ReadCloser, error) - StderrPipe() (io.ReadCloser, error) -} - - -// HandlerFunc is useful to write inline Producers, and provides an alternative to -// creating something that implements Handler directly. -// -// For example: -// -// shellHandler := telsh.NewShellHandler() -// -// shellHandler.Register("five", telsh.ProducerFunc( -// -// func(ctx telnet.Context, name string, args ...string) telsh.Handler{ -// -// return telsh.PromoteHandlerFunc( -// -// func(stdin io.ReadCloser, stdout io.WriteCloser, stderr io.WriteCloser, args ...string) error { -// oi.LongWrite(stdout, []byte{'5', '\r', '\n'}) -// -// return nil -// }, -// ) -// }, -// )) -// -// Note that PromoteHandlerFunc is used to turn a HandlerFunc into a Handler. -type HandlerFunc func(stdin io.ReadCloser, stdout io.WriteCloser, stderr io.WriteCloser, args ...string)error - - -type internalPromotedHandlerFunc struct { - err error - fn HandlerFunc - stdin io.ReadCloser - stdout io.WriteCloser - stderr io.WriteCloser - - stdinPipe io.WriteCloser - stdoutPipe io.ReadCloser - stderrPipe io.ReadCloser - - args []string -} - - -// PromoteHandlerFunc turns a HandlerFunc into a Handler. -func PromoteHandlerFunc(fn HandlerFunc, args ...string) Handler { - stdin, stdinPipe := io.Pipe() - stdoutPipe, stdout := io.Pipe() - stderrPipe, stderr := io.Pipe() - - argsCopy := make([]string, len(args)) - for i, datum := range args { - argsCopy[i] = datum - } - - handler := internalPromotedHandlerFunc{ - err:nil, - - fn:fn, - - stdin:stdin, - stdout:stdout, - stderr:stderr, - - stdinPipe:stdinPipe, - stdoutPipe:stdoutPipe, - stderrPipe:stderrPipe, - - args:argsCopy, - } - - return &handler -} - - -func (handler *internalPromotedHandlerFunc) Run() error { - if nil != handler.err { - return handler.err - } - - handler.err = handler.fn(handler.stdin, handler.stdout, handler.stderr, handler.args...) - - handler.stdin.Close() - handler.stdout.Close() - handler.stderr.Close() - - return handler.err -} - -func (handler *internalPromotedHandlerFunc) StdinPipe() (io.WriteCloser, error) { - if nil != handler.err { - return nil, handler.err - } - - return handler.stdinPipe, nil -} - -func (handler *internalPromotedHandlerFunc) StdoutPipe() (io.ReadCloser, error) { - if nil != handler.err { - return nil, handler.err - } - - return handler.stdoutPipe, nil -} - -func (handler *internalPromotedHandlerFunc) StderrPipe() (io.ReadCloser, error) { - if nil != handler.err { - return nil, handler.err - } - - return handler.stderrPipe, nil -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/help.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/help.go deleted file mode 100644 index 80aed8c..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/help.go +++ /dev/null @@ -1,120 +0,0 @@ -package telsh - - -import ( - "github.com/reiver/go-oi" - "github.com/reiver/go-telnet" - - "io" - "sort" -) - - -type internalHelpProducer struct { - shellHandler *ShellHandler -} - - -func Help(shellHandler *ShellHandler) Producer { - producer := internalHelpProducer{ - shellHandler:shellHandler, - } - - return &producer -} - - -func (producer *internalHelpProducer) Produce(telnet.Context, string, ...string) Handler { - return newHelpHandler(producer) -} - - -type internalHelpHandler struct { - helpProducer *internalHelpProducer - - err error - - stdin io.ReadCloser - stdout io.WriteCloser - stderr io.WriteCloser - - stdinPipe io.WriteCloser - stdoutPipe io.ReadCloser - stderrPipe io.ReadCloser -} - - -func newHelpHandler(helpProducer *internalHelpProducer) *internalHelpHandler { - stdin, stdinPipe := io.Pipe() - stdoutPipe, stdout := io.Pipe() - stderrPipe, stderr := io.Pipe() - - handler := internalHelpHandler{ - helpProducer:helpProducer, - - err:nil, - - stdin:stdin, - stdout:stdout, - stderr:stderr, - - stdinPipe:stdinPipe, - stdoutPipe:stdoutPipe, - stderrPipe:stderrPipe, - } - - return &handler -} - - - - -func (handler *internalHelpHandler) Run() error { - if nil != handler.err { - return handler.err - } - - //@TODO: Should this be reaching inside of ShellHandler? Maybe there should be ShellHandler public methods instead. - keys := make([]string, 1+len(handler.helpProducer.shellHandler.producers)) - i:=0 - for key,_ := range handler.helpProducer.shellHandler.producers { - keys[i] = key - i++ - } - keys[i] = handler.helpProducer.shellHandler.ExitCommandName - sort.Strings(keys) - for _, key := range keys { - oi.LongWriteString(handler.stdout, key) - oi.LongWriteString(handler.stdout, "\r\n") - } - - handler.stdin.Close() - handler.stdout.Close() - handler.stderr.Close() - - return handler.err -} - -func (handler *internalHelpHandler) StdinPipe() (io.WriteCloser, error) { - if nil != handler.err { - return nil, handler.err - } - - return handler.stdinPipe, nil -} - -func (handler *internalHelpHandler) StdoutPipe() (io.ReadCloser, error) { - if nil != handler.err { - return nil, handler.err - } - - return handler.stdoutPipe, nil -} - -func (handler *internalHelpHandler) StderrPipe() (io.ReadCloser, error) { - if nil != handler.err { - return nil, handler.err - } - - return handler.stderrPipe, nil -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/producer.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/producer.go deleted file mode 100644 index df824fc..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/producer.go +++ /dev/null @@ -1,36 +0,0 @@ -package telsh - - -import ( - "github.com/reiver/go-telnet" -) - - -// A Producer provides a Produce method which creates a Handler. -// -// Producer is an abstraction that represents a shell "command". -// -// Contrast this with a Handler, which is is an abstraction that -// represents a "running" shell "command". -// -// To use a metaphor, the differences between a Producer and a Handler, -// is like the difference between a program executable and actually running -// the program executable. -type Producer interface { - Produce(telnet.Context, string, ...string) Handler -} - - -// ProducerFunc is an adaptor, that can be used to turn a func with the -// signature: -// -// func(telnet.Context, string, ...string) Handler -// -// Into a Producer -type ProducerFunc func(telnet.Context, string, ...string) Handler - - -// Produce makes ProducerFunc fit the Producer interface. -func (fn ProducerFunc) Produce(ctx telnet.Context, name string, args ...string) Handler { - return fn(ctx, name, args...) -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/telnet_handler.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/telnet_handler.go deleted file mode 100644 index ca08c7b..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/telnet_handler.go +++ /dev/null @@ -1,297 +0,0 @@ -package telsh - - -import ( - "github.com/reiver/go-oi" - "github.com/reiver/go-telnet" - - "bytes" - "io" - "strings" - "sync" -) - - -const ( - defaultExitCommandName = "exit" - defaultPrompt = "§ " - defaultWelcomeMessage = "\r\nWelcome!\r\n" - defaultExitMessage = "\r\nGoodbye!\r\n" -) - - -type ShellHandler struct { - muxtex sync.RWMutex - producers map[string]Producer - elseProducer Producer - - ExitCommandName string - Prompt string - WelcomeMessage string - ExitMessage string -} - - -func NewShellHandler() *ShellHandler { - producers := map[string]Producer{} - - telnetHandler := ShellHandler{ - producers:producers, - - Prompt: defaultPrompt, - ExitCommandName: defaultExitCommandName, - WelcomeMessage: defaultWelcomeMessage, - ExitMessage: defaultExitMessage, - } - - return &telnetHandler -} - - -func (telnetHandler *ShellHandler) Register(name string, producer Producer) error { - - telnetHandler.muxtex.Lock() - telnetHandler.producers[name] = producer - telnetHandler.muxtex.Unlock() - - return nil -} - -func (telnetHandler *ShellHandler) MustRegister(name string, producer Producer) *ShellHandler { - if err := telnetHandler.Register(name, producer); nil != err { - panic(err) - } - - return telnetHandler -} - - -func (telnetHandler *ShellHandler) RegisterHandlerFunc(name string, handlerFunc HandlerFunc) error { - - produce := func(ctx telnet.Context, name string, args ...string) Handler { - return PromoteHandlerFunc(handlerFunc, args...) - } - - producer := ProducerFunc(produce) - - return telnetHandler.Register(name, producer) -} - -func (telnetHandler *ShellHandler) MustRegisterHandlerFunc(name string, handlerFunc HandlerFunc) *ShellHandler { - if err := telnetHandler.RegisterHandlerFunc(name, handlerFunc); nil != err { - panic(err) - } - - return telnetHandler -} - - -func (telnetHandler *ShellHandler) RegisterElse(producer Producer) error { - - telnetHandler.muxtex.Lock() - telnetHandler.elseProducer = producer - telnetHandler.muxtex.Unlock() - - return nil -} - -func (telnetHandler *ShellHandler) MustRegisterElse(producer Producer) *ShellHandler { - if err := telnetHandler.RegisterElse(producer); nil != err { - panic(err) - } - - return telnetHandler -} - - -func (telnetHandler *ShellHandler) ServeTELNET(ctx telnet.Context, writer telnet.Writer, reader telnet.Reader) { - - logger := ctx.Logger() - if nil == logger { - logger = internalDiscardLogger{} - } - - - colonSpaceCommandNotFoundEL := []byte(": command not found\r\n") - - - var prompt bytes.Buffer - var exitCommandName string - var welcomeMessage string - var exitMessage string - - prompt.WriteString(telnetHandler.Prompt) - - promptBytes := prompt.Bytes() - - exitCommandName = telnetHandler.ExitCommandName - welcomeMessage = telnetHandler.WelcomeMessage - exitMessage = telnetHandler.ExitMessage - - - if _, err := oi.LongWriteString(writer, welcomeMessage); nil != err { - logger.Errorf("Problem long writing welcome message: %v", err) - return - } - logger.Debugf("Wrote welcome message: %q.", welcomeMessage) - if _, err := oi.LongWrite(writer, promptBytes); nil != err { - logger.Errorf("Problem long writing prompt: %v", err) - return - } - logger.Debugf("Wrote prompt: %q.", promptBytes) - - - var buffer [1]byte // Seems like the length of the buffer needs to be small, otherwise will have to wait for buffer to fill up. - p := buffer[:] - - var line bytes.Buffer - - for { - // Read 1 byte. - n, err := reader.Read(p) - if n <= 0 && nil == err { - continue - } else if n <= 0 && nil != err { - break - } - - - line.WriteByte(p[0]) - //logger.Tracef("Received: %q (%d).", p[0], p[0]) - - - if '\n' == p[0] { - lineString := line.String() - - if "\r\n" == lineString { - line.Reset() - if _, err := oi.LongWrite(writer, promptBytes); nil != err { - return - } - continue - } - - -//@TODO: support piping. - fields := strings.Fields(lineString) - logger.Debugf("Have %d tokens.", len(fields)) - logger.Tracef("Tokens: %v", fields) - if len(fields) <= 0 { - line.Reset() - if _, err := oi.LongWrite(writer, promptBytes); nil != err { - return - } - continue - } - - - field0 := fields[0] - - if exitCommandName == field0 { - oi.LongWriteString(writer, exitMessage) - return - } - - - var producer Producer - - telnetHandler.muxtex.RLock() - var ok bool - producer, ok = telnetHandler.producers[field0] - telnetHandler.muxtex.RUnlock() - - if !ok { - telnetHandler.muxtex.RLock() - producer = telnetHandler.elseProducer - telnetHandler.muxtex.RUnlock() - } - - if nil == producer { -//@TODO: Don't convert that to []byte! think this creates "garbage" (for collector). - oi.LongWrite(writer, []byte(field0)) - oi.LongWrite(writer, colonSpaceCommandNotFoundEL) - line.Reset() - if _, err := oi.LongWrite(writer, promptBytes); nil != err { - return - } - continue - } - - handler := producer.Produce(ctx, field0, fields[1:]...) - if nil == handler { - oi.LongWrite(writer, []byte(field0)) -//@TODO: Need to use a different error message. - oi.LongWrite(writer, colonSpaceCommandNotFoundEL) - line.Reset() - oi.LongWrite(writer, promptBytes) - continue - } - -//@TODO: Wire up the stdin, stdout, stderr of the handler. - - if stdoutPipe, err := handler.StdoutPipe(); nil != err { -//@TODO: - } else if nil == stdoutPipe { -//@TODO: - } else { - connect(ctx, writer, stdoutPipe) - } - - - if stderrPipe, err := handler.StderrPipe(); nil != err { -//@TODO: - } else if nil == stderrPipe { -//@TODO: - } else { - connect(ctx, writer, stderrPipe) - } - - - if err := handler.Run(); nil != err { -//@TODO: - } - line.Reset() - if _, err := oi.LongWrite(writer, promptBytes); nil != err { - return - } - } - - -//@TODO: Are there any special errors we should be dealing with separately? - if nil != err { - break - } - } - - - oi.LongWriteString(writer, exitMessage) - return -} - - - -func connect(ctx telnet.Context, writer io.Writer, reader io.Reader) { - - logger := ctx.Logger() - - go func(logger telnet.Logger){ - - var buffer [1]byte // Seems like the length of the buffer needs to be small, otherwise will have to wait for buffer to fill up. - p := buffer[:] - - for { - // Read 1 byte. - n, err := reader.Read(p) - if n <= 0 && nil == err { - continue - } else if n <= 0 && nil != err { - break - } - - //logger.Tracef("Sending: %q.", p) -//@TODO: Should we be checking for errors? - oi.LongWrite(writer, p) - //logger.Tracef("Sent: %q.", p) - } - }(logger) -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/telnet_handler_test.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/telnet_handler_test.go deleted file mode 100644 index 1053d43..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/telsh/telnet_handler_test.go +++ /dev/null @@ -1,110 +0,0 @@ -package telsh - - -import ( - "github.com/reiver/go-telnet" - - "bytes" - "strings" - - "testing" -) - - -func TestServeTELNETCommandNotFound(t *testing.T) { - - tests := []struct{ - ClientSends string - Expected string - }{ - { - ClientSends: "\r\n", - Expected: "", - }, - - - - { - ClientSends: "apple\r\n", - Expected: "apple: command not found\r\n", - }, - { - ClientSends: "banana\r\n", - Expected: "banana: command not found\r\n", - }, - { - ClientSends: "cherry\r\n", - Expected: "cherry: command not found\r\n", - }, - - - - { - ClientSends: "\t\r\n", - Expected: "", - }, - { - ClientSends: "\t\t\r\n", - Expected: "", - }, - { - ClientSends: "\t\t\t\r\n", - Expected: "", - }, - - - - { - ClientSends: " \r\n", - Expected: "", - }, - { - ClientSends: " \r\n", - Expected: "", - }, - { - ClientSends: " \r\n", - Expected: "", - }, - - - - { - ClientSends: " \t\r\n", - Expected: "", - }, - { - ClientSends: "\t \r\n", - Expected: "", - }, - - - - { - ClientSends: "ls -alF\r\n", - Expected: "ls: command not found\r\n", - }, - } - - - for testNumber, test := range tests { - - shellHandler := NewShellHandler() - if nil == shellHandler { - t.Errorf("For test #%d, did not expect to get nil, but actually got it: %v; for client sent: %q", testNumber, shellHandler, test.ClientSends) - continue - } - - - ctx := telnet.NewContext() - - var buffer bytes.Buffer - - shellHandler.ServeTELNET(ctx, &buffer, strings.NewReader(test.ClientSends)) - - if expected, actual := shellHandler.WelcomeMessage+shellHandler.Prompt+test.Expected+shellHandler.Prompt+shellHandler.ExitMessage, buffer.String(); expected != actual { - t.Errorf("For test #%d, expect %q, but actually got %q; for client sent: %q", testNumber, expected, actual, test.ClientSends) - continue - } - } -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/tls.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/tls.go deleted file mode 100644 index c5606a3..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/tls.go +++ /dev/null @@ -1,113 +0,0 @@ -package telnet - - -import ( - "crypto/tls" - "net" -) - - -// ListenAndServeTLS acts identically to ListenAndServe, except that it -// uses the TELNET protocol over TLS. -// -// From a TELNET protocol point-of-view, it allows for 'secured telnet', also known as TELNETS, -// which by default listens to port 992. -// -// Of course, this port can be overridden using the 'addr' argument. -// -// For a very simple example: -// -// package main -// -// import ( -// "github.com/reiver/go-telnet" -// ) -// -// func main() { -// -// //@TODO: In your code, you would probably want to use a different handler. -// var handler telnet.Handler = telnet.EchoHandler -// -// err := telnet.ListenAndServeTLS(":5555", "cert.pem", "key.pem", handler) -// if nil != err { -// //@TODO: Handle this error better. -// panic(err) -// } -// } -func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) error { - server := &Server{Addr: addr, Handler: handler} - return server.ListenAndServeTLS(certFile, keyFile) -} - - - -// ListenAndServeTLS acts identically to ListenAndServe, except that it -// uses the TELNET protocol over TLS. -// -// From a TELNET protocol point-of-view, it allows for 'secured telnet', also known as TELNETS, -// which by default listens to port 992. -func (server *Server) ListenAndServeTLS(certFile string, keyFile string) error { - - addr := server.Addr - if "" == addr { - addr = ":telnets" - } - - - listener, err := net.Listen("tcp", addr) - if nil != err { - return err - } - - - // Apparently have to make a copy of the TLS config this way, rather than by - // simple assignment, to prevent some unexported fields from being copied over. - // - // It would be nice if tls.Config had a method that would do this "safely". - // (I.e., what happens if in the future more exported fields are added to - // tls.Config?) - var tlsConfig *tls.Config = nil - if nil == server.TLSConfig { - tlsConfig = &tls.Config{} - } else { - tlsConfig = &tls.Config{ - Rand: server.TLSConfig.Rand, - Time: server.TLSConfig.Time, - Certificates: server.TLSConfig.Certificates, - NameToCertificate: server.TLSConfig.NameToCertificate, - GetCertificate: server.TLSConfig.GetCertificate, - RootCAs: server.TLSConfig.RootCAs, - NextProtos: server.TLSConfig.NextProtos, - ServerName: server.TLSConfig.ServerName, - ClientAuth: server.TLSConfig.ClientAuth, - ClientCAs: server.TLSConfig.ClientCAs, - InsecureSkipVerify: server.TLSConfig.InsecureSkipVerify, - CipherSuites: server.TLSConfig.CipherSuites, - PreferServerCipherSuites: server.TLSConfig.PreferServerCipherSuites, - SessionTicketsDisabled: server.TLSConfig.SessionTicketsDisabled, - SessionTicketKey: server.TLSConfig.SessionTicketKey, - ClientSessionCache: server.TLSConfig.ClientSessionCache, - MinVersion: server.TLSConfig.MinVersion, - MaxVersion: server.TLSConfig.MaxVersion, - CurvePreferences: server.TLSConfig.CurvePreferences, - } - } - - - tlsConfigHasCertificate := len(tlsConfig.Certificates) > 0 || nil != tlsConfig.GetCertificate - if "" == certFile || "" == keyFile || !tlsConfigHasCertificate { - tlsConfig.Certificates = make([]tls.Certificate, 1) - - var err error - tlsConfig.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile) - if nil != err { - return err - } - } - - - tlsListener := tls.NewListener(listener, tlsConfig) - - - return server.Serve(tlsListener) -} diff --git a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/writer.go b/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/writer.go deleted file mode 100644 index a42d04f..0000000 --- a/proxy_go/public/go-telnet@v0.0.0-20180421082511-9ff0b2ab096e/writer.go +++ /dev/null @@ -1,6 +0,0 @@ -package telnet - - -type Writer interface { - Write([]byte) (int, error) -} diff --git a/proxy_go/public/logger_conf@v1.0.0/conf.go b/proxy_go/public/logger_conf@v1.0.0/conf.go deleted file mode 100644 index eded158..0000000 --- a/proxy_go/public/logger_conf@v1.0.0/conf.go +++ /dev/null @@ -1,60 +0,0 @@ -package logger_conf - -import ( - "log" - "os" - "strconv" -) - -//var Free5gcLogDir string = path_util.Free5gcPath("free5gc/log") + "/" -var Free5gcLogDir string = "/var/log/" -var LibLogDir string = Free5gcLogDir + "lib/" -var NfLogDir string = Free5gcLogDir + "nf/" - -var Free5gcLogFile string = Free5gcLogDir + "proxy_go.log" - -func init() { - if err := os.MkdirAll(LibLogDir, 0775); err != nil { - log.Printf("Mkdir %s failed: %+v", LibLogDir, err) - } - if err := os.MkdirAll(NfLogDir, 0775); err != nil { - log.Printf("Mkdir %s failed: %+v", NfLogDir, err) - } - - // Create log file or if it already exist, check if user can access it - f, fileOpenErr := os.OpenFile(Free5gcLogFile, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666) - if fileOpenErr != nil { - // user cannot access it. - log.Printf("Cannot Open %s\n", Free5gcLogFile) - } else { - // user can access it - if err := f.Close(); err != nil { - log.Printf("File %s cannot been closed\n", Free5gcLogFile) - } - } - - sudoUID, errUID := strconv.Atoi(os.Getenv("SUDO_UID")) - sudoGID, errGID := strconv.Atoi(os.Getenv("SUDO_GID")) - - if errUID == nil && errGID == nil { - // if using sudo to run the program, errUID will be nil and sudoUID will get the uid who run sudo - // else errUID will not be nil and sudoUID will be nil - // If user using sudo to run the program and create log file, log will own by root, - // here we change own to user so user can view and reuse the file - if err := os.Chown(Free5gcLogDir, sudoUID, sudoGID); err != nil { - log.Printf("Dir %s chown to %d:%d error: %v\n", Free5gcLogDir, sudoUID, sudoGID, err) - } - if err := os.Chown(LibLogDir, sudoUID, sudoGID); err != nil { - log.Printf("Dir %s chown to %d:%d error: %v\n", LibLogDir, sudoUID, sudoGID, err) - } - if err := os.Chown(NfLogDir, sudoUID, sudoGID); err != nil { - log.Printf("Dir %s chown to %d:%d error: %v\n", NfLogDir, sudoUID, sudoGID, err) - } - - if fileOpenErr == nil { - if err := os.Chown(Free5gcLogFile, sudoUID, sudoGID); err != nil { - log.Printf("File %s chown to %d:%d error: %v\n", Free5gcLogFile, sudoUID, sudoGID, err) - } - } - } -} diff --git a/proxy_go/public/logger_conf@v1.0.0/go.sum b/proxy_go/public/logger_conf@v1.0.0/go.sum deleted file mode 100644 index 1848efe..0000000 --- a/proxy_go/public/logger_conf@v1.0.0/go.sum +++ /dev/null @@ -1,22 +0,0 @@ -github.com/free5gc/path_util v0.0.0-20201212235135-42ce24f2b9c9 h1:GzLy+VsNFUruyrgM5GECl6QEq2/43rZQxvrjEFWuXQI= -github.com/free5gc/path_util v0.0.0-20201212235135-42ce24f2b9c9/go.mod h1:8KT1mRTxzh0STAR4juLuvsCo3y1kTUHQ9X+OIeagU4k= -github.com/antonfisher/nested-logrus-formatter v1.3.0 h1:8zixYquU1Odk+vzAaAQPAdRh1ZjmUXNQ1T+dUBvlhVo= -github.com/antonfisher/nested-logrus-formatter v1.3.0/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -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/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f h1:QdHQnPce6K4XQewki9WNbG5KOROuDzqO3NaYjI1cXJ0= -golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -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/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/proxy_go/public/logger_util@v1.0.0/go.sum b/proxy_go/public/logger_util@v1.0.0/go.sum deleted file mode 100644 index 04662ed..0000000 --- a/proxy_go/public/logger_util@v1.0.0/go.sum +++ /dev/null @@ -1,147 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/antonfisher/nested-logrus-formatter v1.3.0 h1:8zixYquU1Odk+vzAaAQPAdRh1ZjmUXNQ1T+dUBvlhVo= -github.com/antonfisher/nested-logrus-formatter v1.3.0/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= -github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go v1.2.1 h1:dz+JxTe7GZQdErTo7SREc1jQj/hFP1k7jyIAwODoW+k= -github.com/ugorji/go v1.2.1/go.mod h1:cSVypSfTLm2o9fKxXvQgn3rMmkPXovcWor6Qn5tbFmI= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ugorji/go/codec v1.2.1 h1:/TRfW3XKkvWvmAYyCUaQlhoCDGjcvNR8xVVA/l5p/jQ= -github.com/ugorji/go/codec v1.2.1/go.mod h1:s/WxCRi46t8rA+fowL40EnmD7ec0XhR7ZypxeBNdzsM= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9 h1:sYNJzB4J8toYPQTM6pAkcmBRgw9SnQKP9oXCHfgy604= -golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f h1:QdHQnPce6K4XQewki9WNbG5KOROuDzqO3NaYjI1cXJ0= -golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -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/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/proxy_go/public/logger_util@v1.0.0/logger_util.go b/proxy_go/public/logger_util@v1.0.0/logger_util.go deleted file mode 100644 index b31243c..0000000 --- a/proxy_go/public/logger_util@v1.0.0/logger_util.go +++ /dev/null @@ -1,147 +0,0 @@ -package logger_util - -import ( - "fmt" - "log" - "os" - "path" - "runtime" - - formatter "github.com/antonfisher/nested-logrus-formatter" - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" -) - -const ( - maxLogFileSize = 1024*1024*128 - maxLogFile = 8 -) - -type FileHook struct { - file *os.File - flag int - chmod os.FileMode - formatter *formatter.Formatter -} - -func renameFiles(file string) { - var oldFileName, newFileName string - var i int - for i = maxLogFile-1; i > 0; i-- { - if i > 1 { - oldFileName = fmt.Sprintf("%s.%d",file, i-1) - } else { - oldFileName = file - } - if _, err := os.Stat(oldFileName); err == nil { - newFileName = fmt.Sprintf("%s.%d", file, i) - os.Rename(oldFileName, newFileName) - } - } -} - -func NewFileHook(file string, flag int, chmod os.FileMode) (*FileHook, error) { - plainFormatter := &formatter.Formatter{ - TimestampFormat: "2006-01-02 15:04:05.000", - TrimMessages: true, - NoColors: true, - NoFieldsColors: true, - NoFieldsSpace: true, - HideKeys: true, - FieldsOrder: []string{"component", "category", "remote_addr"}, - CallerFirst: true, - CustomCallerFormatter: func(f *runtime.Frame) string { - file := path.Base(f.File) - if len(file) > 25 { - file = file[len(file)-25:] - } - return fmt.Sprintf(" %15s:%04d", file, f.Line) - }, - } - - logFile, err := os.OpenFile(file, flag, chmod) - if err != nil { - fmt.Fprintf(os.Stderr, "unable to write file on filehook %v", err) - return nil, err - } - - return &FileHook{logFile, flag, chmod, plainFormatter}, err -} - -// Fire event -func (hook *FileHook) Fire(entry *logrus.Entry) error { - var line string - - info, err := hook.file.Stat() - if err != nil { - return err - } - if info.Size() > maxLogFileSize { - fileInfo, err := os.Stat(hook.file.Name()) - if err != nil { - return err - } - if fileInfo.Size() > maxLogFileSize { - renameFiles(hook.file.Name()) - } - hook.file.Close() - if hook.file, err = os.OpenFile(hook.file.Name(), hook.flag, hook.chmod); err != nil { - fmt.Fprintf(os.Stderr, "unable to write file on filehook %v", err) - return err - } - } - - if plainformat, err := hook.formatter.Format(entry); err != nil { - log.Printf("Formatter error: %+v", err) - return err - } else { - line = string(plainformat) - } - if _, err := hook.file.WriteString(line); err != nil { - fmt.Fprintf(os.Stderr, "unable to write file on filehook(entry.String)%v", err) - return err - } - - return nil -} - -func (hook *FileHook) Levels() []logrus.Level { - return []logrus.Level{ - logrus.PanicLevel, - logrus.FatalLevel, - logrus.ErrorLevel, - logrus.WarnLevel, - logrus.InfoLevel, - logrus.DebugLevel, - } -} - -//The Middleware will write the Gin logs to logrus. -func ginToLogrus(log *logrus.Entry) gin.HandlerFunc { - return func(c *gin.Context) { - path := c.Request.URL.Path - raw := c.Request.URL.RawQuery - - // Process request - c.Next() - - clientIP := c.ClientIP() - method := c.Request.Method - statusCode := c.Writer.Status() - errorMessage := c.Errors.ByType(gin.ErrorTypePrivate).String() - - if raw != "" { - path = path + "?" + raw - } - - log.Infof("| %3d | %15s | %-7s | %s | %s", - statusCode, clientIP, method, path, errorMessage) - } -} - -//NewGinWithLogrus - returns an Engine instance with the ginToLogrus and Recovery middleware already attached. -func NewGinWithLogrus(log *logrus.Entry) *gin.Engine { - engine := gin.New() - engine.Use(ginToLogrus(log), gin.Recovery()) - return engine -} diff --git a/proxy_go/public/mysql@v1.6.0/.github/CONTRIBUTING.md b/proxy_go/public/mysql@v1.6.0/.github/CONTRIBUTING.md deleted file mode 100644 index 8fe16bc..0000000 --- a/proxy_go/public/mysql@v1.6.0/.github/CONTRIBUTING.md +++ /dev/null @@ -1,23 +0,0 @@ -# Contributing Guidelines - -## Reporting Issues - -Before creating a new Issue, please check first if a similar Issue [already exists](https://github.com/go-sql-driver/mysql/issues?state=open) or was [recently closed](https://github.com/go-sql-driver/mysql/issues?direction=desc&page=1&sort=updated&state=closed). - -## Contributing Code - -By contributing to this project, you share your code under the Mozilla Public License 2, as specified in the LICENSE file. -Don't forget to add yourself to the AUTHORS file. - -### Code Review - -Everyone is invited to review and comment on pull requests. -If it looks fine to you, comment with "LGTM" (Looks good to me). - -If changes are required, notice the reviewers with "PTAL" (Please take another look) after committing the fixes. - -Before merging the Pull Request, at least one [team member](https://github.com/go-sql-driver?tab=members) must have commented with "LGTM". - -## Development Ideas - -If you are looking for ideas for code contributions, please check our [Development Ideas](https://github.com/go-sql-driver/mysql/wiki/Development-Ideas) Wiki page. diff --git a/proxy_go/public/mysql@v1.6.0/.github/ISSUE_TEMPLATE.md b/proxy_go/public/mysql@v1.6.0/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index d9771f1..0000000 --- a/proxy_go/public/mysql@v1.6.0/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,21 +0,0 @@ -### Issue description -Tell us what should happen and what happens instead - -### Example code -```go -If possible, please enter some example code here to reproduce the issue. -``` - -### Error log -``` -If you have an error log, please paste it here. -``` - -### Configuration -*Driver version (or git SHA):* - -*Go version:* run `go version` in your console - -*Server version:* E.g. MySQL 5.6, MariaDB 10.0.20 - -*Server OS:* E.g. Debian 8.1 (Jessie), Windows 10 diff --git a/proxy_go/public/mysql@v1.6.0/.github/PULL_REQUEST_TEMPLATE.md b/proxy_go/public/mysql@v1.6.0/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 6f5c7eb..0000000 --- a/proxy_go/public/mysql@v1.6.0/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,9 +0,0 @@ -### Description -Please explain the changes you made here. - -### Checklist -- [ ] Code compiles correctly -- [ ] Created tests which fail without the change (if possible) -- [ ] All tests passing -- [ ] Extended the README / documentation, if necessary -- [ ] Added myself / the copyright holder to the AUTHORS file diff --git a/proxy_go/public/mysql@v1.6.0/.github/workflows/test.yml b/proxy_go/public/mysql@v1.6.0/.github/workflows/test.yml deleted file mode 100644 index 8860021..0000000 --- a/proxy_go/public/mysql@v1.6.0/.github/workflows/test.yml +++ /dev/null @@ -1,104 +0,0 @@ -name: test -on: - pull_request: - push: - workflow_dispatch: - -env: - MYSQL_TEST_USER: gotest - MYSQL_TEST_PASS: secret - MYSQL_TEST_ADDR: 127.0.0.1:3306 - MYSQL_TEST_CONCURRENT: 1 - -jobs: - list: - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.set-matrix.outputs.matrix }} - steps: - - name: list - id: set-matrix - run: | - import json - go = [ - # Keep the most recent production release at the top - '1.16', - # Older production releases - '1.15', - '1.14', - '1.13', - '1.12', - '1.11', - ] - mysql = [ - '8.0', - '5.7', - '5.6', - 'mariadb-10.5', - 'mariadb-10.4', - 'mariadb-10.3', - ] - - includes = [] - # Go versions compatibility check - for v in go[1:]: - includes.append({'os': 'ubuntu-latest', 'go': v, 'mysql': mysql[0]}) - - matrix = { - # OS vs MySQL versions - 'os': [ 'ubuntu-latest', 'macos-latest', 'windows-latest' ], - 'go': [ go[0] ], - 'mysql': mysql, - - 'include': includes - } - output = json.dumps(matrix, separators=(',', ':')) - print('::set-output name=matrix::{0}'.format(output)) - shell: python - test: - needs: list - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: ${{ fromJSON(needs.list.outputs.matrix) }} - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go }} - - uses: shogo82148/actions-setup-mysql@v1 - with: - mysql-version: ${{ matrix.mysql }} - user: ${{ env.MYSQL_TEST_USER }} - password: ${{ env.MYSQL_TEST_PASS }} - my-cnf: | - innodb_log_file_size=256MB - innodb_buffer_pool_size=512MB - max_allowed_packet=16MB - ; TestConcurrent fails if max_connections is too large - max_connections=50 - local_infile=1 - - name: setup database - run: | - mysql --user 'root' --host '127.0.0.1' -e 'create database gotest;' - - - name: test - run: | - go test -v '-covermode=count' '-coverprofile=coverage.out' - - - name: Send coverage - uses: shogo82148/actions-goveralls@v1 - with: - path-to-profile: coverage.out - flag-name: ${{ runner.os }}-Go-${{ matrix.go }}-DB-${{ matrix.mysql }} - parallel: true - - # notifies that all test jobs are finished. - finish: - needs: test - if: always() - runs-on: ubuntu-latest - steps: - - uses: shogo82148/actions-goveralls@v1 - with: - parallel-finished: true diff --git a/proxy_go/public/mysql@v1.6.0/.gitignore b/proxy_go/public/mysql@v1.6.0/.gitignore deleted file mode 100644 index 2de28da..0000000 --- a/proxy_go/public/mysql@v1.6.0/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -.DS_Store -.DS_Store? -._* -.Spotlight-V100 -.Trashes -Icon? -ehthumbs.db -Thumbs.db -.idea diff --git a/proxy_go/public/mysql@v1.6.0/AUTHORS b/proxy_go/public/mysql@v1.6.0/AUTHORS deleted file mode 100644 index 50afa2c..0000000 --- a/proxy_go/public/mysql@v1.6.0/AUTHORS +++ /dev/null @@ -1,117 +0,0 @@ -# This is the official list of Go-MySQL-Driver authors for copyright purposes. - -# If you are submitting a patch, please add your name or the name of the -# organization which holds the copyright to this list in alphabetical order. - -# Names should be added to this file as -# Name -# The email address is not required for organizations. -# Please keep the list sorted. - - -# Individual Persons - -Aaron Hopkins -Achille Roussel -Alex Snast -Alexey Palazhchenko -Andrew Reid -Animesh Ray -Arne Hormann -Ariel Mashraki -Asta Xie -Bulat Gaifullin -Caine Jette -Carlos Nieto -Chris Moos -Craig Wilson -Daniel Montoya -Daniel Nichter -Daniël van Eeden -Dave Protasowski -DisposaBoy -Egor Smolyakov -Erwan Martin -Evan Shaw -Frederick Mayle -Gustavo Kristic -Hajime Nakagami -Hanno Braun -Henri Yandell -Hirotaka Yamamoto -Huyiguang -ICHINOSE Shogo -Ilia Cimpoes -INADA Naoki -Jacek Szwec -James Harr -Jeff Hodges -Jeffrey Charles -Jerome Meyer -Jiajia Zhong -Jian Zhen -Joshua Prunier -Julien Lefevre -Julien Schmidt -Justin Li -Justin Nuß -Kamil Dziedzic -Kei Kamikawa -Kevin Malachowski -Kieron Woodhouse -Lennart Rudolph -Leonardo YongUk Kim -Linh Tran Tuan -Lion Yang -Luca Looz -Lucas Liu -Luke Scott -Maciej Zimnoch -Michael Woolnough -Nathanial Murphy -Nicola Peduzzi -Olivier Mengué -oscarzhao -Paul Bonser -Peter Schultz -Rebecca Chin -Reed Allman -Richard Wilkes -Robert Russell -Runrioter Wung -Sho Iizuka -Sho Ikeda -Shuode Li -Simon J Mudd -Soroush Pour -Stan Putrya -Stanley Gunawan -Steven Hartland -Tan Jinhua <312841925 at qq.com> -Thomas Wodarek -Tim Ruffles -Tom Jenkinson -Vladimir Kovpak -Vladyslav Zhelezniak -Xiangyu Hu -Xiaobing Jiang -Xiuming Chen -Xuehong Chan -Zhenye Xie -Zhixin Wen - -# Organizations - -Barracuda Networks, Inc. -Counting Ltd. -DigitalOcean Inc. -Facebook Inc. -GitHub Inc. -Google Inc. -InfoSum Ltd. -Keybase Inc. -Multiplay Ltd. -Percona LLC -Pivotal Inc. -Stripe Inc. -Zendesk Inc. diff --git a/proxy_go/public/mysql@v1.6.0/CHANGELOG.md b/proxy_go/public/mysql@v1.6.0/CHANGELOG.md deleted file mode 100644 index 72a738e..0000000 --- a/proxy_go/public/mysql@v1.6.0/CHANGELOG.md +++ /dev/null @@ -1,232 +0,0 @@ -## Version 1.6 (2021-04-01) - -Changes: - - - Migrate the CI service from travis-ci to GitHub Actions (#1176, #1183, #1190) - - `NullTime` is deprecated (#960, #1144) - - Reduce allocations when building SET command (#1111) - - Performance improvement for time formatting (#1118) - - Performance improvement for time parsing (#1098, #1113) - -New Features: - - - Implement `driver.Validator` interface (#1106, #1174) - - Support returning `uint64` from `Valuer` in `ConvertValue` (#1143) - - Add `json.RawMessage` for converter and prepared statement (#1059) - - Interpolate `json.RawMessage` as `string` (#1058) - - Implements `CheckNamedValue` (#1090) - -Bugfixes: - - - Stop rounding times (#1121, #1172) - - Put zero filler into the SSL handshake packet (#1066) - - Fix checking cancelled connections back into the connection pool (#1095) - - Fix remove last 0 byte for mysql_old_password when password is empty (#1133) - - -## Version 1.5 (2020-01-07) - -Changes: - - - Dropped support Go 1.9 and lower (#823, #829, #886, #1016, #1017) - - Improve buffer handling (#890) - - Document potentially insecure TLS configs (#901) - - Use a double-buffering scheme to prevent data races (#943) - - Pass uint64 values without converting them to string (#838, #955) - - Update collations and make utf8mb4 default (#877, #1054) - - Make NullTime compatible with sql.NullTime in Go 1.13+ (#995) - - Removed CloudSQL support (#993, #1007) - - Add Go Module support (#1003) - -New Features: - - - Implement support of optional TLS (#900) - - Check connection liveness (#934, #964, #997, #1048, #1051, #1052) - - Implement Connector Interface (#941, #958, #1020, #1035) - -Bugfixes: - - - Mark connections as bad on error during ping (#875) - - Mark connections as bad on error during dial (#867) - - Fix connection leak caused by rapid context cancellation (#1024) - - Mark connections as bad on error during Conn.Prepare (#1030) - - -## Version 1.4.1 (2018-11-14) - -Bugfixes: - - - Fix TIME format for binary columns (#818) - - Fix handling of empty auth plugin names (#835) - - Fix caching_sha2_password with empty password (#826) - - Fix canceled context broke mysqlConn (#862) - - Fix OldAuthSwitchRequest support (#870) - - Fix Auth Response packet for cleartext password (#887) - -## Version 1.4 (2018-06-03) - -Changes: - - - Documentation fixes (#530, #535, #567) - - Refactoring (#575, #579, #580, #581, #603, #615, #704) - - Cache column names (#444) - - Sort the DSN parameters in DSNs generated from a config (#637) - - Allow native password authentication by default (#644) - - Use the default port if it is missing in the DSN (#668) - - Removed the `strict` mode (#676) - - Do not query `max_allowed_packet` by default (#680) - - Dropped support Go 1.6 and lower (#696) - - Updated `ConvertValue()` to match the database/sql/driver implementation (#760) - - Document the usage of `0000-00-00T00:00:00` as the time.Time zero value (#783) - - Improved the compatibility of the authentication system (#807) - -New Features: - - - Multi-Results support (#537) - - `rejectReadOnly` DSN option (#604) - - `context.Context` support (#608, #612, #627, #761) - - Transaction isolation level support (#619, #744) - - Read-Only transactions support (#618, #634) - - `NewConfig` function which initializes a config with default values (#679) - - Implemented the `ColumnType` interfaces (#667, #724) - - Support for custom string types in `ConvertValue` (#623) - - Implemented `NamedValueChecker`, improving support for uint64 with high bit set (#690, #709, #710) - - `caching_sha2_password` authentication plugin support (#794, #800, #801, #802) - - Implemented `driver.SessionResetter` (#779) - - `sha256_password` authentication plugin support (#808) - -Bugfixes: - - - Use the DSN hostname as TLS default ServerName if `tls=true` (#564, #718) - - Fixed LOAD LOCAL DATA INFILE for empty files (#590) - - Removed columns definition cache since it sometimes cached invalid data (#592) - - Don't mutate registered TLS configs (#600) - - Make RegisterTLSConfig concurrency-safe (#613) - - Handle missing auth data in the handshake packet correctly (#646) - - Do not retry queries when data was written to avoid data corruption (#302, #736) - - Cache the connection pointer for error handling before invalidating it (#678) - - Fixed imports for appengine/cloudsql (#700) - - Fix sending STMT_LONG_DATA for 0 byte data (#734) - - Set correct capacity for []bytes read from length-encoded strings (#766) - - Make RegisterDial concurrency-safe (#773) - - -## Version 1.3 (2016-12-01) - -Changes: - - - Go 1.1 is no longer supported - - Use decimals fields in MySQL to format time types (#249) - - Buffer optimizations (#269) - - TLS ServerName defaults to the host (#283) - - Refactoring (#400, #410, #437) - - Adjusted documentation for second generation CloudSQL (#485) - - Documented DSN system var quoting rules (#502) - - Made statement.Close() calls idempotent to avoid errors in Go 1.6+ (#512) - -New Features: - - - Enable microsecond resolution on TIME, DATETIME and TIMESTAMP (#249) - - Support for returning table alias on Columns() (#289, #359, #382) - - Placeholder interpolation, can be actived with the DSN parameter `interpolateParams=true` (#309, #318, #490) - - Support for uint64 parameters with high bit set (#332, #345) - - Cleartext authentication plugin support (#327) - - Exported ParseDSN function and the Config struct (#403, #419, #429) - - Read / Write timeouts (#401) - - Support for JSON field type (#414) - - Support for multi-statements and multi-results (#411, #431) - - DSN parameter to set the driver-side max_allowed_packet value manually (#489) - - Native password authentication plugin support (#494, #524) - -Bugfixes: - - - Fixed handling of queries without columns and rows (#255) - - Fixed a panic when SetKeepAlive() failed (#298) - - Handle ERR packets while reading rows (#321) - - Fixed reading NULL length-encoded integers in MySQL 5.6+ (#349) - - Fixed absolute paths support in LOAD LOCAL DATA INFILE (#356) - - Actually zero out bytes in handshake response (#378) - - Fixed race condition in registering LOAD DATA INFILE handler (#383) - - Fixed tests with MySQL 5.7.9+ (#380) - - QueryUnescape TLS config names (#397) - - Fixed "broken pipe" error by writing to closed socket (#390) - - Fixed LOAD LOCAL DATA INFILE buffering (#424) - - Fixed parsing of floats into float64 when placeholders are used (#434) - - Fixed DSN tests with Go 1.7+ (#459) - - Handle ERR packets while waiting for EOF (#473) - - Invalidate connection on error while discarding additional results (#513) - - Allow terminating packets of length 0 (#516) - - -## Version 1.2 (2014-06-03) - -Changes: - - - We switched back to a "rolling release". `go get` installs the current master branch again - - Version v1 of the driver will not be maintained anymore. Go 1.0 is no longer supported by this driver - - Exported errors to allow easy checking from application code - - Enabled TCP Keepalives on TCP connections - - Optimized INFILE handling (better buffer size calculation, lazy init, ...) - - The DSN parser also checks for a missing separating slash - - Faster binary date / datetime to string formatting - - Also exported the MySQLWarning type - - mysqlConn.Close returns the first error encountered instead of ignoring all errors - - writePacket() automatically writes the packet size to the header - - readPacket() uses an iterative approach instead of the recursive approach to merge splitted packets - -New Features: - - - `RegisterDial` allows the usage of a custom dial function to establish the network connection - - Setting the connection collation is possible with the `collation` DSN parameter. This parameter should be preferred over the `charset` parameter - - Logging of critical errors is configurable with `SetLogger` - - Google CloudSQL support - -Bugfixes: - - - Allow more than 32 parameters in prepared statements - - Various old_password fixes - - Fixed TestConcurrent test to pass Go's race detection - - Fixed appendLengthEncodedInteger for large numbers - - Renamed readLengthEnodedString to readLengthEncodedString and skipLengthEnodedString to skipLengthEncodedString (fixed typo) - - -## Version 1.1 (2013-11-02) - -Changes: - - - Go-MySQL-Driver now requires Go 1.1 - - Connections now use the collation `utf8_general_ci` by default. Adding `&charset=UTF8` to the DSN should not be necessary anymore - - Made closing rows and connections error tolerant. This allows for example deferring rows.Close() without checking for errors - - `[]byte(nil)` is now treated as a NULL value. Before, it was treated like an empty string / `[]byte("")` - - DSN parameter values must now be url.QueryEscape'ed. This allows text values to contain special characters, such as '&'. - - Use the IO buffer also for writing. This results in zero allocations (by the driver) for most queries - - Optimized the buffer for reading - - stmt.Query now caches column metadata - - New Logo - - Changed the copyright header to include all contributors - - Improved the LOAD INFILE documentation - - The driver struct is now exported to make the driver directly accessible - - Refactored the driver tests - - Added more benchmarks and moved all to a separate file - - Other small refactoring - -New Features: - - - Added *old_passwords* support: Required in some cases, but must be enabled by adding `allowOldPasswords=true` to the DSN since it is insecure - - Added a `clientFoundRows` parameter: Return the number of matching rows instead of the number of rows changed on UPDATEs - - Added TLS/SSL support: Use a TLS/SSL encrypted connection to the server. Custom TLS configs can be registered and used - -Bugfixes: - - - Fixed MySQL 4.1 support: MySQL 4.1 sends packets with lengths which differ from the specification - - Convert to DB timezone when inserting `time.Time` - - Splitted packets (more than 16MB) are now merged correctly - - Fixed false positive `io.EOF` errors when the data was fully read - - Avoid panics on reuse of closed connections - - Fixed empty string producing false nil values - - Fixed sign byte for positive TIME fields - - -## Version 1.0 (2013-05-14) - -Initial Release diff --git a/proxy_go/public/mysql@v1.6.0/LICENSE b/proxy_go/public/mysql@v1.6.0/LICENSE deleted file mode 100644 index 14e2f77..0000000 --- a/proxy_go/public/mysql@v1.6.0/LICENSE +++ /dev/null @@ -1,373 +0,0 @@ -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/proxy_go/public/mysql@v1.6.0/README.md b/proxy_go/public/mysql@v1.6.0/README.md deleted file mode 100644 index 0b13154..0000000 --- a/proxy_go/public/mysql@v1.6.0/README.md +++ /dev/null @@ -1,520 +0,0 @@ -# Go-MySQL-Driver - -A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) package - -![Go-MySQL-Driver logo](https://raw.github.com/wiki/go-sql-driver/mysql/gomysql_m.png "Golang Gopher holding the MySQL Dolphin") - ---------------------------------------- - * [Features](#features) - * [Requirements](#requirements) - * [Installation](#installation) - * [Usage](#usage) - * [DSN (Data Source Name)](#dsn-data-source-name) - * [Password](#password) - * [Protocol](#protocol) - * [Address](#address) - * [Parameters](#parameters) - * [Examples](#examples) - * [Connection pool and timeouts](#connection-pool-and-timeouts) - * [context.Context Support](#contextcontext-support) - * [ColumnType Support](#columntype-support) - * [LOAD DATA LOCAL INFILE support](#load-data-local-infile-support) - * [time.Time support](#timetime-support) - * [Unicode support](#unicode-support) - * [Testing / Development](#testing--development) - * [License](#license) - ---------------------------------------- - -## Features - * Lightweight and [fast](https://github.com/go-sql-driver/sql-benchmark "golang MySQL-Driver performance") - * Native Go implementation. No C-bindings, just pure Go - * Connections over TCP/IPv4, TCP/IPv6, Unix domain sockets or [custom protocols](https://godoc.org/github.com/go-sql-driver/mysql#DialFunc) - * Automatic handling of broken connections - * Automatic Connection Pooling *(by database/sql package)* - * Supports queries larger than 16MB - * Full [`sql.RawBytes`](https://golang.org/pkg/database/sql/#RawBytes) support. - * Intelligent `LONG DATA` handling in prepared statements - * Secure `LOAD DATA LOCAL INFILE` support with file allowlisting and `io.Reader` support - * Optional `time.Time` parsing - * Optional placeholder interpolation - -## Requirements - * Go 1.10 or higher. We aim to support the 3 latest versions of Go. - * MySQL (4.1+), MariaDB, Percona Server, Google CloudSQL or Sphinx (2.2.3+) - ---------------------------------------- - -## Installation -Simple install the package to your [$GOPATH](https://github.com/golang/go/wiki/GOPATH "GOPATH") with the [go tool](https://golang.org/cmd/go/ "go command") from shell: -```bash -$ go get -u github.com/go-sql-driver/mysql -``` -Make sure [Git is installed](https://git-scm.com/downloads) on your machine and in your system's `PATH`. - -## Usage -_Go MySQL Driver_ is an implementation of Go's `database/sql/driver` interface. You only need to import the driver and can use the full [`database/sql`](https://golang.org/pkg/database/sql/) API then. - -Use `mysql` as `driverName` and a valid [DSN](#dsn-data-source-name) as `dataSourceName`: - -```go -import ( - "database/sql" - "time" - - _ "github.com/go-sql-driver/mysql" -) - -// ... - -db, err := sql.Open("mysql", "user:password@/dbname") -if err != nil { - panic(err) -} -// See "Important settings" section. -db.SetConnMaxLifetime(time.Minute * 3) -db.SetMaxOpenConns(10) -db.SetMaxIdleConns(10) -``` - -[Examples are available in our Wiki](https://github.com/go-sql-driver/mysql/wiki/Examples "Go-MySQL-Driver Examples"). - -### Important settings - -`db.SetConnMaxLifetime()` is required to ensure connections are closed by the driver safely before connection is closed by MySQL server, OS, or other middlewares. Since some middlewares close idle connections by 5 minutes, we recommend timeout shorter than 5 minutes. This setting helps load balancing and changing system variables too. - -`db.SetMaxOpenConns()` is highly recommended to limit the number of connection used by the application. There is no recommended limit number because it depends on application and MySQL server. - -`db.SetMaxIdleConns()` is recommended to be set same to (or greater than) `db.SetMaxOpenConns()`. When it is smaller than `SetMaxOpenConns()`, connections can be opened and closed very frequently than you expect. Idle connections can be closed by the `db.SetConnMaxLifetime()`. If you want to close idle connections more rapidly, you can use `db.SetConnMaxIdleTime()` since Go 1.15. - - -### DSN (Data Source Name) - -The Data Source Name has a common format, like e.g. [PEAR DB](http://pear.php.net/manual/en/package.database.db.intro-dsn.php) uses it, but without type-prefix (optional parts marked by squared brackets): -``` -[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN] -``` - -A DSN in its fullest form: -``` -username:password@protocol(address)/dbname?param=value -``` - -Except for the databasename, all values are optional. So the minimal DSN is: -``` -/dbname -``` - -If you do not want to preselect a database, leave `dbname` empty: -``` -/ -``` -This has the same effect as an empty DSN string: -``` - -``` - -Alternatively, [Config.FormatDSN](https://godoc.org/github.com/go-sql-driver/mysql#Config.FormatDSN) can be used to create a DSN string by filling a struct. - -#### Password -Passwords can consist of any character. Escaping is **not** necessary. - -#### Protocol -See [net.Dial](https://golang.org/pkg/net/#Dial) for more information which networks are available. -In general you should use an Unix domain socket if available and TCP otherwise for best performance. - -#### Address -For TCP and UDP networks, addresses have the form `host[:port]`. -If `port` is omitted, the default port will be used. -If `host` is a literal IPv6 address, it must be enclosed in square brackets. -The functions [net.JoinHostPort](https://golang.org/pkg/net/#JoinHostPort) and [net.SplitHostPort](https://golang.org/pkg/net/#SplitHostPort) manipulate addresses in this form. - -For Unix domain sockets the address is the absolute path to the MySQL-Server-socket, e.g. `/var/run/mysqld/mysqld.sock` or `/tmp/mysql.sock`. - -#### Parameters -*Parameters are case-sensitive!* - -Notice that any of `true`, `TRUE`, `True` or `1` is accepted to stand for a true boolean value. Not surprisingly, false can be specified as any of: `false`, `FALSE`, `False` or `0`. - -##### `allowAllFiles` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -`allowAllFiles=true` disables the file allowlist for `LOAD DATA LOCAL INFILE` and allows *all* files. -[*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html) - -##### `allowCleartextPasswords` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -`allowCleartextPasswords=true` allows using the [cleartext client side plugin](https://dev.mysql.com/doc/en/cleartext-pluggable-authentication.html) if required by an account, such as one defined with the [PAM authentication plugin](http://dev.mysql.com/doc/en/pam-authentication-plugin.html). Sending passwords in clear text may be a security problem in some configurations. To avoid problems if there is any possibility that the password would be intercepted, clients should connect to MySQL Server using a method that protects the password. Possibilities include [TLS / SSL](#tls), IPsec, or a private network. - -##### `allowNativePasswords` - -``` -Type: bool -Valid Values: true, false -Default: true -``` -`allowNativePasswords=false` disallows the usage of MySQL native password method. - -##### `allowOldPasswords` - -``` -Type: bool -Valid Values: true, false -Default: false -``` -`allowOldPasswords=true` allows the usage of the insecure old password method. This should be avoided, but is necessary in some cases. See also [the old_passwords wiki page](https://github.com/go-sql-driver/mysql/wiki/old_passwords). - -##### `charset` - -``` -Type: string -Valid Values: -Default: none -``` - -Sets the charset used for client-server interaction (`"SET NAMES "`). If multiple charsets are set (separated by a comma), the following charset is used if setting the charset failes. This enables for example support for `utf8mb4` ([introduced in MySQL 5.5.3](http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html)) with fallback to `utf8` for older servers (`charset=utf8mb4,utf8`). - -Usage of the `charset` parameter is discouraged because it issues additional queries to the server. -Unless you need the fallback behavior, please use `collation` instead. - -##### `checkConnLiveness` - -``` -Type: bool -Valid Values: true, false -Default: true -``` - -On supported platforms connections retrieved from the connection pool are checked for liveness before using them. If the check fails, the respective connection is marked as bad and the query retried with another connection. -`checkConnLiveness=false` disables this liveness check of connections. - -##### `collation` - -``` -Type: string -Valid Values: -Default: utf8mb4_general_ci -``` - -Sets the collation used for client-server interaction on connection. In contrast to `charset`, `collation` does not issue additional queries. If the specified collation is unavailable on the target server, the connection will fail. - -A list of valid charsets for a server is retrievable with `SHOW COLLATION`. - -The default collation (`utf8mb4_general_ci`) is supported from MySQL 5.5. You should use an older collation (e.g. `utf8_general_ci`) for older MySQL. - -Collations for charset "ucs2", "utf16", "utf16le", and "utf32" can not be used ([ref](https://dev.mysql.com/doc/refman/5.7/en/charset-connection.html#charset-connection-impermissible-client-charset)). - - -##### `clientFoundRows` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -`clientFoundRows=true` causes an UPDATE to return the number of matching rows instead of the number of rows changed. - -##### `columnsWithAlias` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -When `columnsWithAlias` is true, calls to `sql.Rows.Columns()` will return the table alias and the column name separated by a dot. For example: - -``` -SELECT u.id FROM users as u -``` - -will return `u.id` instead of just `id` if `columnsWithAlias=true`. - -##### `interpolateParams` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -If `interpolateParams` is true, placeholders (`?`) in calls to `db.Query()` and `db.Exec()` are interpolated into a single query string with given parameters. This reduces the number of roundtrips, since the driver has to prepare a statement, execute it with given parameters and close the statement again with `interpolateParams=false`. - -*This can not be used together with the multibyte encodings BIG5, CP932, GB2312, GBK or SJIS. These are rejected as they may [introduce a SQL injection vulnerability](http://stackoverflow.com/a/12118602/3430118)!* - -##### `loc` - -``` -Type: string -Valid Values: -Default: UTC -``` - -Sets the location for time.Time values (when using `parseTime=true`). *"Local"* sets the system's location. See [time.LoadLocation](https://golang.org/pkg/time/#LoadLocation) for details. - -Note that this sets the location for time.Time values but does not change MySQL's [time_zone setting](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html). For that see the [time_zone system variable](#system-variables), which can also be set as a DSN parameter. - -Please keep in mind, that param values must be [url.QueryEscape](https://golang.org/pkg/net/url/#QueryEscape)'ed. Alternatively you can manually replace the `/` with `%2F`. For example `US/Pacific` would be `loc=US%2FPacific`. - -##### `maxAllowedPacket` -``` -Type: decimal number -Default: 4194304 -``` - -Max packet size allowed in bytes. The default value is 4 MiB and should be adjusted to match the server settings. `maxAllowedPacket=0` can be used to automatically fetch the `max_allowed_packet` variable from server *on every connection*. - -##### `multiStatements` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -Allow multiple statements in one query. While this allows batch queries, it also greatly increases the risk of SQL injections. Only the result of the first query is returned, all other results are silently discarded. - -When `multiStatements` is used, `?` parameters must only be used in the first statement. - -##### `parseTime` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - -`parseTime=true` changes the output type of `DATE` and `DATETIME` values to `time.Time` instead of `[]byte` / `string` -The date or datetime like `0000-00-00 00:00:00` is converted into zero value of `time.Time`. - - -##### `readTimeout` - -``` -Type: duration -Default: 0 -``` - -I/O read timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. - -##### `rejectReadOnly` - -``` -Type: bool -Valid Values: true, false -Default: false -``` - - -`rejectReadOnly=true` causes the driver to reject read-only connections. This -is for a possible race condition during an automatic failover, where the mysql -client gets connected to a read-only replica after the failover. - -Note that this should be a fairly rare case, as an automatic failover normally -happens when the primary is down, and the race condition shouldn't happen -unless it comes back up online as soon as the failover is kicked off. On the -other hand, when this happens, a MySQL application can get stuck on a -read-only connection until restarted. It is however fairly easy to reproduce, -for example, using a manual failover on AWS Aurora's MySQL-compatible cluster. - -If you are not relying on read-only transactions to reject writes that aren't -supposed to happen, setting this on some MySQL providers (such as AWS Aurora) -is safer for failovers. - -Note that ERROR 1290 can be returned for a `read-only` server and this option will -cause a retry for that error. However the same error number is used for some -other cases. You should ensure your application will never cause an ERROR 1290 -except for `read-only` mode when enabling this option. - - -##### `serverPubKey` - -``` -Type: string -Valid Values: -Default: none -``` - -Server public keys can be registered with [`mysql.RegisterServerPubKey`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterServerPubKey), which can then be used by the assigned name in the DSN. -Public keys are used to transmit encrypted data, e.g. for authentication. -If the server's public key is known, it should be set manually to avoid expensive and potentially insecure transmissions of the public key from the server to the client each time it is required. - - -##### `timeout` - -``` -Type: duration -Default: OS default -``` - -Timeout for establishing connections, aka dial timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. - - -##### `tls` - -``` -Type: bool / string -Valid Values: true, false, skip-verify, preferred, -Default: false -``` - -`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side) or use `preferred` to use TLS only when advertised by the server. This is similar to `skip-verify`, but additionally allows a fallback to a connection which is not encrypted. Neither `skip-verify` nor `preferred` add any reliable security. You can use a custom TLS config after registering it with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig). - - -##### `writeTimeout` - -``` -Type: duration -Default: 0 -``` - -I/O write timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. - - -##### System Variables - -Any other parameters are interpreted as system variables: - * `=`: `SET =` - * `=`: `SET =` - * `=%27%27`: `SET =''` - -Rules: -* The values for string variables must be quoted with `'`. -* The values must also be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed! - (which implies values of string variables must be wrapped with `%27`). - -Examples: - * `autocommit=1`: `SET autocommit=1` - * [`time_zone=%27Europe%2FParis%27`](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html): `SET time_zone='Europe/Paris'` - * [`transaction_isolation=%27REPEATABLE-READ%27`](https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_transaction_isolation): `SET transaction_isolation='REPEATABLE-READ'` - - -#### Examples -``` -user@unix(/path/to/socket)/dbname -``` - -``` -root:pw@unix(/tmp/mysql.sock)/myDatabase?loc=Local -``` - -``` -user:password@tcp(localhost:5555)/dbname?tls=skip-verify&autocommit=true -``` - -Treat warnings as errors by setting the system variable [`sql_mode`](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html): -``` -user:password@/dbname?sql_mode=TRADITIONAL -``` - -TCP via IPv6: -``` -user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname?timeout=90s&collation=utf8mb4_unicode_ci -``` - -TCP on a remote host, e.g. Amazon RDS: -``` -id:password@tcp(your-amazonaws-uri.com:3306)/dbname -``` - -Google Cloud SQL on App Engine: -``` -user:password@unix(/cloudsql/project-id:region-name:instance-name)/dbname -``` - -TCP using default port (3306) on localhost: -``` -user:password@tcp/dbname?charset=utf8mb4,utf8&sys_var=esc%40ped -``` - -Use the default protocol (tcp) and host (localhost:3306): -``` -user:password@/dbname -``` - -No Database preselected: -``` -user:password@/ -``` - - -### Connection pool and timeouts -The connection pool is managed by Go's database/sql package. For details on how to configure the size of the pool and how long connections stay in the pool see `*DB.SetMaxOpenConns`, `*DB.SetMaxIdleConns`, and `*DB.SetConnMaxLifetime` in the [database/sql documentation](https://golang.org/pkg/database/sql/). The read, write, and dial timeouts for each individual connection are configured with the DSN parameters [`readTimeout`](#readtimeout), [`writeTimeout`](#writetimeout), and [`timeout`](#timeout), respectively. - -## `ColumnType` Support -This driver supports the [`ColumnType` interface](https://golang.org/pkg/database/sql/#ColumnType) introduced in Go 1.8, with the exception of [`ColumnType.Length()`](https://golang.org/pkg/database/sql/#ColumnType.Length), which is currently not supported. - -## `context.Context` Support -Go 1.8 added `database/sql` support for `context.Context`. This driver supports query timeouts and cancellation via contexts. -See [context support in the database/sql package](https://golang.org/doc/go1.8#database_sql) for more details. - - -### `LOAD DATA LOCAL INFILE` support -For this feature you need direct access to the package. Therefore you must change the import path (no `_`): -```go -import "github.com/go-sql-driver/mysql" -``` - -Files must be explicitly allowed by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the allowlist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)). - -To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore. - -See the [godoc of Go-MySQL-Driver](https://godoc.org/github.com/go-sql-driver/mysql "golang mysql driver documentation") for details. - - -### `time.Time` support -The default internal output type of MySQL `DATE` and `DATETIME` values is `[]byte` which allows you to scan the value into a `[]byte`, `string` or `sql.RawBytes` variable in your program. - -However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` variables, which is the logical equivalent in Go to `DATE` and `DATETIME` in MySQL. You can do that by changing the internal output type from `[]byte` to `time.Time` with the DSN parameter `parseTime=true`. You can set the default [`time.Time` location](https://golang.org/pkg/time/#Location) with the `loc` DSN parameter. - -**Caution:** As of Go 1.1, this makes `time.Time` the only variable type you can scan `DATE` and `DATETIME` values into. This breaks for example [`sql.RawBytes` support](https://github.com/go-sql-driver/mysql/wiki/Examples#rawbytes). - - -### Unicode support -Since version 1.5 Go-MySQL-Driver automatically uses the collation ` utf8mb4_general_ci` by default. - -Other collations / charsets can be set using the [`collation`](#collation) DSN parameter. - -Version 1.0 of the driver recommended adding `&charset=utf8` (alias for `SET NAMES utf8`) to the DSN to enable proper UTF-8 support. This is not necessary anymore. The [`collation`](#collation) parameter should be preferred to set another collation / charset than the default. - -See http://dev.mysql.com/doc/refman/8.0/en/charset-unicode.html for more details on MySQL's Unicode support. - -## Testing / Development -To run the driver tests you may need to adjust the configuration. See the [Testing Wiki-Page](https://github.com/go-sql-driver/mysql/wiki/Testing "Testing") for details. - -Go-MySQL-Driver is not feature-complete yet. Your help is very appreciated. -If you want to contribute, you can work on an [open issue](https://github.com/go-sql-driver/mysql/issues?state=open) or review a [pull request](https://github.com/go-sql-driver/mysql/pulls). - -See the [Contribution Guidelines](https://github.com/go-sql-driver/mysql/blob/master/.github/CONTRIBUTING.md) for details. - ---------------------------------------- - -## License -Go-MySQL-Driver is licensed under the [Mozilla Public License Version 2.0](https://raw.github.com/go-sql-driver/mysql/master/LICENSE) - -Mozilla summarizes the license scope as follows: -> MPL: The copyleft applies to any files containing MPLed code. - - -That means: - * You can **use** the **unchanged** source code both in private and commercially. - * When distributing, you **must publish** the source code of any **changed files** licensed under the MPL 2.0 under a) the MPL 2.0 itself or b) a compatible license (e.g. GPL 3.0 or Apache License 2.0). - * You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged**. - -Please read the [MPL 2.0 FAQ](https://www.mozilla.org/en-US/MPL/2.0/FAQ/) if you have further questions regarding the license. - -You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE). - -![Go Gopher and MySQL Dolphin](https://raw.github.com/wiki/go-sql-driver/mysql/go-mysql-driver_m.jpg "Golang Gopher transporting the MySQL Dolphin in a wheelbarrow") diff --git a/proxy_go/public/mysql@v1.6.0/auth.go b/proxy_go/public/mysql@v1.6.0/auth.go deleted file mode 100644 index b2f19e8..0000000 --- a/proxy_go/public/mysql@v1.6.0/auth.go +++ /dev/null @@ -1,425 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2018 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/sha1" - "crypto/sha256" - "crypto/x509" - "encoding/pem" - "fmt" - "sync" -) - -// server pub keys registry -var ( - serverPubKeyLock sync.RWMutex - serverPubKeyRegistry map[string]*rsa.PublicKey -) - -// RegisterServerPubKey registers a server RSA public key which can be used to -// send data in a secure manner to the server without receiving the public key -// in a potentially insecure way from the server first. -// Registered keys can afterwards be used adding serverPubKey= to the DSN. -// -// Note: The provided rsa.PublicKey instance is exclusively owned by the driver -// after registering it and may not be modified. -// -// data, err := ioutil.ReadFile("mykey.pem") -// if err != nil { -// log.Fatal(err) -// } -// -// block, _ := pem.Decode(data) -// if block == nil || block.Type != "PUBLIC KEY" { -// log.Fatal("failed to decode PEM block containing public key") -// } -// -// pub, err := x509.ParsePKIXPublicKey(block.Bytes) -// if err != nil { -// log.Fatal(err) -// } -// -// if rsaPubKey, ok := pub.(*rsa.PublicKey); ok { -// mysql.RegisterServerPubKey("mykey", rsaPubKey) -// } else { -// log.Fatal("not a RSA public key") -// } -// -func RegisterServerPubKey(name string, pubKey *rsa.PublicKey) { - serverPubKeyLock.Lock() - if serverPubKeyRegistry == nil { - serverPubKeyRegistry = make(map[string]*rsa.PublicKey) - } - - serverPubKeyRegistry[name] = pubKey - serverPubKeyLock.Unlock() -} - -// DeregisterServerPubKey removes the public key registered with the given name. -func DeregisterServerPubKey(name string) { - serverPubKeyLock.Lock() - if serverPubKeyRegistry != nil { - delete(serverPubKeyRegistry, name) - } - serverPubKeyLock.Unlock() -} - -func getServerPubKey(name string) (pubKey *rsa.PublicKey) { - serverPubKeyLock.RLock() - if v, ok := serverPubKeyRegistry[name]; ok { - pubKey = v - } - serverPubKeyLock.RUnlock() - return -} - -// Hash password using pre 4.1 (old password) method -// https://github.com/atcurtis/mariadb/blob/master/mysys/my_rnd.c -type myRnd struct { - seed1, seed2 uint32 -} - -const myRndMaxVal = 0x3FFFFFFF - -// Pseudo random number generator -func newMyRnd(seed1, seed2 uint32) *myRnd { - return &myRnd{ - seed1: seed1 % myRndMaxVal, - seed2: seed2 % myRndMaxVal, - } -} - -// Tested to be equivalent to MariaDB's floating point variant -// http://play.golang.org/p/QHvhd4qved -// http://play.golang.org/p/RG0q4ElWDx -func (r *myRnd) NextByte() byte { - r.seed1 = (r.seed1*3 + r.seed2) % myRndMaxVal - r.seed2 = (r.seed1 + r.seed2 + 33) % myRndMaxVal - - return byte(uint64(r.seed1) * 31 / myRndMaxVal) -} - -// Generate binary hash from byte string using insecure pre 4.1 method -func pwHash(password []byte) (result [2]uint32) { - var add uint32 = 7 - var tmp uint32 - - result[0] = 1345345333 - result[1] = 0x12345671 - - for _, c := range password { - // skip spaces and tabs in password - if c == ' ' || c == '\t' { - continue - } - - tmp = uint32(c) - result[0] ^= (((result[0] & 63) + add) * tmp) + (result[0] << 8) - result[1] += (result[1] << 8) ^ result[0] - add += tmp - } - - // Remove sign bit (1<<31)-1) - result[0] &= 0x7FFFFFFF - result[1] &= 0x7FFFFFFF - - return -} - -// Hash password using insecure pre 4.1 method -func scrambleOldPassword(scramble []byte, password string) []byte { - scramble = scramble[:8] - - hashPw := pwHash([]byte(password)) - hashSc := pwHash(scramble) - - r := newMyRnd(hashPw[0]^hashSc[0], hashPw[1]^hashSc[1]) - - var out [8]byte - for i := range out { - out[i] = r.NextByte() + 64 - } - - mask := r.NextByte() - for i := range out { - out[i] ^= mask - } - - return out[:] -} - -// Hash password using 4.1+ method (SHA1) -func scramblePassword(scramble []byte, password string) []byte { - if len(password) == 0 { - return nil - } - - // stage1Hash = SHA1(password) - crypt := sha1.New() - crypt.Write([]byte(password)) - stage1 := crypt.Sum(nil) - - // scrambleHash = SHA1(scramble + SHA1(stage1Hash)) - // inner Hash - crypt.Reset() - crypt.Write(stage1) - hash := crypt.Sum(nil) - - // outer Hash - crypt.Reset() - crypt.Write(scramble) - crypt.Write(hash) - scramble = crypt.Sum(nil) - - // token = scrambleHash XOR stage1Hash - for i := range scramble { - scramble[i] ^= stage1[i] - } - return scramble -} - -// Hash password using MySQL 8+ method (SHA256) -func scrambleSHA256Password(scramble []byte, password string) []byte { - if len(password) == 0 { - return nil - } - - // XOR(SHA256(password), SHA256(SHA256(SHA256(password)), scramble)) - - crypt := sha256.New() - crypt.Write([]byte(password)) - message1 := crypt.Sum(nil) - - crypt.Reset() - crypt.Write(message1) - message1Hash := crypt.Sum(nil) - - crypt.Reset() - crypt.Write(message1Hash) - crypt.Write(scramble) - message2 := crypt.Sum(nil) - - for i := range message1 { - message1[i] ^= message2[i] - } - - return message1 -} - -func encryptPassword(password string, seed []byte, pub *rsa.PublicKey) ([]byte, error) { - plain := make([]byte, len(password)+1) - copy(plain, password) - for i := range plain { - j := i % len(seed) - plain[i] ^= seed[j] - } - sha1 := sha1.New() - return rsa.EncryptOAEP(sha1, rand.Reader, pub, plain, nil) -} - -func (mc *mysqlConn) sendEncryptedPassword(seed []byte, pub *rsa.PublicKey) error { - enc, err := encryptPassword(mc.cfg.Passwd, seed, pub) - if err != nil { - return err - } - return mc.writeAuthSwitchPacket(enc) -} - -func (mc *mysqlConn) auth(authData []byte, plugin string) ([]byte, error) { - switch plugin { - case "caching_sha2_password": - authResp := scrambleSHA256Password(authData, mc.cfg.Passwd) - return authResp, nil - - case "mysql_old_password": - if !mc.cfg.AllowOldPasswords { - return nil, ErrOldPassword - } - if len(mc.cfg.Passwd) == 0 { - return nil, nil - } - // Note: there are edge cases where this should work but doesn't; - // this is currently "wontfix": - // https://github.com/go-sql-driver/mysql/issues/184 - authResp := append(scrambleOldPassword(authData[:8], mc.cfg.Passwd), 0) - return authResp, nil - - case "mysql_clear_password": - if !mc.cfg.AllowCleartextPasswords { - return nil, ErrCleartextPassword - } - // http://dev.mysql.com/doc/refman/5.7/en/cleartext-authentication-plugin.html - // http://dev.mysql.com/doc/refman/5.7/en/pam-authentication-plugin.html - return append([]byte(mc.cfg.Passwd), 0), nil - - case "mysql_native_password": - if !mc.cfg.AllowNativePasswords { - return nil, ErrNativePassword - } - // https://dev.mysql.com/doc/internals/en/secure-password-authentication.html - // Native password authentication only need and will need 20-byte challenge. - authResp := scramblePassword(authData[:20], mc.cfg.Passwd) - return authResp, nil - - case "sha256_password": - if len(mc.cfg.Passwd) == 0 { - return []byte{0}, nil - } - if mc.cfg.tls != nil || mc.cfg.Net == "unix" { - // write cleartext auth packet - return append([]byte(mc.cfg.Passwd), 0), nil - } - - pubKey := mc.cfg.pubKey - if pubKey == nil { - // request public key from server - return []byte{1}, nil - } - - // encrypted password - enc, err := encryptPassword(mc.cfg.Passwd, authData, pubKey) - return enc, err - - default: - errLog.Print("unknown auth plugin:", plugin) - return nil, ErrUnknownPlugin - } -} - -func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error { - // Read Result Packet - authData, newPlugin, err := mc.readAuthResult() - if err != nil { - return err - } - - // handle auth plugin switch, if requested - if newPlugin != "" { - // If CLIENT_PLUGIN_AUTH capability is not supported, no new cipher is - // sent and we have to keep using the cipher sent in the init packet. - if authData == nil { - authData = oldAuthData - } else { - // copy data from read buffer to owned slice - copy(oldAuthData, authData) - } - - plugin = newPlugin - - authResp, err := mc.auth(authData, plugin) - if err != nil { - return err - } - if err = mc.writeAuthSwitchPacket(authResp); err != nil { - return err - } - - // Read Result Packet - authData, newPlugin, err = mc.readAuthResult() - if err != nil { - return err - } - - // Do not allow to change the auth plugin more than once - if newPlugin != "" { - return ErrMalformPkt - } - } - - switch plugin { - - // https://insidemysql.com/preparing-your-community-connector-for-mysql-8-part-2-sha256/ - case "caching_sha2_password": - switch len(authData) { - case 0: - return nil // auth successful - case 1: - switch authData[0] { - case cachingSha2PasswordFastAuthSuccess: - if err = mc.readResultOK(); err == nil { - return nil // auth successful - } - - case cachingSha2PasswordPerformFullAuthentication: - if mc.cfg.tls != nil || mc.cfg.Net == "unix" { - // write cleartext auth packet - err = mc.writeAuthSwitchPacket(append([]byte(mc.cfg.Passwd), 0)) - if err != nil { - return err - } - } else { - pubKey := mc.cfg.pubKey - if pubKey == nil { - // request public key from server - data, err := mc.buf.takeSmallBuffer(4 + 1) - if err != nil { - return err - } - data[4] = cachingSha2PasswordRequestPublicKey - mc.writePacket(data) - - // parse public key - if data, err = mc.readPacket(); err != nil { - return err - } - - block, rest := pem.Decode(data[1:]) - if block == nil { - return fmt.Errorf("No Pem data found, data: %s", rest) - } - pkix, err := x509.ParsePKIXPublicKey(block.Bytes) - if err != nil { - return err - } - pubKey = pkix.(*rsa.PublicKey) - } - - // send encrypted password - err = mc.sendEncryptedPassword(oldAuthData, pubKey) - if err != nil { - return err - } - } - return mc.readResultOK() - - default: - return ErrMalformPkt - } - default: - return ErrMalformPkt - } - - case "sha256_password": - switch len(authData) { - case 0: - return nil // auth successful - default: - block, _ := pem.Decode(authData) - pub, err := x509.ParsePKIXPublicKey(block.Bytes) - if err != nil { - return err - } - - // send encrypted password - err = mc.sendEncryptedPassword(oldAuthData, pub.(*rsa.PublicKey)) - if err != nil { - return err - } - return mc.readResultOK() - } - - default: - return nil // auth successful - } - - return err -} diff --git a/proxy_go/public/mysql@v1.6.0/auth_test.go b/proxy_go/public/mysql@v1.6.0/auth_test.go deleted file mode 100644 index 3bce7fe..0000000 --- a/proxy_go/public/mysql@v1.6.0/auth_test.go +++ /dev/null @@ -1,1330 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2018 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "bytes" - "crypto/rsa" - "crypto/tls" - "crypto/x509" - "encoding/pem" - "fmt" - "testing" -) - -var testPubKey = []byte("-----BEGIN PUBLIC KEY-----\n" + - "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAol0Z8G8U+25Btxk/g/fm\n" + - "UAW/wEKjQCTjkibDE4B+qkuWeiumg6miIRhtilU6m9BFmLQSy1ltYQuu4k17A4tQ\n" + - "rIPpOQYZges/qsDFkZh3wyK5jL5WEFVdOasf6wsfszExnPmcZS4axxoYJfiuilrN\n" + - "hnwinBAqfi3S0sw5MpSI4Zl1AbOrHG4zDI62Gti2PKiMGyYDZTS9xPrBLbN95Kby\n" + - "FFclQLEzA9RJcS1nHFsWtRgHjGPhhjCQxEm9NQ1nePFhCfBfApyfH1VM2VCOQum6\n" + - "Ci9bMuHWjTjckC84mzF99kOxOWVU7mwS6gnJqBzpuz8t3zq8/iQ2y7QrmZV+jTJP\n" + - "WQIDAQAB\n" + - "-----END PUBLIC KEY-----\n") - -var testPubKeyRSA *rsa.PublicKey - -func init() { - block, _ := pem.Decode(testPubKey) - pub, err := x509.ParsePKIXPublicKey(block.Bytes) - if err != nil { - panic(err) - } - testPubKeyRSA = pub.(*rsa.PublicKey) -} - -func TestScrambleOldPass(t *testing.T) { - scramble := []byte{9, 8, 7, 6, 5, 4, 3, 2} - vectors := []struct { - pass string - out string - }{ - {" pass", "47575c5a435b4251"}, - {"pass ", "47575c5a435b4251"}, - {"123\t456", "575c47505b5b5559"}, - {"C0mpl!ca ted#PASS123", "5d5d554849584a45"}, - } - for _, tuple := range vectors { - ours := scrambleOldPassword(scramble, tuple.pass) - if tuple.out != fmt.Sprintf("%x", ours) { - t.Errorf("Failed old password %q", tuple.pass) - } - } -} - -func TestScrambleSHA256Pass(t *testing.T) { - scramble := []byte{10, 47, 74, 111, 75, 73, 34, 48, 88, 76, 114, 74, 37, 13, 3, 80, 82, 2, 23, 21} - vectors := []struct { - pass string - out string - }{ - {"secret", "f490e76f66d9d86665ce54d98c78d0acfe2fb0b08b423da807144873d30b312c"}, - {"secret2", "abc3934a012cf342e876071c8ee202de51785b430258a7a0138bc79c4d800bc6"}, - } - for _, tuple := range vectors { - ours := scrambleSHA256Password(scramble, tuple.pass) - if tuple.out != fmt.Sprintf("%x", ours) { - t.Errorf("Failed SHA256 password %q", tuple.pass) - } - } -} - -func TestAuthFastCachingSHA256PasswordCached(t *testing.T) { - conn, mc := newRWMockConn(1) - mc.cfg.User = "root" - mc.cfg.Passwd = "secret" - - authData := []byte{90, 105, 74, 126, 30, 48, 37, 56, 3, 23, 115, 127, 69, - 22, 41, 84, 32, 123, 43, 118} - plugin := "caching_sha2_password" - - // Send Client Authentication Packet - authResp, err := mc.auth(authData, plugin) - if err != nil { - t.Fatal(err) - } - err = mc.writeHandshakeResponsePacket(authResp, plugin) - if err != nil { - t.Fatal(err) - } - - // check written auth response - authRespStart := 4 + 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 - authRespEnd := authRespStart + 1 + len(authResp) - writtenAuthRespLen := conn.written[authRespStart] - writtenAuthResp := conn.written[authRespStart+1 : authRespEnd] - expectedAuthResp := []byte{102, 32, 5, 35, 143, 161, 140, 241, 171, 232, 56, - 139, 43, 14, 107, 196, 249, 170, 147, 60, 220, 204, 120, 178, 214, 15, - 184, 150, 26, 61, 57, 235} - if writtenAuthRespLen != 32 || !bytes.Equal(writtenAuthResp, expectedAuthResp) { - t.Fatalf("unexpected written auth response (%d bytes): %v", writtenAuthRespLen, writtenAuthResp) - } - conn.written = nil - - // auth response - conn.data = []byte{ - 2, 0, 0, 2, 1, 3, // Fast Auth Success - 7, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, // OK - } - conn.maxReads = 1 - - // Handle response to auth packet - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } -} - -func TestAuthFastCachingSHA256PasswordEmpty(t *testing.T) { - conn, mc := newRWMockConn(1) - mc.cfg.User = "root" - mc.cfg.Passwd = "" - - authData := []byte{90, 105, 74, 126, 30, 48, 37, 56, 3, 23, 115, 127, 69, - 22, 41, 84, 32, 123, 43, 118} - plugin := "caching_sha2_password" - - // Send Client Authentication Packet - authResp, err := mc.auth(authData, plugin) - if err != nil { - t.Fatal(err) - } - err = mc.writeHandshakeResponsePacket(authResp, plugin) - if err != nil { - t.Fatal(err) - } - - // check written auth response - authRespStart := 4 + 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 - authRespEnd := authRespStart + 1 + len(authResp) - writtenAuthRespLen := conn.written[authRespStart] - writtenAuthResp := conn.written[authRespStart+1 : authRespEnd] - if writtenAuthRespLen != 0 { - t.Fatalf("unexpected written auth response (%d bytes): %v", - writtenAuthRespLen, writtenAuthResp) - } - conn.written = nil - - // auth response - conn.data = []byte{ - 7, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, // OK - } - conn.maxReads = 1 - - // Handle response to auth packet - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } -} - -func TestAuthFastCachingSHA256PasswordFullRSA(t *testing.T) { - conn, mc := newRWMockConn(1) - mc.cfg.User = "root" - mc.cfg.Passwd = "secret" - - authData := []byte{6, 81, 96, 114, 14, 42, 50, 30, 76, 47, 1, 95, 126, 81, - 62, 94, 83, 80, 52, 85} - plugin := "caching_sha2_password" - - // Send Client Authentication Packet - authResp, err := mc.auth(authData, plugin) - if err != nil { - t.Fatal(err) - } - err = mc.writeHandshakeResponsePacket(authResp, plugin) - if err != nil { - t.Fatal(err) - } - - // check written auth response - authRespStart := 4 + 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 - authRespEnd := authRespStart + 1 + len(authResp) - writtenAuthRespLen := conn.written[authRespStart] - writtenAuthResp := conn.written[authRespStart+1 : authRespEnd] - expectedAuthResp := []byte{171, 201, 138, 146, 89, 159, 11, 170, 0, 67, 165, - 49, 175, 94, 218, 68, 177, 109, 110, 86, 34, 33, 44, 190, 67, 240, 70, - 110, 40, 139, 124, 41} - if writtenAuthRespLen != 32 || !bytes.Equal(writtenAuthResp, expectedAuthResp) { - t.Fatalf("unexpected written auth response (%d bytes): %v", writtenAuthRespLen, writtenAuthResp) - } - conn.written = nil - - // auth response - conn.data = []byte{ - 2, 0, 0, 2, 1, 4, // Perform Full Authentication - } - conn.queuedReplies = [][]byte{ - // pub key response - append([]byte{byte(1 + len(testPubKey)), 1, 0, 4, 1}, testPubKey...), - - // OK - {7, 0, 0, 6, 0, 0, 0, 2, 0, 0, 0}, - } - conn.maxReads = 3 - - // Handle response to auth packet - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - if !bytes.HasPrefix(conn.written, []byte{1, 0, 0, 3, 2, 0, 1, 0, 5}) { - t.Errorf("unexpected written data: %v", conn.written) - } -} - -func TestAuthFastCachingSHA256PasswordFullRSAWithKey(t *testing.T) { - conn, mc := newRWMockConn(1) - mc.cfg.User = "root" - mc.cfg.Passwd = "secret" - mc.cfg.pubKey = testPubKeyRSA - - authData := []byte{6, 81, 96, 114, 14, 42, 50, 30, 76, 47, 1, 95, 126, 81, - 62, 94, 83, 80, 52, 85} - plugin := "caching_sha2_password" - - // Send Client Authentication Packet - authResp, err := mc.auth(authData, plugin) - if err != nil { - t.Fatal(err) - } - err = mc.writeHandshakeResponsePacket(authResp, plugin) - if err != nil { - t.Fatal(err) - } - - // check written auth response - authRespStart := 4 + 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 - authRespEnd := authRespStart + 1 + len(authResp) - writtenAuthRespLen := conn.written[authRespStart] - writtenAuthResp := conn.written[authRespStart+1 : authRespEnd] - expectedAuthResp := []byte{171, 201, 138, 146, 89, 159, 11, 170, 0, 67, 165, - 49, 175, 94, 218, 68, 177, 109, 110, 86, 34, 33, 44, 190, 67, 240, 70, - 110, 40, 139, 124, 41} - if writtenAuthRespLen != 32 || !bytes.Equal(writtenAuthResp, expectedAuthResp) { - t.Fatalf("unexpected written auth response (%d bytes): %v", writtenAuthRespLen, writtenAuthResp) - } - conn.written = nil - - // auth response - conn.data = []byte{ - 2, 0, 0, 2, 1, 4, // Perform Full Authentication - } - conn.queuedReplies = [][]byte{ - // OK - {7, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0}, - } - conn.maxReads = 2 - - // Handle response to auth packet - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - if !bytes.HasPrefix(conn.written, []byte{0, 1, 0, 3}) { - t.Errorf("unexpected written data: %v", conn.written) - } -} - -func TestAuthFastCachingSHA256PasswordFullSecure(t *testing.T) { - conn, mc := newRWMockConn(1) - mc.cfg.User = "root" - mc.cfg.Passwd = "secret" - - authData := []byte{6, 81, 96, 114, 14, 42, 50, 30, 76, 47, 1, 95, 126, 81, - 62, 94, 83, 80, 52, 85} - plugin := "caching_sha2_password" - - // Send Client Authentication Packet - authResp, err := mc.auth(authData, plugin) - if err != nil { - t.Fatal(err) - } - err = mc.writeHandshakeResponsePacket(authResp, plugin) - if err != nil { - t.Fatal(err) - } - - // Hack to make the caching_sha2_password plugin believe that the connection - // is secure - mc.cfg.tls = &tls.Config{InsecureSkipVerify: true} - - // check written auth response - authRespStart := 4 + 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 - authRespEnd := authRespStart + 1 + len(authResp) - writtenAuthRespLen := conn.written[authRespStart] - writtenAuthResp := conn.written[authRespStart+1 : authRespEnd] - expectedAuthResp := []byte{171, 201, 138, 146, 89, 159, 11, 170, 0, 67, 165, - 49, 175, 94, 218, 68, 177, 109, 110, 86, 34, 33, 44, 190, 67, 240, 70, - 110, 40, 139, 124, 41} - if writtenAuthRespLen != 32 || !bytes.Equal(writtenAuthResp, expectedAuthResp) { - t.Fatalf("unexpected written auth response (%d bytes): %v", writtenAuthRespLen, writtenAuthResp) - } - conn.written = nil - - // auth response - conn.data = []byte{ - 2, 0, 0, 2, 1, 4, // Perform Full Authentication - } - conn.queuedReplies = [][]byte{ - // OK - {7, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0}, - } - conn.maxReads = 3 - - // Handle response to auth packet - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - if !bytes.Equal(conn.written, []byte{7, 0, 0, 3, 115, 101, 99, 114, 101, 116, 0}) { - t.Errorf("unexpected written data: %v", conn.written) - } -} - -func TestAuthFastCleartextPasswordNotAllowed(t *testing.T) { - _, mc := newRWMockConn(1) - mc.cfg.User = "root" - mc.cfg.Passwd = "secret" - - authData := []byte{70, 114, 92, 94, 1, 38, 11, 116, 63, 114, 23, 101, 126, - 103, 26, 95, 81, 17, 24, 21} - plugin := "mysql_clear_password" - - // Send Client Authentication Packet - _, err := mc.auth(authData, plugin) - if err != ErrCleartextPassword { - t.Errorf("expected ErrCleartextPassword, got %v", err) - } -} - -func TestAuthFastCleartextPassword(t *testing.T) { - conn, mc := newRWMockConn(1) - mc.cfg.User = "root" - mc.cfg.Passwd = "secret" - mc.cfg.AllowCleartextPasswords = true - - authData := []byte{70, 114, 92, 94, 1, 38, 11, 116, 63, 114, 23, 101, 126, - 103, 26, 95, 81, 17, 24, 21} - plugin := "mysql_clear_password" - - // Send Client Authentication Packet - authResp, err := mc.auth(authData, plugin) - if err != nil { - t.Fatal(err) - } - err = mc.writeHandshakeResponsePacket(authResp, plugin) - if err != nil { - t.Fatal(err) - } - - // check written auth response - authRespStart := 4 + 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 - authRespEnd := authRespStart + 1 + len(authResp) - writtenAuthRespLen := conn.written[authRespStart] - writtenAuthResp := conn.written[authRespStart+1 : authRespEnd] - expectedAuthResp := []byte{115, 101, 99, 114, 101, 116, 0} - if writtenAuthRespLen != 7 || !bytes.Equal(writtenAuthResp, expectedAuthResp) { - t.Fatalf("unexpected written auth response (%d bytes): %v", writtenAuthRespLen, writtenAuthResp) - } - conn.written = nil - - // auth response - conn.data = []byte{ - 7, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, // OK - } - conn.maxReads = 1 - - // Handle response to auth packet - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } -} - -func TestAuthFastCleartextPasswordEmpty(t *testing.T) { - conn, mc := newRWMockConn(1) - mc.cfg.User = "root" - mc.cfg.Passwd = "" - mc.cfg.AllowCleartextPasswords = true - - authData := []byte{70, 114, 92, 94, 1, 38, 11, 116, 63, 114, 23, 101, 126, - 103, 26, 95, 81, 17, 24, 21} - plugin := "mysql_clear_password" - - // Send Client Authentication Packet - authResp, err := mc.auth(authData, plugin) - if err != nil { - t.Fatal(err) - } - err = mc.writeHandshakeResponsePacket(authResp, plugin) - if err != nil { - t.Fatal(err) - } - - // check written auth response - authRespStart := 4 + 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 - authRespEnd := authRespStart + 1 + len(authResp) - writtenAuthRespLen := conn.written[authRespStart] - writtenAuthResp := conn.written[authRespStart+1 : authRespEnd] - expectedAuthResp := []byte{0} - if writtenAuthRespLen != 1 || !bytes.Equal(writtenAuthResp, expectedAuthResp) { - t.Fatalf("unexpected written auth response (%d bytes): %v", writtenAuthRespLen, writtenAuthResp) - } - conn.written = nil - - // auth response - conn.data = []byte{ - 7, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, // OK - } - conn.maxReads = 1 - - // Handle response to auth packet - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } -} - -func TestAuthFastNativePasswordNotAllowed(t *testing.T) { - _, mc := newRWMockConn(1) - mc.cfg.User = "root" - mc.cfg.Passwd = "secret" - mc.cfg.AllowNativePasswords = false - - authData := []byte{70, 114, 92, 94, 1, 38, 11, 116, 63, 114, 23, 101, 126, - 103, 26, 95, 81, 17, 24, 21} - plugin := "mysql_native_password" - - // Send Client Authentication Packet - _, err := mc.auth(authData, plugin) - if err != ErrNativePassword { - t.Errorf("expected ErrNativePassword, got %v", err) - } -} - -func TestAuthFastNativePassword(t *testing.T) { - conn, mc := newRWMockConn(1) - mc.cfg.User = "root" - mc.cfg.Passwd = "secret" - - authData := []byte{70, 114, 92, 94, 1, 38, 11, 116, 63, 114, 23, 101, 126, - 103, 26, 95, 81, 17, 24, 21} - plugin := "mysql_native_password" - - // Send Client Authentication Packet - authResp, err := mc.auth(authData, plugin) - if err != nil { - t.Fatal(err) - } - err = mc.writeHandshakeResponsePacket(authResp, plugin) - if err != nil { - t.Fatal(err) - } - - // check written auth response - authRespStart := 4 + 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 - authRespEnd := authRespStart + 1 + len(authResp) - writtenAuthRespLen := conn.written[authRespStart] - writtenAuthResp := conn.written[authRespStart+1 : authRespEnd] - expectedAuthResp := []byte{53, 177, 140, 159, 251, 189, 127, 53, 109, 252, - 172, 50, 211, 192, 240, 164, 26, 48, 207, 45} - if writtenAuthRespLen != 20 || !bytes.Equal(writtenAuthResp, expectedAuthResp) { - t.Fatalf("unexpected written auth response (%d bytes): %v", writtenAuthRespLen, writtenAuthResp) - } - conn.written = nil - - // auth response - conn.data = []byte{ - 7, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, // OK - } - conn.maxReads = 1 - - // Handle response to auth packet - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } -} - -func TestAuthFastNativePasswordEmpty(t *testing.T) { - conn, mc := newRWMockConn(1) - mc.cfg.User = "root" - mc.cfg.Passwd = "" - - authData := []byte{70, 114, 92, 94, 1, 38, 11, 116, 63, 114, 23, 101, 126, - 103, 26, 95, 81, 17, 24, 21} - plugin := "mysql_native_password" - - // Send Client Authentication Packet - authResp, err := mc.auth(authData, plugin) - if err != nil { - t.Fatal(err) - } - err = mc.writeHandshakeResponsePacket(authResp, plugin) - if err != nil { - t.Fatal(err) - } - - // check written auth response - authRespStart := 4 + 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 - authRespEnd := authRespStart + 1 + len(authResp) - writtenAuthRespLen := conn.written[authRespStart] - writtenAuthResp := conn.written[authRespStart+1 : authRespEnd] - if writtenAuthRespLen != 0 { - t.Fatalf("unexpected written auth response (%d bytes): %v", - writtenAuthRespLen, writtenAuthResp) - } - conn.written = nil - - // auth response - conn.data = []byte{ - 7, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, // OK - } - conn.maxReads = 1 - - // Handle response to auth packet - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } -} - -func TestAuthFastSHA256PasswordEmpty(t *testing.T) { - conn, mc := newRWMockConn(1) - mc.cfg.User = "root" - mc.cfg.Passwd = "" - - authData := []byte{6, 81, 96, 114, 14, 42, 50, 30, 76, 47, 1, 95, 126, 81, - 62, 94, 83, 80, 52, 85} - plugin := "sha256_password" - - // Send Client Authentication Packet - authResp, err := mc.auth(authData, plugin) - if err != nil { - t.Fatal(err) - } - err = mc.writeHandshakeResponsePacket(authResp, plugin) - if err != nil { - t.Fatal(err) - } - - // check written auth response - authRespStart := 4 + 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 - authRespEnd := authRespStart + 1 + len(authResp) - writtenAuthRespLen := conn.written[authRespStart] - writtenAuthResp := conn.written[authRespStart+1 : authRespEnd] - expectedAuthResp := []byte{0} - if writtenAuthRespLen != 1 || !bytes.Equal(writtenAuthResp, expectedAuthResp) { - t.Fatalf("unexpected written auth response (%d bytes): %v", writtenAuthRespLen, writtenAuthResp) - } - conn.written = nil - - // auth response (pub key response) - conn.data = append([]byte{byte(1 + len(testPubKey)), 1, 0, 2, 1}, testPubKey...) - conn.queuedReplies = [][]byte{ - // OK - {7, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0}, - } - conn.maxReads = 2 - - // Handle response to auth packet - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - if !bytes.HasPrefix(conn.written, []byte{0, 1, 0, 3}) { - t.Errorf("unexpected written data: %v", conn.written) - } -} - -func TestAuthFastSHA256PasswordRSA(t *testing.T) { - conn, mc := newRWMockConn(1) - mc.cfg.User = "root" - mc.cfg.Passwd = "secret" - - authData := []byte{6, 81, 96, 114, 14, 42, 50, 30, 76, 47, 1, 95, 126, 81, - 62, 94, 83, 80, 52, 85} - plugin := "sha256_password" - - // Send Client Authentication Packet - authResp, err := mc.auth(authData, plugin) - if err != nil { - t.Fatal(err) - } - err = mc.writeHandshakeResponsePacket(authResp, plugin) - if err != nil { - t.Fatal(err) - } - - // check written auth response - authRespStart := 4 + 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 - authRespEnd := authRespStart + 1 + len(authResp) - writtenAuthRespLen := conn.written[authRespStart] - writtenAuthResp := conn.written[authRespStart+1 : authRespEnd] - expectedAuthResp := []byte{1} - if writtenAuthRespLen != 1 || !bytes.Equal(writtenAuthResp, expectedAuthResp) { - t.Fatalf("unexpected written auth response (%d bytes): %v", writtenAuthRespLen, writtenAuthResp) - } - conn.written = nil - - // auth response (pub key response) - conn.data = append([]byte{byte(1 + len(testPubKey)), 1, 0, 2, 1}, testPubKey...) - conn.queuedReplies = [][]byte{ - // OK - {7, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0}, - } - conn.maxReads = 2 - - // Handle response to auth packet - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - if !bytes.HasPrefix(conn.written, []byte{0, 1, 0, 3}) { - t.Errorf("unexpected written data: %v", conn.written) - } -} - -func TestAuthFastSHA256PasswordRSAWithKey(t *testing.T) { - conn, mc := newRWMockConn(1) - mc.cfg.User = "root" - mc.cfg.Passwd = "secret" - mc.cfg.pubKey = testPubKeyRSA - - authData := []byte{6, 81, 96, 114, 14, 42, 50, 30, 76, 47, 1, 95, 126, 81, - 62, 94, 83, 80, 52, 85} - plugin := "sha256_password" - - // Send Client Authentication Packet - authResp, err := mc.auth(authData, plugin) - if err != nil { - t.Fatal(err) - } - err = mc.writeHandshakeResponsePacket(authResp, plugin) - if err != nil { - t.Fatal(err) - } - - // auth response (OK) - conn.data = []byte{7, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0} - conn.maxReads = 1 - - // Handle response to auth packet - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } -} - -func TestAuthFastSHA256PasswordSecure(t *testing.T) { - conn, mc := newRWMockConn(1) - mc.cfg.User = "root" - mc.cfg.Passwd = "secret" - - // hack to make the caching_sha2_password plugin believe that the connection - // is secure - mc.cfg.tls = &tls.Config{InsecureSkipVerify: true} - - authData := []byte{6, 81, 96, 114, 14, 42, 50, 30, 76, 47, 1, 95, 126, 81, - 62, 94, 83, 80, 52, 85} - plugin := "sha256_password" - - // send Client Authentication Packet - authResp, err := mc.auth(authData, plugin) - if err != nil { - t.Fatal(err) - } - - // unset TLS config to prevent the actual establishment of a TLS wrapper - mc.cfg.tls = nil - - err = mc.writeHandshakeResponsePacket(authResp, plugin) - if err != nil { - t.Fatal(err) - } - - // check written auth response - authRespStart := 4 + 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 - authRespEnd := authRespStart + 1 + len(authResp) - writtenAuthRespLen := conn.written[authRespStart] - writtenAuthResp := conn.written[authRespStart+1 : authRespEnd] - expectedAuthResp := []byte{115, 101, 99, 114, 101, 116, 0} - if writtenAuthRespLen != 7 || !bytes.Equal(writtenAuthResp, expectedAuthResp) { - t.Fatalf("unexpected written auth response (%d bytes): %v", writtenAuthRespLen, writtenAuthResp) - } - conn.written = nil - - // auth response (OK) - conn.data = []byte{7, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0} - conn.maxReads = 1 - - // Handle response to auth packet - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - if !bytes.Equal(conn.written, []byte{}) { - t.Errorf("unexpected written data: %v", conn.written) - } -} - -func TestAuthSwitchCachingSHA256PasswordCached(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.Passwd = "secret" - - // auth switch request - conn.data = []byte{44, 0, 0, 2, 254, 99, 97, 99, 104, 105, 110, 103, 95, - 115, 104, 97, 50, 95, 112, 97, 115, 115, 119, 111, 114, 100, 0, 101, - 11, 26, 18, 94, 97, 22, 72, 2, 46, 70, 106, 29, 55, 45, 94, 76, 90, 84, - 50, 0} - - // auth response - conn.queuedReplies = [][]byte{ - {7, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0}, // OK - } - conn.maxReads = 3 - - authData := []byte{123, 87, 15, 84, 20, 58, 37, 121, 91, 117, 51, 24, 19, - 47, 43, 9, 41, 112, 67, 110} - plugin := "mysql_native_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReply := []byte{ - // 1. Packet: Hash - 32, 0, 0, 3, 129, 93, 132, 95, 114, 48, 79, 215, 128, 62, 193, 118, 128, - 54, 75, 208, 159, 252, 227, 215, 129, 15, 242, 97, 19, 159, 31, 20, 58, - 153, 9, 130, - } - if !bytes.Equal(conn.written, expectedReply) { - t.Errorf("got unexpected data: %v", conn.written) - } -} - -func TestAuthSwitchCachingSHA256PasswordEmpty(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.Passwd = "" - - // auth switch request - conn.data = []byte{44, 0, 0, 2, 254, 99, 97, 99, 104, 105, 110, 103, 95, - 115, 104, 97, 50, 95, 112, 97, 115, 115, 119, 111, 114, 100, 0, 101, - 11, 26, 18, 94, 97, 22, 72, 2, 46, 70, 106, 29, 55, 45, 94, 76, 90, 84, - 50, 0} - - // auth response - conn.queuedReplies = [][]byte{{7, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0}} - conn.maxReads = 2 - - authData := []byte{123, 87, 15, 84, 20, 58, 37, 121, 91, 117, 51, 24, 19, - 47, 43, 9, 41, 112, 67, 110} - plugin := "mysql_native_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReply := []byte{0, 0, 0, 3} - if !bytes.Equal(conn.written, expectedReply) { - t.Errorf("got unexpected data: %v", conn.written) - } -} - -func TestAuthSwitchCachingSHA256PasswordFullRSA(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.Passwd = "secret" - - // auth switch request - conn.data = []byte{44, 0, 0, 2, 254, 99, 97, 99, 104, 105, 110, 103, 95, - 115, 104, 97, 50, 95, 112, 97, 115, 115, 119, 111, 114, 100, 0, 101, - 11, 26, 18, 94, 97, 22, 72, 2, 46, 70, 106, 29, 55, 45, 94, 76, 90, 84, - 50, 0} - - conn.queuedReplies = [][]byte{ - // Perform Full Authentication - {2, 0, 0, 4, 1, 4}, - - // Pub Key Response - append([]byte{byte(1 + len(testPubKey)), 1, 0, 6, 1}, testPubKey...), - - // OK - {7, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0}, - } - conn.maxReads = 4 - - authData := []byte{123, 87, 15, 84, 20, 58, 37, 121, 91, 117, 51, 24, 19, - 47, 43, 9, 41, 112, 67, 110} - plugin := "mysql_native_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReplyPrefix := []byte{ - // 1. Packet: Hash - 32, 0, 0, 3, 129, 93, 132, 95, 114, 48, 79, 215, 128, 62, 193, 118, 128, - 54, 75, 208, 159, 252, 227, 215, 129, 15, 242, 97, 19, 159, 31, 20, 58, - 153, 9, 130, - - // 2. Packet: Pub Key Request - 1, 0, 0, 5, 2, - - // 3. Packet: Encrypted Password - 0, 1, 0, 7, // [changing bytes] - } - if !bytes.HasPrefix(conn.written, expectedReplyPrefix) { - t.Errorf("got unexpected data: %v", conn.written) - } -} - -func TestAuthSwitchCachingSHA256PasswordFullRSAWithKey(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.Passwd = "secret" - mc.cfg.pubKey = testPubKeyRSA - - // auth switch request - conn.data = []byte{44, 0, 0, 2, 254, 99, 97, 99, 104, 105, 110, 103, 95, - 115, 104, 97, 50, 95, 112, 97, 115, 115, 119, 111, 114, 100, 0, 101, - 11, 26, 18, 94, 97, 22, 72, 2, 46, 70, 106, 29, 55, 45, 94, 76, 90, 84, - 50, 0} - - conn.queuedReplies = [][]byte{ - // Perform Full Authentication - {2, 0, 0, 4, 1, 4}, - - // OK - {7, 0, 0, 6, 0, 0, 0, 2, 0, 0, 0}, - } - conn.maxReads = 3 - - authData := []byte{123, 87, 15, 84, 20, 58, 37, 121, 91, 117, 51, 24, 19, - 47, 43, 9, 41, 112, 67, 110} - plugin := "mysql_native_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReplyPrefix := []byte{ - // 1. Packet: Hash - 32, 0, 0, 3, 129, 93, 132, 95, 114, 48, 79, 215, 128, 62, 193, 118, 128, - 54, 75, 208, 159, 252, 227, 215, 129, 15, 242, 97, 19, 159, 31, 20, 58, - 153, 9, 130, - - // 2. Packet: Encrypted Password - 0, 1, 0, 5, // [changing bytes] - } - if !bytes.HasPrefix(conn.written, expectedReplyPrefix) { - t.Errorf("got unexpected data: %v", conn.written) - } -} - -func TestAuthSwitchCachingSHA256PasswordFullSecure(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.Passwd = "secret" - - // Hack to make the caching_sha2_password plugin believe that the connection - // is secure - mc.cfg.tls = &tls.Config{InsecureSkipVerify: true} - - // auth switch request - conn.data = []byte{44, 0, 0, 2, 254, 99, 97, 99, 104, 105, 110, 103, 95, - 115, 104, 97, 50, 95, 112, 97, 115, 115, 119, 111, 114, 100, 0, 101, - 11, 26, 18, 94, 97, 22, 72, 2, 46, 70, 106, 29, 55, 45, 94, 76, 90, 84, - 50, 0} - - // auth response - conn.queuedReplies = [][]byte{ - {2, 0, 0, 4, 1, 4}, // Perform Full Authentication - {7, 0, 0, 6, 0, 0, 0, 2, 0, 0, 0}, // OK - } - conn.maxReads = 3 - - authData := []byte{123, 87, 15, 84, 20, 58, 37, 121, 91, 117, 51, 24, 19, - 47, 43, 9, 41, 112, 67, 110} - plugin := "mysql_native_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReply := []byte{ - // 1. Packet: Hash - 32, 0, 0, 3, 129, 93, 132, 95, 114, 48, 79, 215, 128, 62, 193, 118, 128, - 54, 75, 208, 159, 252, 227, 215, 129, 15, 242, 97, 19, 159, 31, 20, 58, - 153, 9, 130, - - // 2. Packet: Cleartext password - 7, 0, 0, 5, 115, 101, 99, 114, 101, 116, 0, - } - if !bytes.Equal(conn.written, expectedReply) { - t.Errorf("got unexpected data: %v", conn.written) - } -} - -func TestAuthSwitchCleartextPasswordNotAllowed(t *testing.T) { - conn, mc := newRWMockConn(2) - - conn.data = []byte{22, 0, 0, 2, 254, 109, 121, 115, 113, 108, 95, 99, 108, - 101, 97, 114, 95, 112, 97, 115, 115, 119, 111, 114, 100, 0} - conn.maxReads = 1 - authData := []byte{123, 87, 15, 84, 20, 58, 37, 121, 91, 117, 51, 24, 19, - 47, 43, 9, 41, 112, 67, 110} - plugin := "mysql_native_password" - err := mc.handleAuthResult(authData, plugin) - if err != ErrCleartextPassword { - t.Errorf("expected ErrCleartextPassword, got %v", err) - } -} - -func TestAuthSwitchCleartextPassword(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.AllowCleartextPasswords = true - mc.cfg.Passwd = "secret" - - // auth switch request - conn.data = []byte{22, 0, 0, 2, 254, 109, 121, 115, 113, 108, 95, 99, 108, - 101, 97, 114, 95, 112, 97, 115, 115, 119, 111, 114, 100, 0} - - // auth response - conn.queuedReplies = [][]byte{{7, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0}} - conn.maxReads = 2 - - authData := []byte{123, 87, 15, 84, 20, 58, 37, 121, 91, 117, 51, 24, 19, - 47, 43, 9, 41, 112, 67, 110} - plugin := "mysql_native_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReply := []byte{7, 0, 0, 3, 115, 101, 99, 114, 101, 116, 0} - if !bytes.Equal(conn.written, expectedReply) { - t.Errorf("got unexpected data: %v", conn.written) - } -} - -func TestAuthSwitchCleartextPasswordEmpty(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.AllowCleartextPasswords = true - mc.cfg.Passwd = "" - - // auth switch request - conn.data = []byte{22, 0, 0, 2, 254, 109, 121, 115, 113, 108, 95, 99, 108, - 101, 97, 114, 95, 112, 97, 115, 115, 119, 111, 114, 100, 0} - - // auth response - conn.queuedReplies = [][]byte{{7, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0}} - conn.maxReads = 2 - - authData := []byte{123, 87, 15, 84, 20, 58, 37, 121, 91, 117, 51, 24, 19, - 47, 43, 9, 41, 112, 67, 110} - plugin := "mysql_native_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReply := []byte{1, 0, 0, 3, 0} - if !bytes.Equal(conn.written, expectedReply) { - t.Errorf("got unexpected data: %v", conn.written) - } -} - -func TestAuthSwitchNativePasswordNotAllowed(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.AllowNativePasswords = false - - conn.data = []byte{44, 0, 0, 2, 254, 109, 121, 115, 113, 108, 95, 110, 97, - 116, 105, 118, 101, 95, 112, 97, 115, 115, 119, 111, 114, 100, 0, 96, - 71, 63, 8, 1, 58, 75, 12, 69, 95, 66, 60, 117, 31, 48, 31, 89, 39, 55, - 31, 0} - conn.maxReads = 1 - authData := []byte{96, 71, 63, 8, 1, 58, 75, 12, 69, 95, 66, 60, 117, 31, - 48, 31, 89, 39, 55, 31} - plugin := "caching_sha2_password" - err := mc.handleAuthResult(authData, plugin) - if err != ErrNativePassword { - t.Errorf("expected ErrNativePassword, got %v", err) - } -} - -func TestAuthSwitchNativePassword(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.AllowNativePasswords = true - mc.cfg.Passwd = "secret" - - // auth switch request - conn.data = []byte{44, 0, 0, 2, 254, 109, 121, 115, 113, 108, 95, 110, 97, - 116, 105, 118, 101, 95, 112, 97, 115, 115, 119, 111, 114, 100, 0, 96, - 71, 63, 8, 1, 58, 75, 12, 69, 95, 66, 60, 117, 31, 48, 31, 89, 39, 55, - 31, 0} - - // auth response - conn.queuedReplies = [][]byte{{7, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0}} - conn.maxReads = 2 - - authData := []byte{96, 71, 63, 8, 1, 58, 75, 12, 69, 95, 66, 60, 117, 31, - 48, 31, 89, 39, 55, 31} - plugin := "caching_sha2_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReply := []byte{20, 0, 0, 3, 202, 41, 195, 164, 34, 226, 49, 103, - 21, 211, 167, 199, 227, 116, 8, 48, 57, 71, 149, 146} - if !bytes.Equal(conn.written, expectedReply) { - t.Errorf("got unexpected data: %v", conn.written) - } -} - -func TestAuthSwitchNativePasswordEmpty(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.AllowNativePasswords = true - mc.cfg.Passwd = "" - - // auth switch request - conn.data = []byte{44, 0, 0, 2, 254, 109, 121, 115, 113, 108, 95, 110, 97, - 116, 105, 118, 101, 95, 112, 97, 115, 115, 119, 111, 114, 100, 0, 96, - 71, 63, 8, 1, 58, 75, 12, 69, 95, 66, 60, 117, 31, 48, 31, 89, 39, 55, - 31, 0} - - // auth response - conn.queuedReplies = [][]byte{{7, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0}} - conn.maxReads = 2 - - authData := []byte{96, 71, 63, 8, 1, 58, 75, 12, 69, 95, 66, 60, 117, 31, - 48, 31, 89, 39, 55, 31} - plugin := "caching_sha2_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReply := []byte{0, 0, 0, 3} - if !bytes.Equal(conn.written, expectedReply) { - t.Errorf("got unexpected data: %v", conn.written) - } -} - -func TestAuthSwitchOldPasswordNotAllowed(t *testing.T) { - conn, mc := newRWMockConn(2) - - conn.data = []byte{41, 0, 0, 2, 254, 109, 121, 115, 113, 108, 95, 111, 108, - 100, 95, 112, 97, 115, 115, 119, 111, 114, 100, 0, 95, 84, 103, 43, 61, - 49, 123, 61, 91, 50, 40, 113, 35, 84, 96, 101, 92, 123, 121, 107, 0} - conn.maxReads = 1 - authData := []byte{95, 84, 103, 43, 61, 49, 123, 61, 91, 50, 40, 113, 35, - 84, 96, 101, 92, 123, 121, 107} - plugin := "mysql_native_password" - err := mc.handleAuthResult(authData, plugin) - if err != ErrOldPassword { - t.Errorf("expected ErrOldPassword, got %v", err) - } -} - -// Same to TestAuthSwitchOldPasswordNotAllowed, but use OldAuthSwitch request. -func TestOldAuthSwitchNotAllowed(t *testing.T) { - conn, mc := newRWMockConn(2) - - // OldAuthSwitch request - conn.data = []byte{1, 0, 0, 2, 0xfe} - conn.maxReads = 1 - authData := []byte{95, 84, 103, 43, 61, 49, 123, 61, 91, 50, 40, 113, 35, - 84, 96, 101, 92, 123, 121, 107} - plugin := "mysql_native_password" - err := mc.handleAuthResult(authData, plugin) - if err != ErrOldPassword { - t.Errorf("expected ErrOldPassword, got %v", err) - } -} - -func TestAuthSwitchOldPassword(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.AllowOldPasswords = true - mc.cfg.Passwd = "secret" - - // auth switch request - conn.data = []byte{41, 0, 0, 2, 254, 109, 121, 115, 113, 108, 95, 111, 108, - 100, 95, 112, 97, 115, 115, 119, 111, 114, 100, 0, 95, 84, 103, 43, 61, - 49, 123, 61, 91, 50, 40, 113, 35, 84, 96, 101, 92, 123, 121, 107, 0} - - // auth response - conn.queuedReplies = [][]byte{{8, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 0}} - conn.maxReads = 2 - - authData := []byte{95, 84, 103, 43, 61, 49, 123, 61, 91, 50, 40, 113, 35, - 84, 96, 101, 92, 123, 121, 107} - plugin := "mysql_native_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReply := []byte{9, 0, 0, 3, 86, 83, 83, 79, 74, 78, 65, 66, 0} - if !bytes.Equal(conn.written, expectedReply) { - t.Errorf("got unexpected data: %v", conn.written) - } -} - -// Same to TestAuthSwitchOldPassword, but use OldAuthSwitch request. -func TestOldAuthSwitch(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.AllowOldPasswords = true - mc.cfg.Passwd = "secret" - - // OldAuthSwitch request - conn.data = []byte{1, 0, 0, 2, 0xfe} - - // auth response - conn.queuedReplies = [][]byte{{8, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 0}} - conn.maxReads = 2 - - authData := []byte{95, 84, 103, 43, 61, 49, 123, 61, 91, 50, 40, 113, 35, - 84, 96, 101, 92, 123, 121, 107} - plugin := "mysql_native_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReply := []byte{9, 0, 0, 3, 86, 83, 83, 79, 74, 78, 65, 66, 0} - if !bytes.Equal(conn.written, expectedReply) { - t.Errorf("got unexpected data: %v", conn.written) - } -} -func TestAuthSwitchOldPasswordEmpty(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.AllowOldPasswords = true - mc.cfg.Passwd = "" - - // auth switch request - conn.data = []byte{41, 0, 0, 2, 254, 109, 121, 115, 113, 108, 95, 111, 108, - 100, 95, 112, 97, 115, 115, 119, 111, 114, 100, 0, 95, 84, 103, 43, 61, - 49, 123, 61, 91, 50, 40, 113, 35, 84, 96, 101, 92, 123, 121, 107, 0} - - // auth response - conn.queuedReplies = [][]byte{{8, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 0}} - conn.maxReads = 2 - - authData := []byte{95, 84, 103, 43, 61, 49, 123, 61, 91, 50, 40, 113, 35, - 84, 96, 101, 92, 123, 121, 107} - plugin := "mysql_native_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReply := []byte{0, 0, 0, 3} - if !bytes.Equal(conn.written, expectedReply) { - t.Errorf("got unexpected data: %v", conn.written) - } -} - -// Same to TestAuthSwitchOldPasswordEmpty, but use OldAuthSwitch request. -func TestOldAuthSwitchPasswordEmpty(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.AllowOldPasswords = true - mc.cfg.Passwd = "" - - // OldAuthSwitch request. - conn.data = []byte{1, 0, 0, 2, 0xfe} - - // auth response - conn.queuedReplies = [][]byte{{8, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 0}} - conn.maxReads = 2 - - authData := []byte{95, 84, 103, 43, 61, 49, 123, 61, 91, 50, 40, 113, 35, - 84, 96, 101, 92, 123, 121, 107} - plugin := "mysql_native_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReply := []byte{0, 0, 0, 3} - if !bytes.Equal(conn.written, expectedReply) { - t.Errorf("got unexpected data: %v", conn.written) - } -} - -func TestAuthSwitchSHA256PasswordEmpty(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.Passwd = "" - - // auth switch request - conn.data = []byte{38, 0, 0, 2, 254, 115, 104, 97, 50, 53, 54, 95, 112, 97, - 115, 115, 119, 111, 114, 100, 0, 78, 82, 62, 40, 100, 1, 59, 31, 44, 69, - 33, 112, 8, 81, 51, 96, 65, 82, 16, 114, 0} - - conn.queuedReplies = [][]byte{ - // OK - {7, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0}, - } - conn.maxReads = 3 - - authData := []byte{123, 87, 15, 84, 20, 58, 37, 121, 91, 117, 51, 24, 19, - 47, 43, 9, 41, 112, 67, 110} - plugin := "mysql_native_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReplyPrefix := []byte{ - // 1. Packet: Empty Password - 1, 0, 0, 3, 0, - } - if !bytes.HasPrefix(conn.written, expectedReplyPrefix) { - t.Errorf("got unexpected data: %v", conn.written) - } -} - -func TestAuthSwitchSHA256PasswordRSA(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.Passwd = "secret" - - // auth switch request - conn.data = []byte{38, 0, 0, 2, 254, 115, 104, 97, 50, 53, 54, 95, 112, 97, - 115, 115, 119, 111, 114, 100, 0, 78, 82, 62, 40, 100, 1, 59, 31, 44, 69, - 33, 112, 8, 81, 51, 96, 65, 82, 16, 114, 0} - - conn.queuedReplies = [][]byte{ - // Pub Key Response - append([]byte{byte(1 + len(testPubKey)), 1, 0, 4, 1}, testPubKey...), - - // OK - {7, 0, 0, 6, 0, 0, 0, 2, 0, 0, 0}, - } - conn.maxReads = 3 - - authData := []byte{123, 87, 15, 84, 20, 58, 37, 121, 91, 117, 51, 24, 19, - 47, 43, 9, 41, 112, 67, 110} - plugin := "mysql_native_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReplyPrefix := []byte{ - // 1. Packet: Pub Key Request - 1, 0, 0, 3, 1, - - // 2. Packet: Encrypted Password - 0, 1, 0, 5, // [changing bytes] - } - if !bytes.HasPrefix(conn.written, expectedReplyPrefix) { - t.Errorf("got unexpected data: %v", conn.written) - } -} - -func TestAuthSwitchSHA256PasswordRSAWithKey(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.Passwd = "secret" - mc.cfg.pubKey = testPubKeyRSA - - // auth switch request - conn.data = []byte{38, 0, 0, 2, 254, 115, 104, 97, 50, 53, 54, 95, 112, 97, - 115, 115, 119, 111, 114, 100, 0, 78, 82, 62, 40, 100, 1, 59, 31, 44, 69, - 33, 112, 8, 81, 51, 96, 65, 82, 16, 114, 0} - - conn.queuedReplies = [][]byte{ - // OK - {7, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0}, - } - conn.maxReads = 2 - - authData := []byte{123, 87, 15, 84, 20, 58, 37, 121, 91, 117, 51, 24, 19, - 47, 43, 9, 41, 112, 67, 110} - plugin := "mysql_native_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReplyPrefix := []byte{ - // 1. Packet: Encrypted Password - 0, 1, 0, 3, // [changing bytes] - } - if !bytes.HasPrefix(conn.written, expectedReplyPrefix) { - t.Errorf("got unexpected data: %v", conn.written) - } -} - -func TestAuthSwitchSHA256PasswordSecure(t *testing.T) { - conn, mc := newRWMockConn(2) - mc.cfg.Passwd = "secret" - - // Hack to make the caching_sha2_password plugin believe that the connection - // is secure - mc.cfg.tls = &tls.Config{InsecureSkipVerify: true} - - // auth switch request - conn.data = []byte{38, 0, 0, 2, 254, 115, 104, 97, 50, 53, 54, 95, 112, 97, - 115, 115, 119, 111, 114, 100, 0, 78, 82, 62, 40, 100, 1, 59, 31, 44, 69, - 33, 112, 8, 81, 51, 96, 65, 82, 16, 114, 0} - - conn.queuedReplies = [][]byte{ - // OK - {7, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0}, - } - conn.maxReads = 2 - - authData := []byte{123, 87, 15, 84, 20, 58, 37, 121, 91, 117, 51, 24, 19, - 47, 43, 9, 41, 112, 67, 110} - plugin := "mysql_native_password" - - if err := mc.handleAuthResult(authData, plugin); err != nil { - t.Errorf("got error: %v", err) - } - - expectedReplyPrefix := []byte{ - // 1. Packet: Cleartext Password - 7, 0, 0, 3, 115, 101, 99, 114, 101, 116, 0, - } - if !bytes.Equal(conn.written, expectedReplyPrefix) { - t.Errorf("got unexpected data: %v", conn.written) - } -} diff --git a/proxy_go/public/mysql@v1.6.0/benchmark_test.go b/proxy_go/public/mysql@v1.6.0/benchmark_test.go deleted file mode 100644 index 1030ddc..0000000 --- a/proxy_go/public/mysql@v1.6.0/benchmark_test.go +++ /dev/null @@ -1,374 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "bytes" - "context" - "database/sql" - "database/sql/driver" - "fmt" - "math" - "runtime" - "strings" - "sync" - "sync/atomic" - "testing" - "time" -) - -type TB testing.B - -func (tb *TB) check(err error) { - if err != nil { - tb.Fatal(err) - } -} - -func (tb *TB) checkDB(db *sql.DB, err error) *sql.DB { - tb.check(err) - return db -} - -func (tb *TB) checkRows(rows *sql.Rows, err error) *sql.Rows { - tb.check(err) - return rows -} - -func (tb *TB) checkStmt(stmt *sql.Stmt, err error) *sql.Stmt { - tb.check(err) - return stmt -} - -func initDB(b *testing.B, queries ...string) *sql.DB { - tb := (*TB)(b) - db := tb.checkDB(sql.Open("mysql", dsn)) - for _, query := range queries { - if _, err := db.Exec(query); err != nil { - b.Fatalf("error on %q: %v", query, err) - } - } - return db -} - -const concurrencyLevel = 10 - -func BenchmarkQuery(b *testing.B) { - tb := (*TB)(b) - b.StopTimer() - b.ReportAllocs() - db := initDB(b, - "DROP TABLE IF EXISTS foo", - "CREATE TABLE foo (id INT PRIMARY KEY, val CHAR(50))", - `INSERT INTO foo VALUES (1, "one")`, - `INSERT INTO foo VALUES (2, "two")`, - ) - db.SetMaxIdleConns(concurrencyLevel) - defer db.Close() - - stmt := tb.checkStmt(db.Prepare("SELECT val FROM foo WHERE id=?")) - defer stmt.Close() - - remain := int64(b.N) - var wg sync.WaitGroup - wg.Add(concurrencyLevel) - defer wg.Wait() - b.StartTimer() - - for i := 0; i < concurrencyLevel; i++ { - go func() { - for { - if atomic.AddInt64(&remain, -1) < 0 { - wg.Done() - return - } - - var got string - tb.check(stmt.QueryRow(1).Scan(&got)) - if got != "one" { - b.Errorf("query = %q; want one", got) - wg.Done() - return - } - } - }() - } -} - -func BenchmarkExec(b *testing.B) { - tb := (*TB)(b) - b.StopTimer() - b.ReportAllocs() - db := tb.checkDB(sql.Open("mysql", dsn)) - db.SetMaxIdleConns(concurrencyLevel) - defer db.Close() - - stmt := tb.checkStmt(db.Prepare("DO 1")) - defer stmt.Close() - - remain := int64(b.N) - var wg sync.WaitGroup - wg.Add(concurrencyLevel) - defer wg.Wait() - b.StartTimer() - - for i := 0; i < concurrencyLevel; i++ { - go func() { - for { - if atomic.AddInt64(&remain, -1) < 0 { - wg.Done() - return - } - - if _, err := stmt.Exec(); err != nil { - b.Logf("stmt.Exec failed: %v", err) - b.Fail() - } - } - }() - } -} - -// data, but no db writes -var roundtripSample []byte - -func initRoundtripBenchmarks() ([]byte, int, int) { - if roundtripSample == nil { - roundtripSample = []byte(strings.Repeat("0123456789abcdef", 1024*1024)) - } - return roundtripSample, 16, len(roundtripSample) -} - -func BenchmarkRoundtripTxt(b *testing.B) { - b.StopTimer() - sample, min, max := initRoundtripBenchmarks() - sampleString := string(sample) - b.ReportAllocs() - tb := (*TB)(b) - db := tb.checkDB(sql.Open("mysql", dsn)) - defer db.Close() - b.StartTimer() - var result string - for i := 0; i < b.N; i++ { - length := min + i - if length > max { - length = max - } - test := sampleString[0:length] - rows := tb.checkRows(db.Query(`SELECT "` + test + `"`)) - if !rows.Next() { - rows.Close() - b.Fatalf("crashed") - } - err := rows.Scan(&result) - if err != nil { - rows.Close() - b.Fatalf("crashed") - } - if result != test { - rows.Close() - b.Errorf("mismatch") - } - rows.Close() - } -} - -func BenchmarkRoundtripBin(b *testing.B) { - b.StopTimer() - sample, min, max := initRoundtripBenchmarks() - b.ReportAllocs() - tb := (*TB)(b) - db := tb.checkDB(sql.Open("mysql", dsn)) - defer db.Close() - stmt := tb.checkStmt(db.Prepare("SELECT ?")) - defer stmt.Close() - b.StartTimer() - var result sql.RawBytes - for i := 0; i < b.N; i++ { - length := min + i - if length > max { - length = max - } - test := sample[0:length] - rows := tb.checkRows(stmt.Query(test)) - if !rows.Next() { - rows.Close() - b.Fatalf("crashed") - } - err := rows.Scan(&result) - if err != nil { - rows.Close() - b.Fatalf("crashed") - } - if !bytes.Equal(result, test) { - rows.Close() - b.Errorf("mismatch") - } - rows.Close() - } -} - -func BenchmarkInterpolation(b *testing.B) { - mc := &mysqlConn{ - cfg: &Config{ - InterpolateParams: true, - Loc: time.UTC, - }, - maxAllowedPacket: maxPacketSize, - maxWriteSize: maxPacketSize - 1, - buf: newBuffer(nil), - } - - args := []driver.Value{ - int64(42424242), - float64(math.Pi), - false, - time.Unix(1423411542, 807015000), - []byte("bytes containing special chars ' \" \a \x00"), - "string containing special chars ' \" \a \x00", - } - q := "SELECT ?, ?, ?, ?, ?, ?" - - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, err := mc.interpolateParams(q, args) - if err != nil { - b.Fatal(err) - } - } -} - -func benchmarkQueryContext(b *testing.B, db *sql.DB, p int) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - db.SetMaxIdleConns(p * runtime.GOMAXPROCS(0)) - - tb := (*TB)(b) - stmt := tb.checkStmt(db.PrepareContext(ctx, "SELECT val FROM foo WHERE id=?")) - defer stmt.Close() - - b.SetParallelism(p) - b.ReportAllocs() - b.ResetTimer() - b.RunParallel(func(pb *testing.PB) { - var got string - for pb.Next() { - tb.check(stmt.QueryRow(1).Scan(&got)) - if got != "one" { - b.Fatalf("query = %q; want one", got) - } - } - }) -} - -func BenchmarkQueryContext(b *testing.B) { - db := initDB(b, - "DROP TABLE IF EXISTS foo", - "CREATE TABLE foo (id INT PRIMARY KEY, val CHAR(50))", - `INSERT INTO foo VALUES (1, "one")`, - `INSERT INTO foo VALUES (2, "two")`, - ) - defer db.Close() - for _, p := range []int{1, 2, 3, 4} { - b.Run(fmt.Sprintf("%d", p), func(b *testing.B) { - benchmarkQueryContext(b, db, p) - }) - } -} - -func benchmarkExecContext(b *testing.B, db *sql.DB, p int) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - db.SetMaxIdleConns(p * runtime.GOMAXPROCS(0)) - - tb := (*TB)(b) - stmt := tb.checkStmt(db.PrepareContext(ctx, "DO 1")) - defer stmt.Close() - - b.SetParallelism(p) - b.ReportAllocs() - b.ResetTimer() - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - if _, err := stmt.ExecContext(ctx); err != nil { - b.Fatal(err) - } - } - }) -} - -func BenchmarkExecContext(b *testing.B) { - db := initDB(b, - "DROP TABLE IF EXISTS foo", - "CREATE TABLE foo (id INT PRIMARY KEY, val CHAR(50))", - `INSERT INTO foo VALUES (1, "one")`, - `INSERT INTO foo VALUES (2, "two")`, - ) - defer db.Close() - for _, p := range []int{1, 2, 3, 4} { - b.Run(fmt.Sprintf("%d", p), func(b *testing.B) { - benchmarkQueryContext(b, db, p) - }) - } -} - -// BenchmarkQueryRawBytes benchmarks fetching 100 blobs using sql.RawBytes. -// "size=" means size of each blobs. -func BenchmarkQueryRawBytes(b *testing.B) { - var sizes []int = []int{100, 1000, 2000, 4000, 8000, 12000, 16000, 32000, 64000, 256000} - db := initDB(b, - "DROP TABLE IF EXISTS bench_rawbytes", - "CREATE TABLE bench_rawbytes (id INT PRIMARY KEY, val LONGBLOB)", - ) - defer db.Close() - - blob := make([]byte, sizes[len(sizes)-1]) - for i := range blob { - blob[i] = 42 - } - for i := 0; i < 100; i++ { - _, err := db.Exec("INSERT INTO bench_rawbytes VALUES (?, ?)", i, blob) - if err != nil { - b.Fatal(err) - } - } - - for _, s := range sizes { - b.Run(fmt.Sprintf("size=%v", s), func(b *testing.B) { - db.SetMaxIdleConns(0) - db.SetMaxIdleConns(1) - b.ReportAllocs() - b.ResetTimer() - - for j := 0; j < b.N; j++ { - rows, err := db.Query("SELECT LEFT(val, ?) as v FROM bench_rawbytes", s) - if err != nil { - b.Fatal(err) - } - nrows := 0 - for rows.Next() { - var buf sql.RawBytes - err := rows.Scan(&buf) - if err != nil { - b.Fatal(err) - } - if len(buf) != s { - b.Fatalf("size mismatch: expected %v, got %v", s, len(buf)) - } - nrows++ - } - rows.Close() - if nrows != 100 { - b.Fatalf("numbers of rows mismatch: expected %v, got %v", 100, nrows) - } - } - }) - } -} diff --git a/proxy_go/public/mysql@v1.6.0/buffer.go b/proxy_go/public/mysql@v1.6.0/buffer.go deleted file mode 100644 index 0774c5c..0000000 --- a/proxy_go/public/mysql@v1.6.0/buffer.go +++ /dev/null @@ -1,182 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "io" - "net" - "time" -) - -const defaultBufSize = 4096 -const maxCachedBufSize = 256 * 1024 - -// A buffer which is used for both reading and writing. -// This is possible since communication on each connection is synchronous. -// In other words, we can't write and read simultaneously on the same connection. -// The buffer is similar to bufio.Reader / Writer but zero-copy-ish -// Also highly optimized for this particular use case. -// This buffer is backed by two byte slices in a double-buffering scheme -type buffer struct { - buf []byte // buf is a byte buffer who's length and capacity are equal. - nc net.Conn - idx int - length int - timeout time.Duration - dbuf [2][]byte // dbuf is an array with the two byte slices that back this buffer - flipcnt uint // flipccnt is the current buffer counter for double-buffering -} - -// newBuffer allocates and returns a new buffer. -func newBuffer(nc net.Conn) buffer { - fg := make([]byte, defaultBufSize) - return buffer{ - buf: fg, - nc: nc, - dbuf: [2][]byte{fg, nil}, - } -} - -// flip replaces the active buffer with the background buffer -// this is a delayed flip that simply increases the buffer counter; -// the actual flip will be performed the next time we call `buffer.fill` -func (b *buffer) flip() { - b.flipcnt += 1 -} - -// fill reads into the buffer until at least _need_ bytes are in it -func (b *buffer) fill(need int) error { - n := b.length - // fill data into its double-buffering target: if we've called - // flip on this buffer, we'll be copying to the background buffer, - // and then filling it with network data; otherwise we'll just move - // the contents of the current buffer to the front before filling it - dest := b.dbuf[b.flipcnt&1] - - // grow buffer if necessary to fit the whole packet. - if need > len(dest) { - // Round up to the next multiple of the default size - dest = make([]byte, ((need/defaultBufSize)+1)*defaultBufSize) - - // if the allocated buffer is not too large, move it to backing storage - // to prevent extra allocations on applications that perform large reads - if len(dest) <= maxCachedBufSize { - b.dbuf[b.flipcnt&1] = dest - } - } - - // if we're filling the fg buffer, move the existing data to the start of it. - // if we're filling the bg buffer, copy over the data - if n > 0 { - copy(dest[:n], b.buf[b.idx:]) - } - - b.buf = dest - b.idx = 0 - - for { - if b.timeout > 0 { - if err := b.nc.SetReadDeadline(time.Now().Add(b.timeout)); err != nil { - return err - } - } - - nn, err := b.nc.Read(b.buf[n:]) - n += nn - - switch err { - case nil: - if n < need { - continue - } - b.length = n - return nil - - case io.EOF: - if n >= need { - b.length = n - return nil - } - return io.ErrUnexpectedEOF - - default: - return err - } - } -} - -// returns next N bytes from buffer. -// The returned slice is only guaranteed to be valid until the next read -func (b *buffer) readNext(need int) ([]byte, error) { - if b.length < need { - // refill - if err := b.fill(need); err != nil { - return nil, err - } - } - - offset := b.idx - b.idx += need - b.length -= need - return b.buf[offset:b.idx], nil -} - -// takeBuffer returns a buffer with the requested size. -// If possible, a slice from the existing buffer is returned. -// Otherwise a bigger buffer is made. -// Only one buffer (total) can be used at a time. -func (b *buffer) takeBuffer(length int) ([]byte, error) { - if b.length > 0 { - return nil, ErrBusyBuffer - } - - // test (cheap) general case first - if length <= cap(b.buf) { - return b.buf[:length], nil - } - - if length < maxPacketSize { - b.buf = make([]byte, length) - return b.buf, nil - } - - // buffer is larger than we want to store. - return make([]byte, length), nil -} - -// takeSmallBuffer is shortcut which can be used if length is -// known to be smaller than defaultBufSize. -// Only one buffer (total) can be used at a time. -func (b *buffer) takeSmallBuffer(length int) ([]byte, error) { - if b.length > 0 { - return nil, ErrBusyBuffer - } - return b.buf[:length], nil -} - -// takeCompleteBuffer returns the complete existing buffer. -// This can be used if the necessary buffer size is unknown. -// cap and len of the returned buffer will be equal. -// Only one buffer (total) can be used at a time. -func (b *buffer) takeCompleteBuffer() ([]byte, error) { - if b.length > 0 { - return nil, ErrBusyBuffer - } - return b.buf, nil -} - -// store stores buf, an updated buffer, if its suitable to do so. -func (b *buffer) store(buf []byte) error { - if b.length > 0 { - return ErrBusyBuffer - } else if cap(buf) <= maxPacketSize && cap(buf) > cap(b.buf) { - b.buf = buf[:cap(buf)] - } - return nil -} diff --git a/proxy_go/public/mysql@v1.6.0/collations.go b/proxy_go/public/mysql@v1.6.0/collations.go deleted file mode 100644 index 326a9f7..0000000 --- a/proxy_go/public/mysql@v1.6.0/collations.go +++ /dev/null @@ -1,265 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2014 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -const defaultCollation = "utf8mb4_general_ci" -const binaryCollation = "binary" - -// A list of available collations mapped to the internal ID. -// To update this map use the following MySQL query: -// SELECT COLLATION_NAME, ID FROM information_schema.COLLATIONS WHERE ID<256 ORDER BY ID -// -// Handshake packet have only 1 byte for collation_id. So we can't use collations with ID > 255. -// -// ucs2, utf16, and utf32 can't be used for connection charset. -// https://dev.mysql.com/doc/refman/5.7/en/charset-connection.html#charset-connection-impermissible-client-charset -// They are commented out to reduce this map. -var collations = map[string]byte{ - "big5_chinese_ci": 1, - "latin2_czech_cs": 2, - "dec8_swedish_ci": 3, - "cp850_general_ci": 4, - "latin1_german1_ci": 5, - "hp8_english_ci": 6, - "koi8r_general_ci": 7, - "latin1_swedish_ci": 8, - "latin2_general_ci": 9, - "swe7_swedish_ci": 10, - "ascii_general_ci": 11, - "ujis_japanese_ci": 12, - "sjis_japanese_ci": 13, - "cp1251_bulgarian_ci": 14, - "latin1_danish_ci": 15, - "hebrew_general_ci": 16, - "tis620_thai_ci": 18, - "euckr_korean_ci": 19, - "latin7_estonian_cs": 20, - "latin2_hungarian_ci": 21, - "koi8u_general_ci": 22, - "cp1251_ukrainian_ci": 23, - "gb2312_chinese_ci": 24, - "greek_general_ci": 25, - "cp1250_general_ci": 26, - "latin2_croatian_ci": 27, - "gbk_chinese_ci": 28, - "cp1257_lithuanian_ci": 29, - "latin5_turkish_ci": 30, - "latin1_german2_ci": 31, - "armscii8_general_ci": 32, - "utf8_general_ci": 33, - "cp1250_czech_cs": 34, - //"ucs2_general_ci": 35, - "cp866_general_ci": 36, - "keybcs2_general_ci": 37, - "macce_general_ci": 38, - "macroman_general_ci": 39, - "cp852_general_ci": 40, - "latin7_general_ci": 41, - "latin7_general_cs": 42, - "macce_bin": 43, - "cp1250_croatian_ci": 44, - "utf8mb4_general_ci": 45, - "utf8mb4_bin": 46, - "latin1_bin": 47, - "latin1_general_ci": 48, - "latin1_general_cs": 49, - "cp1251_bin": 50, - "cp1251_general_ci": 51, - "cp1251_general_cs": 52, - "macroman_bin": 53, - //"utf16_general_ci": 54, - //"utf16_bin": 55, - //"utf16le_general_ci": 56, - "cp1256_general_ci": 57, - "cp1257_bin": 58, - "cp1257_general_ci": 59, - //"utf32_general_ci": 60, - //"utf32_bin": 61, - //"utf16le_bin": 62, - "binary": 63, - "armscii8_bin": 64, - "ascii_bin": 65, - "cp1250_bin": 66, - "cp1256_bin": 67, - "cp866_bin": 68, - "dec8_bin": 69, - "greek_bin": 70, - "hebrew_bin": 71, - "hp8_bin": 72, - "keybcs2_bin": 73, - "koi8r_bin": 74, - "koi8u_bin": 75, - "utf8_tolower_ci": 76, - "latin2_bin": 77, - "latin5_bin": 78, - "latin7_bin": 79, - "cp850_bin": 80, - "cp852_bin": 81, - "swe7_bin": 82, - "utf8_bin": 83, - "big5_bin": 84, - "euckr_bin": 85, - "gb2312_bin": 86, - "gbk_bin": 87, - "sjis_bin": 88, - "tis620_bin": 89, - //"ucs2_bin": 90, - "ujis_bin": 91, - "geostd8_general_ci": 92, - "geostd8_bin": 93, - "latin1_spanish_ci": 94, - "cp932_japanese_ci": 95, - "cp932_bin": 96, - "eucjpms_japanese_ci": 97, - "eucjpms_bin": 98, - "cp1250_polish_ci": 99, - //"utf16_unicode_ci": 101, - //"utf16_icelandic_ci": 102, - //"utf16_latvian_ci": 103, - //"utf16_romanian_ci": 104, - //"utf16_slovenian_ci": 105, - //"utf16_polish_ci": 106, - //"utf16_estonian_ci": 107, - //"utf16_spanish_ci": 108, - //"utf16_swedish_ci": 109, - //"utf16_turkish_ci": 110, - //"utf16_czech_ci": 111, - //"utf16_danish_ci": 112, - //"utf16_lithuanian_ci": 113, - //"utf16_slovak_ci": 114, - //"utf16_spanish2_ci": 115, - //"utf16_roman_ci": 116, - //"utf16_persian_ci": 117, - //"utf16_esperanto_ci": 118, - //"utf16_hungarian_ci": 119, - //"utf16_sinhala_ci": 120, - //"utf16_german2_ci": 121, - //"utf16_croatian_ci": 122, - //"utf16_unicode_520_ci": 123, - //"utf16_vietnamese_ci": 124, - //"ucs2_unicode_ci": 128, - //"ucs2_icelandic_ci": 129, - //"ucs2_latvian_ci": 130, - //"ucs2_romanian_ci": 131, - //"ucs2_slovenian_ci": 132, - //"ucs2_polish_ci": 133, - //"ucs2_estonian_ci": 134, - //"ucs2_spanish_ci": 135, - //"ucs2_swedish_ci": 136, - //"ucs2_turkish_ci": 137, - //"ucs2_czech_ci": 138, - //"ucs2_danish_ci": 139, - //"ucs2_lithuanian_ci": 140, - //"ucs2_slovak_ci": 141, - //"ucs2_spanish2_ci": 142, - //"ucs2_roman_ci": 143, - //"ucs2_persian_ci": 144, - //"ucs2_esperanto_ci": 145, - //"ucs2_hungarian_ci": 146, - //"ucs2_sinhala_ci": 147, - //"ucs2_german2_ci": 148, - //"ucs2_croatian_ci": 149, - //"ucs2_unicode_520_ci": 150, - //"ucs2_vietnamese_ci": 151, - //"ucs2_general_mysql500_ci": 159, - //"utf32_unicode_ci": 160, - //"utf32_icelandic_ci": 161, - //"utf32_latvian_ci": 162, - //"utf32_romanian_ci": 163, - //"utf32_slovenian_ci": 164, - //"utf32_polish_ci": 165, - //"utf32_estonian_ci": 166, - //"utf32_spanish_ci": 167, - //"utf32_swedish_ci": 168, - //"utf32_turkish_ci": 169, - //"utf32_czech_ci": 170, - //"utf32_danish_ci": 171, - //"utf32_lithuanian_ci": 172, - //"utf32_slovak_ci": 173, - //"utf32_spanish2_ci": 174, - //"utf32_roman_ci": 175, - //"utf32_persian_ci": 176, - //"utf32_esperanto_ci": 177, - //"utf32_hungarian_ci": 178, - //"utf32_sinhala_ci": 179, - //"utf32_german2_ci": 180, - //"utf32_croatian_ci": 181, - //"utf32_unicode_520_ci": 182, - //"utf32_vietnamese_ci": 183, - "utf8_unicode_ci": 192, - "utf8_icelandic_ci": 193, - "utf8_latvian_ci": 194, - "utf8_romanian_ci": 195, - "utf8_slovenian_ci": 196, - "utf8_polish_ci": 197, - "utf8_estonian_ci": 198, - "utf8_spanish_ci": 199, - "utf8_swedish_ci": 200, - "utf8_turkish_ci": 201, - "utf8_czech_ci": 202, - "utf8_danish_ci": 203, - "utf8_lithuanian_ci": 204, - "utf8_slovak_ci": 205, - "utf8_spanish2_ci": 206, - "utf8_roman_ci": 207, - "utf8_persian_ci": 208, - "utf8_esperanto_ci": 209, - "utf8_hungarian_ci": 210, - "utf8_sinhala_ci": 211, - "utf8_german2_ci": 212, - "utf8_croatian_ci": 213, - "utf8_unicode_520_ci": 214, - "utf8_vietnamese_ci": 215, - "utf8_general_mysql500_ci": 223, - "utf8mb4_unicode_ci": 224, - "utf8mb4_icelandic_ci": 225, - "utf8mb4_latvian_ci": 226, - "utf8mb4_romanian_ci": 227, - "utf8mb4_slovenian_ci": 228, - "utf8mb4_polish_ci": 229, - "utf8mb4_estonian_ci": 230, - "utf8mb4_spanish_ci": 231, - "utf8mb4_swedish_ci": 232, - "utf8mb4_turkish_ci": 233, - "utf8mb4_czech_ci": 234, - "utf8mb4_danish_ci": 235, - "utf8mb4_lithuanian_ci": 236, - "utf8mb4_slovak_ci": 237, - "utf8mb4_spanish2_ci": 238, - "utf8mb4_roman_ci": 239, - "utf8mb4_persian_ci": 240, - "utf8mb4_esperanto_ci": 241, - "utf8mb4_hungarian_ci": 242, - "utf8mb4_sinhala_ci": 243, - "utf8mb4_german2_ci": 244, - "utf8mb4_croatian_ci": 245, - "utf8mb4_unicode_520_ci": 246, - "utf8mb4_vietnamese_ci": 247, - "gb18030_chinese_ci": 248, - "gb18030_bin": 249, - "gb18030_unicode_520_ci": 250, - "utf8mb4_0900_ai_ci": 255, -} - -// A denylist of collations which is unsafe to interpolate parameters. -// These multibyte encodings may contains 0x5c (`\`) in their trailing bytes. -var unsafeCollations = map[string]bool{ - "big5_chinese_ci": true, - "sjis_japanese_ci": true, - "gbk_chinese_ci": true, - "big5_bin": true, - "gb2312_bin": true, - "gbk_bin": true, - "sjis_bin": true, - "cp932_japanese_ci": true, - "cp932_bin": true, - "gb18030_chinese_ci": true, - "gb18030_bin": true, - "gb18030_unicode_520_ci": true, -} diff --git a/proxy_go/public/mysql@v1.6.0/conncheck.go b/proxy_go/public/mysql@v1.6.0/conncheck.go deleted file mode 100644 index 024eb28..0000000 --- a/proxy_go/public/mysql@v1.6.0/conncheck.go +++ /dev/null @@ -1,54 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2019 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -// +build linux darwin dragonfly freebsd netbsd openbsd solaris illumos - -package mysql - -import ( - "errors" - "io" - "net" - "syscall" -) - -var errUnexpectedRead = errors.New("unexpected read from socket") - -func connCheck(conn net.Conn) error { - var sysErr error - - sysConn, ok := conn.(syscall.Conn) - if !ok { - return nil - } - rawConn, err := sysConn.SyscallConn() - if err != nil { - return err - } - - err = rawConn.Read(func(fd uintptr) bool { - var buf [1]byte - n, err := syscall.Read(int(fd), buf[:]) - switch { - case n == 0 && err == nil: - sysErr = io.EOF - case n > 0: - sysErr = errUnexpectedRead - case err == syscall.EAGAIN || err == syscall.EWOULDBLOCK: - sysErr = nil - default: - sysErr = err - } - return true - }) - if err != nil { - return err - } - - return sysErr -} diff --git a/proxy_go/public/mysql@v1.6.0/conncheck_dummy.go b/proxy_go/public/mysql@v1.6.0/conncheck_dummy.go deleted file mode 100644 index ea7fb60..0000000 --- a/proxy_go/public/mysql@v1.6.0/conncheck_dummy.go +++ /dev/null @@ -1,17 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2019 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -// +build !linux,!darwin,!dragonfly,!freebsd,!netbsd,!openbsd,!solaris,!illumos - -package mysql - -import "net" - -func connCheck(conn net.Conn) error { - return nil -} diff --git a/proxy_go/public/mysql@v1.6.0/conncheck_test.go b/proxy_go/public/mysql@v1.6.0/conncheck_test.go deleted file mode 100644 index 5399551..0000000 --- a/proxy_go/public/mysql@v1.6.0/conncheck_test.go +++ /dev/null @@ -1,38 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -// +build linux darwin dragonfly freebsd netbsd openbsd solaris illumos - -package mysql - -import ( - "testing" - "time" -) - -func TestStaleConnectionChecks(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - dbt.mustExec("SET @@SESSION.wait_timeout = 2") - - if err := dbt.db.Ping(); err != nil { - dbt.Fatal(err) - } - - // wait for MySQL to close our connection - time.Sleep(3 * time.Second) - - tx, err := dbt.db.Begin() - if err != nil { - dbt.Fatal(err) - } - - if err := tx.Rollback(); err != nil { - dbt.Fatal(err) - } - }) -} diff --git a/proxy_go/public/mysql@v1.6.0/connection.go b/proxy_go/public/mysql@v1.6.0/connection.go deleted file mode 100644 index 835f897..0000000 --- a/proxy_go/public/mysql@v1.6.0/connection.go +++ /dev/null @@ -1,650 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "context" - "database/sql" - "database/sql/driver" - "encoding/json" - "io" - "net" - "strconv" - "strings" - "time" -) - -type mysqlConn struct { - buf buffer - netConn net.Conn - rawConn net.Conn // underlying connection when netConn is TLS connection. - affectedRows uint64 - insertId uint64 - cfg *Config - maxAllowedPacket int - maxWriteSize int - writeTimeout time.Duration - flags clientFlag - status statusFlag - sequence uint8 - parseTime bool - reset bool // set when the Go SQL package calls ResetSession - - // for context support (Go 1.8+) - watching bool - watcher chan<- context.Context - closech chan struct{} - finished chan<- struct{} - canceled atomicError // set non-nil if conn is canceled - closed atomicBool // set when conn is closed, before closech is closed -} - -// Handles parameters set in DSN after the connection is established -func (mc *mysqlConn) handleParams() (err error) { - var cmdSet strings.Builder - for param, val := range mc.cfg.Params { - switch param { - // Charset: character_set_connection, character_set_client, character_set_results - case "charset": - charsets := strings.Split(val, ",") - for i := range charsets { - // ignore errors here - a charset may not exist - err = mc.exec("SET NAMES " + charsets[i]) - if err == nil { - break - } - } - if err != nil { - return - } - - // Other system vars accumulated in a single SET command - default: - if cmdSet.Len() == 0 { - // Heuristic: 29 chars for each other key=value to reduce reallocations - cmdSet.Grow(4 + len(param) + 1 + len(val) + 30*(len(mc.cfg.Params)-1)) - cmdSet.WriteString("SET ") - } else { - cmdSet.WriteByte(',') - } - cmdSet.WriteString(param) - cmdSet.WriteByte('=') - cmdSet.WriteString(val) - } - } - - if cmdSet.Len() > 0 { - err = mc.exec(cmdSet.String()) - if err != nil { - return - } - } - - return -} - -func (mc *mysqlConn) markBadConn(err error) error { - if mc == nil { - return err - } - if err != errBadConnNoWrite { - return err - } - return driver.ErrBadConn -} - -func (mc *mysqlConn) Begin() (driver.Tx, error) { - return mc.begin(false) -} - -func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) { - if mc.closed.IsSet() { - errLog.Print(ErrInvalidConn) - return nil, driver.ErrBadConn - } - var q string - if readOnly { - q = "START TRANSACTION READ ONLY" - } else { - q = "START TRANSACTION" - } - err := mc.exec(q) - if err == nil { - return &mysqlTx{mc}, err - } - return nil, mc.markBadConn(err) -} - -func (mc *mysqlConn) Close() (err error) { - // Makes Close idempotent - if !mc.closed.IsSet() { - err = mc.writeCommandPacket(comQuit) - } - - mc.cleanup() - - return -} - -// Closes the network connection and unsets internal variables. Do not call this -// function after successfully authentication, call Close instead. This function -// is called before auth or on auth failure because MySQL will have already -// closed the network connection. -func (mc *mysqlConn) cleanup() { - if !mc.closed.TrySet(true) { - return - } - - // Makes cleanup idempotent - close(mc.closech) - if mc.netConn == nil { - return - } - if err := mc.netConn.Close(); err != nil { - errLog.Print(err) - } -} - -func (mc *mysqlConn) error() error { - if mc.closed.IsSet() { - if err := mc.canceled.Value(); err != nil { - return err - } - return ErrInvalidConn - } - return nil -} - -func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) { - if mc.closed.IsSet() { - errLog.Print(ErrInvalidConn) - return nil, driver.ErrBadConn - } - // Send command - err := mc.writeCommandPacketStr(comStmtPrepare, query) - if err != nil { - // STMT_PREPARE is safe to retry. So we can return ErrBadConn here. - errLog.Print(err) - return nil, driver.ErrBadConn - } - - stmt := &mysqlStmt{ - mc: mc, - } - - // Read Result - columnCount, err := stmt.readPrepareResultPacket() - if err == nil { - if stmt.paramCount > 0 { - if err = mc.readUntilEOF(); err != nil { - return nil, err - } - } - - if columnCount > 0 { - err = mc.readUntilEOF() - } - } - - return stmt, err -} - -func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (string, error) { - // Number of ? should be same to len(args) - if strings.Count(query, "?") != len(args) { - return "", driver.ErrSkip - } - - buf, err := mc.buf.takeCompleteBuffer() - if err != nil { - // can not take the buffer. Something must be wrong with the connection - errLog.Print(err) - return "", ErrInvalidConn - } - buf = buf[:0] - argPos := 0 - - for i := 0; i < len(query); i++ { - q := strings.IndexByte(query[i:], '?') - if q == -1 { - buf = append(buf, query[i:]...) - break - } - buf = append(buf, query[i:i+q]...) - i += q - - arg := args[argPos] - argPos++ - - if arg == nil { - buf = append(buf, "NULL"...) - continue - } - - switch v := arg.(type) { - case int64: - buf = strconv.AppendInt(buf, v, 10) - case uint64: - // Handle uint64 explicitly because our custom ConvertValue emits unsigned values - buf = strconv.AppendUint(buf, v, 10) - case float64: - buf = strconv.AppendFloat(buf, v, 'g', -1, 64) - case bool: - if v { - buf = append(buf, '1') - } else { - buf = append(buf, '0') - } - case time.Time: - if v.IsZero() { - buf = append(buf, "'0000-00-00'"...) - } else { - buf = append(buf, '\'') - buf, err = appendDateTime(buf, v.In(mc.cfg.Loc)) - if err != nil { - return "", err - } - buf = append(buf, '\'') - } - case json.RawMessage: - buf = append(buf, '\'') - if mc.status&statusNoBackslashEscapes == 0 { - buf = escapeBytesBackslash(buf, v) - } else { - buf = escapeBytesQuotes(buf, v) - } - buf = append(buf, '\'') - case []byte: - if v == nil { - buf = append(buf, "NULL"...) - } else { - buf = append(buf, "_binary'"...) - if mc.status&statusNoBackslashEscapes == 0 { - buf = escapeBytesBackslash(buf, v) - } else { - buf = escapeBytesQuotes(buf, v) - } - buf = append(buf, '\'') - } - case string: - buf = append(buf, '\'') - if mc.status&statusNoBackslashEscapes == 0 { - buf = escapeStringBackslash(buf, v) - } else { - buf = escapeStringQuotes(buf, v) - } - buf = append(buf, '\'') - default: - return "", driver.ErrSkip - } - - if len(buf)+4 > mc.maxAllowedPacket { - return "", driver.ErrSkip - } - } - if argPos != len(args) { - return "", driver.ErrSkip - } - return string(buf), nil -} - -func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) { - if mc.closed.IsSet() { - errLog.Print(ErrInvalidConn) - return nil, driver.ErrBadConn - } - if len(args) != 0 { - if !mc.cfg.InterpolateParams { - return nil, driver.ErrSkip - } - // try to interpolate the parameters to save extra roundtrips for preparing and closing a statement - prepared, err := mc.interpolateParams(query, args) - if err != nil { - return nil, err - } - query = prepared - } - mc.affectedRows = 0 - mc.insertId = 0 - - err := mc.exec(query) - if err == nil { - return &mysqlResult{ - affectedRows: int64(mc.affectedRows), - insertId: int64(mc.insertId), - }, err - } - return nil, mc.markBadConn(err) -} - -// Internal function to execute commands -func (mc *mysqlConn) exec(query string) error { - // Send command - if err := mc.writeCommandPacketStr(comQuery, query); err != nil { - return mc.markBadConn(err) - } - - // Read Result - resLen, err := mc.readResultSetHeaderPacket() - if err != nil { - return err - } - - if resLen > 0 { - // columns - if err := mc.readUntilEOF(); err != nil { - return err - } - - // rows - if err := mc.readUntilEOF(); err != nil { - return err - } - } - - return mc.discardResults() -} - -func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) { - return mc.query(query, args) -} - -func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) { - if mc.closed.IsSet() { - errLog.Print(ErrInvalidConn) - return nil, driver.ErrBadConn - } - if len(args) != 0 { - if !mc.cfg.InterpolateParams { - return nil, driver.ErrSkip - } - // try client-side prepare to reduce roundtrip - prepared, err := mc.interpolateParams(query, args) - if err != nil { - return nil, err - } - query = prepared - } - // Send command - err := mc.writeCommandPacketStr(comQuery, query) - if err == nil { - // Read Result - var resLen int - resLen, err = mc.readResultSetHeaderPacket() - if err == nil { - rows := new(textRows) - rows.mc = mc - - if resLen == 0 { - rows.rs.done = true - - switch err := rows.NextResultSet(); err { - case nil, io.EOF: - return rows, nil - default: - return nil, err - } - } - - // Columns - rows.rs.columns, err = mc.readColumns(resLen) - return rows, err - } - } - return nil, mc.markBadConn(err) -} - -// Gets the value of the given MySQL System Variable -// The returned byte slice is only valid until the next read -func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) { - // Send command - if err := mc.writeCommandPacketStr(comQuery, "SELECT @@"+name); err != nil { - return nil, err - } - - // Read Result - resLen, err := mc.readResultSetHeaderPacket() - if err == nil { - rows := new(textRows) - rows.mc = mc - rows.rs.columns = []mysqlField{{fieldType: fieldTypeVarChar}} - - if resLen > 0 { - // Columns - if err := mc.readUntilEOF(); err != nil { - return nil, err - } - } - - dest := make([]driver.Value, resLen) - if err = rows.readRow(dest); err == nil { - return dest[0].([]byte), mc.readUntilEOF() - } - } - return nil, err -} - -// finish is called when the query has canceled. -func (mc *mysqlConn) cancel(err error) { - mc.canceled.Set(err) - mc.cleanup() -} - -// finish is called when the query has succeeded. -func (mc *mysqlConn) finish() { - if !mc.watching || mc.finished == nil { - return - } - select { - case mc.finished <- struct{}{}: - mc.watching = false - case <-mc.closech: - } -} - -// Ping implements driver.Pinger interface -func (mc *mysqlConn) Ping(ctx context.Context) (err error) { - if mc.closed.IsSet() { - errLog.Print(ErrInvalidConn) - return driver.ErrBadConn - } - - if err = mc.watchCancel(ctx); err != nil { - return - } - defer mc.finish() - - if err = mc.writeCommandPacket(comPing); err != nil { - return mc.markBadConn(err) - } - - return mc.readResultOK() -} - -// BeginTx implements driver.ConnBeginTx interface -func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { - if mc.closed.IsSet() { - return nil, driver.ErrBadConn - } - - if err := mc.watchCancel(ctx); err != nil { - return nil, err - } - defer mc.finish() - - if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault { - level, err := mapIsolationLevel(opts.Isolation) - if err != nil { - return nil, err - } - err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level) - if err != nil { - return nil, err - } - } - - return mc.begin(opts.ReadOnly) -} - -func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { - dargs, err := namedValueToValue(args) - if err != nil { - return nil, err - } - - if err := mc.watchCancel(ctx); err != nil { - return nil, err - } - - rows, err := mc.query(query, dargs) - if err != nil { - mc.finish() - return nil, err - } - rows.finish = mc.finish - return rows, err -} - -func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { - dargs, err := namedValueToValue(args) - if err != nil { - return nil, err - } - - if err := mc.watchCancel(ctx); err != nil { - return nil, err - } - defer mc.finish() - - return mc.Exec(query, dargs) -} - -func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { - if err := mc.watchCancel(ctx); err != nil { - return nil, err - } - - stmt, err := mc.Prepare(query) - mc.finish() - if err != nil { - return nil, err - } - - select { - default: - case <-ctx.Done(): - stmt.Close() - return nil, ctx.Err() - } - return stmt, nil -} - -func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { - dargs, err := namedValueToValue(args) - if err != nil { - return nil, err - } - - if err := stmt.mc.watchCancel(ctx); err != nil { - return nil, err - } - - rows, err := stmt.query(dargs) - if err != nil { - stmt.mc.finish() - return nil, err - } - rows.finish = stmt.mc.finish - return rows, err -} - -func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { - dargs, err := namedValueToValue(args) - if err != nil { - return nil, err - } - - if err := stmt.mc.watchCancel(ctx); err != nil { - return nil, err - } - defer stmt.mc.finish() - - return stmt.Exec(dargs) -} - -func (mc *mysqlConn) watchCancel(ctx context.Context) error { - if mc.watching { - // Reach here if canceled, - // so the connection is already invalid - mc.cleanup() - return nil - } - // When ctx is already cancelled, don't watch it. - if err := ctx.Err(); err != nil { - return err - } - // When ctx is not cancellable, don't watch it. - if ctx.Done() == nil { - return nil - } - // When watcher is not alive, can't watch it. - if mc.watcher == nil { - return nil - } - - mc.watching = true - mc.watcher <- ctx - return nil -} - -func (mc *mysqlConn) startWatcher() { - watcher := make(chan context.Context, 1) - mc.watcher = watcher - finished := make(chan struct{}) - mc.finished = finished - go func() { - for { - var ctx context.Context - select { - case ctx = <-watcher: - case <-mc.closech: - return - } - - select { - case <-ctx.Done(): - mc.cancel(ctx.Err()) - case <-finished: - case <-mc.closech: - return - } - } - }() -} - -func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) { - nv.Value, err = converter{}.ConvertValue(nv.Value) - return -} - -// ResetSession implements driver.SessionResetter. -// (From Go 1.10) -func (mc *mysqlConn) ResetSession(ctx context.Context) error { - if mc.closed.IsSet() { - return driver.ErrBadConn - } - mc.reset = true - return nil -} - -// IsValid implements driver.Validator interface -// (From Go 1.15) -func (mc *mysqlConn) IsValid() bool { - return !mc.closed.IsSet() -} diff --git a/proxy_go/public/mysql@v1.6.0/connection_test.go b/proxy_go/public/mysql@v1.6.0/connection_test.go deleted file mode 100644 index a6d6773..0000000 --- a/proxy_go/public/mysql@v1.6.0/connection_test.go +++ /dev/null @@ -1,203 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2016 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "context" - "database/sql/driver" - "encoding/json" - "errors" - "net" - "testing" -) - -func TestInterpolateParams(t *testing.T) { - mc := &mysqlConn{ - buf: newBuffer(nil), - maxAllowedPacket: maxPacketSize, - cfg: &Config{ - InterpolateParams: true, - }, - } - - q, err := mc.interpolateParams("SELECT ?+?", []driver.Value{int64(42), "gopher"}) - if err != nil { - t.Errorf("Expected err=nil, got %#v", err) - return - } - expected := `SELECT 42+'gopher'` - if q != expected { - t.Errorf("Expected: %q\nGot: %q", expected, q) - } -} - -func TestInterpolateParamsJSONRawMessage(t *testing.T) { - mc := &mysqlConn{ - buf: newBuffer(nil), - maxAllowedPacket: maxPacketSize, - cfg: &Config{ - InterpolateParams: true, - }, - } - - buf, err := json.Marshal(struct { - Value int `json:"value"` - }{Value: 42}) - if err != nil { - t.Errorf("Expected err=nil, got %#v", err) - return - } - q, err := mc.interpolateParams("SELECT ?", []driver.Value{json.RawMessage(buf)}) - if err != nil { - t.Errorf("Expected err=nil, got %#v", err) - return - } - expected := `SELECT '{\"value\":42}'` - if q != expected { - t.Errorf("Expected: %q\nGot: %q", expected, q) - } -} - -func TestInterpolateParamsTooManyPlaceholders(t *testing.T) { - mc := &mysqlConn{ - buf: newBuffer(nil), - maxAllowedPacket: maxPacketSize, - cfg: &Config{ - InterpolateParams: true, - }, - } - - q, err := mc.interpolateParams("SELECT ?+?", []driver.Value{int64(42)}) - if err != driver.ErrSkip { - t.Errorf("Expected err=driver.ErrSkip, got err=%#v, q=%#v", err, q) - } -} - -// We don't support placeholder in string literal for now. -// https://github.com/go-sql-driver/mysql/pull/490 -func TestInterpolateParamsPlaceholderInString(t *testing.T) { - mc := &mysqlConn{ - buf: newBuffer(nil), - maxAllowedPacket: maxPacketSize, - cfg: &Config{ - InterpolateParams: true, - }, - } - - q, err := mc.interpolateParams("SELECT 'abc?xyz',?", []driver.Value{int64(42)}) - // When InterpolateParams support string literal, this should return `"SELECT 'abc?xyz', 42` - if err != driver.ErrSkip { - t.Errorf("Expected err=driver.ErrSkip, got err=%#v, q=%#v", err, q) - } -} - -func TestInterpolateParamsUint64(t *testing.T) { - mc := &mysqlConn{ - buf: newBuffer(nil), - maxAllowedPacket: maxPacketSize, - cfg: &Config{ - InterpolateParams: true, - }, - } - - q, err := mc.interpolateParams("SELECT ?", []driver.Value{uint64(42)}) - if err != nil { - t.Errorf("Expected err=nil, got err=%#v, q=%#v", err, q) - } - if q != "SELECT 42" { - t.Errorf("Expected uint64 interpolation to work, got q=%#v", q) - } -} - -func TestCheckNamedValue(t *testing.T) { - value := driver.NamedValue{Value: ^uint64(0)} - x := &mysqlConn{} - err := x.CheckNamedValue(&value) - - if err != nil { - t.Fatal("uint64 high-bit not convertible", err) - } - - if value.Value != ^uint64(0) { - t.Fatalf("uint64 high-bit converted, got %#v %T", value.Value, value.Value) - } -} - -// TestCleanCancel tests passed context is cancelled at start. -// No packet should be sent. Connection should keep current status. -func TestCleanCancel(t *testing.T) { - mc := &mysqlConn{ - closech: make(chan struct{}), - } - mc.startWatcher() - defer mc.cleanup() - - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - for i := 0; i < 3; i++ { // Repeat same behavior - err := mc.Ping(ctx) - if err != context.Canceled { - t.Errorf("expected context.Canceled, got %#v", err) - } - - if mc.closed.IsSet() { - t.Error("expected mc is not closed, closed actually") - } - - if mc.watching { - t.Error("expected watching is false, but true") - } - } -} - -func TestPingMarkBadConnection(t *testing.T) { - nc := badConnection{err: errors.New("boom")} - ms := &mysqlConn{ - netConn: nc, - buf: newBuffer(nc), - maxAllowedPacket: defaultMaxAllowedPacket, - } - - err := ms.Ping(context.Background()) - - if err != driver.ErrBadConn { - t.Errorf("expected driver.ErrBadConn, got %#v", err) - } -} - -func TestPingErrInvalidConn(t *testing.T) { - nc := badConnection{err: errors.New("failed to write"), n: 10} - ms := &mysqlConn{ - netConn: nc, - buf: newBuffer(nc), - maxAllowedPacket: defaultMaxAllowedPacket, - closech: make(chan struct{}), - } - - err := ms.Ping(context.Background()) - - if err != ErrInvalidConn { - t.Errorf("expected ErrInvalidConn, got %#v", err) - } -} - -type badConnection struct { - n int - err error - net.Conn -} - -func (bc badConnection) Write(b []byte) (n int, err error) { - return bc.n, bc.err -} - -func (bc badConnection) Close() error { - return nil -} diff --git a/proxy_go/public/mysql@v1.6.0/connector.go b/proxy_go/public/mysql@v1.6.0/connector.go deleted file mode 100644 index d567b4e..0000000 --- a/proxy_go/public/mysql@v1.6.0/connector.go +++ /dev/null @@ -1,146 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2018 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "context" - "database/sql/driver" - "net" -) - -type connector struct { - cfg *Config // immutable private copy. -} - -// Connect implements driver.Connector interface. -// Connect returns a connection to the database. -func (c *connector) Connect(ctx context.Context) (driver.Conn, error) { - var err error - - // New mysqlConn - mc := &mysqlConn{ - maxAllowedPacket: maxPacketSize, - maxWriteSize: maxPacketSize - 1, - closech: make(chan struct{}), - cfg: c.cfg, - } - mc.parseTime = mc.cfg.ParseTime - - // Connect to Server - dialsLock.RLock() - dial, ok := dials[mc.cfg.Net] - dialsLock.RUnlock() - if ok { - dctx := ctx - if mc.cfg.Timeout > 0 { - var cancel context.CancelFunc - dctx, cancel = context.WithTimeout(ctx, c.cfg.Timeout) - defer cancel() - } - mc.netConn, err = dial(dctx, mc.cfg.Addr) - } else { - nd := net.Dialer{Timeout: mc.cfg.Timeout} - mc.netConn, err = nd.DialContext(ctx, mc.cfg.Net, mc.cfg.Addr) - } - - if err != nil { - return nil, err - } - - // Enable TCP Keepalives on TCP connections - if tc, ok := mc.netConn.(*net.TCPConn); ok { - if err := tc.SetKeepAlive(true); err != nil { - // Don't send COM_QUIT before handshake. - mc.netConn.Close() - mc.netConn = nil - return nil, err - } - } - - // Call startWatcher for context support (From Go 1.8) - mc.startWatcher() - if err := mc.watchCancel(ctx); err != nil { - mc.cleanup() - return nil, err - } - defer mc.finish() - - mc.buf = newBuffer(mc.netConn) - - // Set I/O timeouts - mc.buf.timeout = mc.cfg.ReadTimeout - mc.writeTimeout = mc.cfg.WriteTimeout - - // Reading Handshake Initialization Packet - authData, plugin, err := mc.readHandshakePacket() - if err != nil { - mc.cleanup() - return nil, err - } - - if plugin == "" { - plugin = defaultAuthPlugin - } - - // Send Client Authentication Packet - authResp, err := mc.auth(authData, plugin) - if err != nil { - // try the default auth plugin, if using the requested plugin failed - errLog.Print("could not use requested auth plugin '"+plugin+"': ", err.Error()) - plugin = defaultAuthPlugin - authResp, err = mc.auth(authData, plugin) - if err != nil { - mc.cleanup() - return nil, err - } - } - if err = mc.writeHandshakeResponsePacket(authResp, plugin); err != nil { - mc.cleanup() - return nil, err - } - - // Handle response to auth packet, switch methods if possible - if err = mc.handleAuthResult(authData, plugin); err != nil { - // Authentication failed and MySQL has already closed the connection - // (https://dev.mysql.com/doc/internals/en/authentication-fails.html). - // Do not send COM_QUIT, just cleanup and return the error. - mc.cleanup() - return nil, err - } - - if mc.cfg.MaxAllowedPacket > 0 { - mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket - } else { - // Get max allowed packet size - maxap, err := mc.getSystemVar("max_allowed_packet") - if err != nil { - mc.Close() - return nil, err - } - mc.maxAllowedPacket = stringToInt(maxap) - 1 - } - if mc.maxAllowedPacket < maxPacketSize { - mc.maxWriteSize = mc.maxAllowedPacket - } - - // Handle DSN Params - err = mc.handleParams() - if err != nil { - mc.Close() - return nil, err - } - - return mc, nil -} - -// Driver implements driver.Connector interface. -// Driver returns &MySQLDriver{}. -func (c *connector) Driver() driver.Driver { - return &MySQLDriver{} -} diff --git a/proxy_go/public/mysql@v1.6.0/connector_test.go b/proxy_go/public/mysql@v1.6.0/connector_test.go deleted file mode 100644 index 976903c..0000000 --- a/proxy_go/public/mysql@v1.6.0/connector_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package mysql - -import ( - "context" - "net" - "testing" - "time" -) - -func TestConnectorReturnsTimeout(t *testing.T) { - connector := &connector{&Config{ - Net: "tcp", - Addr: "1.1.1.1:1234", - Timeout: 10 * time.Millisecond, - }} - - _, err := connector.Connect(context.Background()) - if err == nil { - t.Fatal("error expected") - } - - if nerr, ok := err.(*net.OpError); ok { - expected := "dial tcp 1.1.1.1:1234: i/o timeout" - if nerr.Error() != expected { - t.Fatalf("expected %q, got %q", expected, nerr.Error()) - } - } else { - t.Fatalf("expected %T, got %T", nerr, err) - } -} diff --git a/proxy_go/public/mysql@v1.6.0/const.go b/proxy_go/public/mysql@v1.6.0/const.go deleted file mode 100644 index b1e6b85..0000000 --- a/proxy_go/public/mysql@v1.6.0/const.go +++ /dev/null @@ -1,174 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -const ( - defaultAuthPlugin = "mysql_native_password" - defaultMaxAllowedPacket = 4 << 20 // 4 MiB - minProtocolVersion = 10 - maxPacketSize = 1<<24 - 1 - timeFormat = "2006-01-02 15:04:05.999999" -) - -// MySQL constants documentation: -// http://dev.mysql.com/doc/internals/en/client-server-protocol.html - -const ( - iOK byte = 0x00 - iAuthMoreData byte = 0x01 - iLocalInFile byte = 0xfb - iEOF byte = 0xfe - iERR byte = 0xff -) - -// https://dev.mysql.com/doc/internals/en/capability-flags.html#packet-Protocol::CapabilityFlags -type clientFlag uint32 - -const ( - clientLongPassword clientFlag = 1 << iota - clientFoundRows - clientLongFlag - clientConnectWithDB - clientNoSchema - clientCompress - clientODBC - clientLocalFiles - clientIgnoreSpace - clientProtocol41 - clientInteractive - clientSSL - clientIgnoreSIGPIPE - clientTransactions - clientReserved - clientSecureConn - clientMultiStatements - clientMultiResults - clientPSMultiResults - clientPluginAuth - clientConnectAttrs - clientPluginAuthLenEncClientData - clientCanHandleExpiredPasswords - clientSessionTrack - clientDeprecateEOF -) - -const ( - comQuit byte = iota + 1 - comInitDB - comQuery - comFieldList - comCreateDB - comDropDB - comRefresh - comShutdown - comStatistics - comProcessInfo - comConnect - comProcessKill - comDebug - comPing - comTime - comDelayedInsert - comChangeUser - comBinlogDump - comTableDump - comConnectOut - comRegisterSlave - comStmtPrepare - comStmtExecute - comStmtSendLongData - comStmtClose - comStmtReset - comSetOption - comStmtFetch -) - -// https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnType -type fieldType byte - -const ( - fieldTypeDecimal fieldType = iota - fieldTypeTiny - fieldTypeShort - fieldTypeLong - fieldTypeFloat - fieldTypeDouble - fieldTypeNULL - fieldTypeTimestamp - fieldTypeLongLong - fieldTypeInt24 - fieldTypeDate - fieldTypeTime - fieldTypeDateTime - fieldTypeYear - fieldTypeNewDate - fieldTypeVarChar - fieldTypeBit -) -const ( - fieldTypeJSON fieldType = iota + 0xf5 - fieldTypeNewDecimal - fieldTypeEnum - fieldTypeSet - fieldTypeTinyBLOB - fieldTypeMediumBLOB - fieldTypeLongBLOB - fieldTypeBLOB - fieldTypeVarString - fieldTypeString - fieldTypeGeometry -) - -type fieldFlag uint16 - -const ( - flagNotNULL fieldFlag = 1 << iota - flagPriKey - flagUniqueKey - flagMultipleKey - flagBLOB - flagUnsigned - flagZeroFill - flagBinary - flagEnum - flagAutoIncrement - flagTimestamp - flagSet - flagUnknown1 - flagUnknown2 - flagUnknown3 - flagUnknown4 -) - -// http://dev.mysql.com/doc/internals/en/status-flags.html -type statusFlag uint16 - -const ( - statusInTrans statusFlag = 1 << iota - statusInAutocommit - statusReserved // Not in documentation - statusMoreResultsExists - statusNoGoodIndexUsed - statusNoIndexUsed - statusCursorExists - statusLastRowSent - statusDbDropped - statusNoBackslashEscapes - statusMetadataChanged - statusQueryWasSlow - statusPsOutParams - statusInTransReadonly - statusSessionStateChanged -) - -const ( - cachingSha2PasswordRequestPublicKey = 2 - cachingSha2PasswordFastAuthSuccess = 3 - cachingSha2PasswordPerformFullAuthentication = 4 -) diff --git a/proxy_go/public/mysql@v1.6.0/driver.go b/proxy_go/public/mysql@v1.6.0/driver.go deleted file mode 100644 index c1bdf11..0000000 --- a/proxy_go/public/mysql@v1.6.0/driver.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -// Package mysql provides a MySQL driver for Go's database/sql package. -// -// The driver should be used via the database/sql package: -// -// import "database/sql" -// import _ "github.com/go-sql-driver/mysql" -// -// db, err := sql.Open("mysql", "user:password@/dbname") -// -// See https://github.com/go-sql-driver/mysql#usage for details -package mysql - -import ( - "context" - "database/sql" - "database/sql/driver" - "net" - "sync" -) - -// MySQLDriver is exported to make the driver directly accessible. -// In general the driver is used via the database/sql package. -type MySQLDriver struct{} - -// DialFunc is a function which can be used to establish the network connection. -// Custom dial functions must be registered with RegisterDial -// -// Deprecated: users should register a DialContextFunc instead -type DialFunc func(addr string) (net.Conn, error) - -// DialContextFunc is a function which can be used to establish the network connection. -// Custom dial functions must be registered with RegisterDialContext -type DialContextFunc func(ctx context.Context, addr string) (net.Conn, error) - -var ( - dialsLock sync.RWMutex - dials map[string]DialContextFunc -) - -// RegisterDialContext registers a custom dial function. It can then be used by the -// network address mynet(addr), where mynet is the registered new network. -// The current context for the connection and its address is passed to the dial function. -func RegisterDialContext(net string, dial DialContextFunc) { - dialsLock.Lock() - defer dialsLock.Unlock() - if dials == nil { - dials = make(map[string]DialContextFunc) - } - dials[net] = dial -} - -// RegisterDial registers a custom dial function. It can then be used by the -// network address mynet(addr), where mynet is the registered new network. -// addr is passed as a parameter to the dial function. -// -// Deprecated: users should call RegisterDialContext instead -func RegisterDial(network string, dial DialFunc) { - RegisterDialContext(network, func(_ context.Context, addr string) (net.Conn, error) { - return dial(addr) - }) -} - -// Open new Connection. -// See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how -// the DSN string is formatted -func (d MySQLDriver) Open(dsn string) (driver.Conn, error) { - cfg, err := ParseDSN(dsn) - if err != nil { - return nil, err - } - c := &connector{ - cfg: cfg, - } - return c.Connect(context.Background()) -} - -func init() { - sql.Register("mysql", &MySQLDriver{}) -} - -// NewConnector returns new driver.Connector. -func NewConnector(cfg *Config) (driver.Connector, error) { - cfg = cfg.Clone() - // normalize the contents of cfg so calls to NewConnector have the same - // behavior as MySQLDriver.OpenConnector - if err := cfg.normalize(); err != nil { - return nil, err - } - return &connector{cfg: cfg}, nil -} - -// OpenConnector implements driver.DriverContext. -func (d MySQLDriver) OpenConnector(dsn string) (driver.Connector, error) { - cfg, err := ParseDSN(dsn) - if err != nil { - return nil, err - } - return &connector{ - cfg: cfg, - }, nil -} diff --git a/proxy_go/public/mysql@v1.6.0/driver_test.go b/proxy_go/public/mysql@v1.6.0/driver_test.go deleted file mode 100644 index 54f7cd1..0000000 --- a/proxy_go/public/mysql@v1.6.0/driver_test.go +++ /dev/null @@ -1,3211 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "bytes" - "context" - "crypto/tls" - "database/sql" - "database/sql/driver" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "log" - "math" - "net" - "net/url" - "os" - "reflect" - "runtime" - "strings" - "sync" - "sync/atomic" - "testing" - "time" -) - -// Ensure that all the driver interfaces are implemented -var ( - _ driver.Rows = &binaryRows{} - _ driver.Rows = &textRows{} -) - -var ( - user string - pass string - prot string - addr string - dbname string - dsn string - netAddr string - available bool -) - -var ( - tDate = time.Date(2012, 6, 14, 0, 0, 0, 0, time.UTC) - sDate = "2012-06-14" - tDateTime = time.Date(2011, 11, 20, 21, 27, 37, 0, time.UTC) - sDateTime = "2011-11-20 21:27:37" - tDate0 = time.Time{} - sDate0 = "0000-00-00" - sDateTime0 = "0000-00-00 00:00:00" -) - -// See https://github.com/go-sql-driver/mysql/wiki/Testing -func init() { - // get environment variables - env := func(key, defaultValue string) string { - if value := os.Getenv(key); value != "" { - return value - } - return defaultValue - } - user = env("MYSQL_TEST_USER", "root") - pass = env("MYSQL_TEST_PASS", "") - prot = env("MYSQL_TEST_PROT", "tcp") - addr = env("MYSQL_TEST_ADDR", "localhost:3306") - dbname = env("MYSQL_TEST_DBNAME", "gotest") - netAddr = fmt.Sprintf("%s(%s)", prot, addr) - dsn = fmt.Sprintf("%s:%s@%s/%s?timeout=30s", user, pass, netAddr, dbname) - c, err := net.Dial(prot, addr) - if err == nil { - available = true - c.Close() - } -} - -type DBTest struct { - *testing.T - db *sql.DB -} - -type netErrorMock struct { - temporary bool - timeout bool -} - -func (e netErrorMock) Temporary() bool { - return e.temporary -} - -func (e netErrorMock) Timeout() bool { - return e.timeout -} - -func (e netErrorMock) Error() string { - return fmt.Sprintf("mock net error. Temporary: %v, Timeout %v", e.temporary, e.timeout) -} - -func runTestsWithMultiStatement(t *testing.T, dsn string, tests ...func(dbt *DBTest)) { - if !available { - t.Skipf("MySQL server not running on %s", netAddr) - } - - dsn += "&multiStatements=true" - var db *sql.DB - if _, err := ParseDSN(dsn); err != errInvalidDSNUnsafeCollation { - db, err = sql.Open("mysql", dsn) - if err != nil { - t.Fatalf("error connecting: %s", err.Error()) - } - defer db.Close() - } - - dbt := &DBTest{t, db} - for _, test := range tests { - test(dbt) - dbt.db.Exec("DROP TABLE IF EXISTS test") - } -} - -func runTests(t *testing.T, dsn string, tests ...func(dbt *DBTest)) { - if !available { - t.Skipf("MySQL server not running on %s", netAddr) - } - - db, err := sql.Open("mysql", dsn) - if err != nil { - t.Fatalf("error connecting: %s", err.Error()) - } - defer db.Close() - - db.Exec("DROP TABLE IF EXISTS test") - - dsn2 := dsn + "&interpolateParams=true" - var db2 *sql.DB - if _, err := ParseDSN(dsn2); err != errInvalidDSNUnsafeCollation { - db2, err = sql.Open("mysql", dsn2) - if err != nil { - t.Fatalf("error connecting: %s", err.Error()) - } - defer db2.Close() - } - - dsn3 := dsn + "&multiStatements=true" - var db3 *sql.DB - if _, err := ParseDSN(dsn3); err != errInvalidDSNUnsafeCollation { - db3, err = sql.Open("mysql", dsn3) - if err != nil { - t.Fatalf("error connecting: %s", err.Error()) - } - defer db3.Close() - } - - dbt := &DBTest{t, db} - dbt2 := &DBTest{t, db2} - dbt3 := &DBTest{t, db3} - for _, test := range tests { - test(dbt) - dbt.db.Exec("DROP TABLE IF EXISTS test") - if db2 != nil { - test(dbt2) - dbt2.db.Exec("DROP TABLE IF EXISTS test") - } - if db3 != nil { - test(dbt3) - dbt3.db.Exec("DROP TABLE IF EXISTS test") - } - } -} - -func (dbt *DBTest) fail(method, query string, err error) { - if len(query) > 300 { - query = "[query too large to print]" - } - dbt.Fatalf("error on %s %s: %s", method, query, err.Error()) -} - -func (dbt *DBTest) mustExec(query string, args ...interface{}) (res sql.Result) { - res, err := dbt.db.Exec(query, args...) - if err != nil { - dbt.fail("exec", query, err) - } - return res -} - -func (dbt *DBTest) mustQuery(query string, args ...interface{}) (rows *sql.Rows) { - rows, err := dbt.db.Query(query, args...) - if err != nil { - dbt.fail("query", query, err) - } - return rows -} - -func maybeSkip(t *testing.T, err error, skipErrno uint16) { - mySQLErr, ok := err.(*MySQLError) - if !ok { - return - } - - if mySQLErr.Number == skipErrno { - t.Skipf("skipping test for error: %v", err) - } -} - -func TestEmptyQuery(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - // just a comment, no query - rows := dbt.mustQuery("--") - defer rows.Close() - // will hang before #255 - if rows.Next() { - dbt.Errorf("next on rows must be false") - } - }) -} - -func TestCRUD(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - // Create Table - dbt.mustExec("CREATE TABLE test (value BOOL)") - - // Test for unexpected data - var out bool - rows := dbt.mustQuery("SELECT * FROM test") - if rows.Next() { - dbt.Error("unexpected data in empty table") - } - rows.Close() - - // Create Data - res := dbt.mustExec("INSERT INTO test VALUES (1)") - count, err := res.RowsAffected() - if err != nil { - dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) - } - if count != 1 { - dbt.Fatalf("expected 1 affected row, got %d", count) - } - - id, err := res.LastInsertId() - if err != nil { - dbt.Fatalf("res.LastInsertId() returned error: %s", err.Error()) - } - if id != 0 { - dbt.Fatalf("expected InsertId 0, got %d", id) - } - - // Read - rows = dbt.mustQuery("SELECT value FROM test") - if rows.Next() { - rows.Scan(&out) - if true != out { - dbt.Errorf("true != %t", out) - } - - if rows.Next() { - dbt.Error("unexpected data") - } - } else { - dbt.Error("no data") - } - rows.Close() - - // Update - res = dbt.mustExec("UPDATE test SET value = ? WHERE value = ?", false, true) - count, err = res.RowsAffected() - if err != nil { - dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) - } - if count != 1 { - dbt.Fatalf("expected 1 affected row, got %d", count) - } - - // Check Update - rows = dbt.mustQuery("SELECT value FROM test") - if rows.Next() { - rows.Scan(&out) - if false != out { - dbt.Errorf("false != %t", out) - } - - if rows.Next() { - dbt.Error("unexpected data") - } - } else { - dbt.Error("no data") - } - rows.Close() - - // Delete - res = dbt.mustExec("DELETE FROM test WHERE value = ?", false) - count, err = res.RowsAffected() - if err != nil { - dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) - } - if count != 1 { - dbt.Fatalf("expected 1 affected row, got %d", count) - } - - // Check for unexpected rows - res = dbt.mustExec("DELETE FROM test") - count, err = res.RowsAffected() - if err != nil { - dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) - } - if count != 0 { - dbt.Fatalf("expected 0 affected row, got %d", count) - } - }) -} - -func TestMultiQuery(t *testing.T) { - runTestsWithMultiStatement(t, dsn, func(dbt *DBTest) { - // Create Table - dbt.mustExec("CREATE TABLE `test` (`id` int(11) NOT NULL, `value` int(11) NOT NULL) ") - - // Create Data - res := dbt.mustExec("INSERT INTO test VALUES (1, 1)") - count, err := res.RowsAffected() - if err != nil { - dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) - } - if count != 1 { - dbt.Fatalf("expected 1 affected row, got %d", count) - } - - // Update - res = dbt.mustExec("UPDATE test SET value = 3 WHERE id = 1; UPDATE test SET value = 4 WHERE id = 1; UPDATE test SET value = 5 WHERE id = 1;") - count, err = res.RowsAffected() - if err != nil { - dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) - } - if count != 1 { - dbt.Fatalf("expected 1 affected row, got %d", count) - } - - // Read - var out int - rows := dbt.mustQuery("SELECT value FROM test WHERE id=1;") - if rows.Next() { - rows.Scan(&out) - if 5 != out { - dbt.Errorf("5 != %d", out) - } - - if rows.Next() { - dbt.Error("unexpected data") - } - } else { - dbt.Error("no data") - } - rows.Close() - - }) -} - -func TestInt(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - types := [5]string{"TINYINT", "SMALLINT", "MEDIUMINT", "INT", "BIGINT"} - in := int64(42) - var out int64 - var rows *sql.Rows - - // SIGNED - for _, v := range types { - dbt.mustExec("CREATE TABLE test (value " + v + ")") - - dbt.mustExec("INSERT INTO test VALUES (?)", in) - - rows = dbt.mustQuery("SELECT value FROM test") - if rows.Next() { - rows.Scan(&out) - if in != out { - dbt.Errorf("%s: %d != %d", v, in, out) - } - } else { - dbt.Errorf("%s: no data", v) - } - rows.Close() - - dbt.mustExec("DROP TABLE IF EXISTS test") - } - - // UNSIGNED ZEROFILL - for _, v := range types { - dbt.mustExec("CREATE TABLE test (value " + v + " ZEROFILL)") - - dbt.mustExec("INSERT INTO test VALUES (?)", in) - - rows = dbt.mustQuery("SELECT value FROM test") - if rows.Next() { - rows.Scan(&out) - if in != out { - dbt.Errorf("%s ZEROFILL: %d != %d", v, in, out) - } - } else { - dbt.Errorf("%s ZEROFILL: no data", v) - } - rows.Close() - - dbt.mustExec("DROP TABLE IF EXISTS test") - } - }) -} - -func TestFloat32(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - types := [2]string{"FLOAT", "DOUBLE"} - in := float32(42.23) - var out float32 - var rows *sql.Rows - for _, v := range types { - dbt.mustExec("CREATE TABLE test (value " + v + ")") - dbt.mustExec("INSERT INTO test VALUES (?)", in) - rows = dbt.mustQuery("SELECT value FROM test") - if rows.Next() { - rows.Scan(&out) - if in != out { - dbt.Errorf("%s: %g != %g", v, in, out) - } - } else { - dbt.Errorf("%s: no data", v) - } - rows.Close() - dbt.mustExec("DROP TABLE IF EXISTS test") - } - }) -} - -func TestFloat64(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - types := [2]string{"FLOAT", "DOUBLE"} - var expected float64 = 42.23 - var out float64 - var rows *sql.Rows - for _, v := range types { - dbt.mustExec("CREATE TABLE test (value " + v + ")") - dbt.mustExec("INSERT INTO test VALUES (42.23)") - rows = dbt.mustQuery("SELECT value FROM test") - if rows.Next() { - rows.Scan(&out) - if expected != out { - dbt.Errorf("%s: %g != %g", v, expected, out) - } - } else { - dbt.Errorf("%s: no data", v) - } - rows.Close() - dbt.mustExec("DROP TABLE IF EXISTS test") - } - }) -} - -func TestFloat64Placeholder(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - types := [2]string{"FLOAT", "DOUBLE"} - var expected float64 = 42.23 - var out float64 - var rows *sql.Rows - for _, v := range types { - dbt.mustExec("CREATE TABLE test (id int, value " + v + ")") - dbt.mustExec("INSERT INTO test VALUES (1, 42.23)") - rows = dbt.mustQuery("SELECT value FROM test WHERE id = ?", 1) - if rows.Next() { - rows.Scan(&out) - if expected != out { - dbt.Errorf("%s: %g != %g", v, expected, out) - } - } else { - dbt.Errorf("%s: no data", v) - } - rows.Close() - dbt.mustExec("DROP TABLE IF EXISTS test") - } - }) -} - -func TestString(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - types := [6]string{"CHAR(255)", "VARCHAR(255)", "TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT"} - in := "κόσμε üöäßñóùéàâÿœ'îë Árvíztűrő いろはにほへとちりぬるを イロハニホヘト דג סקרן чащах น่าฟังเอย" - var out string - var rows *sql.Rows - - for _, v := range types { - dbt.mustExec("CREATE TABLE test (value " + v + ") CHARACTER SET utf8") - - dbt.mustExec("INSERT INTO test VALUES (?)", in) - - rows = dbt.mustQuery("SELECT value FROM test") - if rows.Next() { - rows.Scan(&out) - if in != out { - dbt.Errorf("%s: %s != %s", v, in, out) - } - } else { - dbt.Errorf("%s: no data", v) - } - rows.Close() - - dbt.mustExec("DROP TABLE IF EXISTS test") - } - - // BLOB - dbt.mustExec("CREATE TABLE test (id int, value BLOB) CHARACTER SET utf8") - - id := 2 - in = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, " + - "sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, " + - "sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. " + - "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. " + - "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, " + - "sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, " + - "sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. " + - "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." - dbt.mustExec("INSERT INTO test VALUES (?, ?)", id, in) - - err := dbt.db.QueryRow("SELECT value FROM test WHERE id = ?", id).Scan(&out) - if err != nil { - dbt.Fatalf("Error on BLOB-Query: %s", err.Error()) - } else if out != in { - dbt.Errorf("BLOB: %s != %s", in, out) - } - }) -} - -func TestRawBytes(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - v1 := []byte("aaa") - v2 := []byte("bbb") - rows := dbt.mustQuery("SELECT ?, ?", v1, v2) - defer rows.Close() - if rows.Next() { - var o1, o2 sql.RawBytes - if err := rows.Scan(&o1, &o2); err != nil { - dbt.Errorf("Got error: %v", err) - } - if !bytes.Equal(v1, o1) { - dbt.Errorf("expected %v, got %v", v1, o1) - } - if !bytes.Equal(v2, o2) { - dbt.Errorf("expected %v, got %v", v2, o2) - } - // https://github.com/go-sql-driver/mysql/issues/765 - // Appending to RawBytes shouldn't overwrite next RawBytes. - o1 = append(o1, "xyzzy"...) - if !bytes.Equal(v2, o2) { - dbt.Errorf("expected %v, got %v", v2, o2) - } - } else { - dbt.Errorf("no data") - } - }) -} - -func TestRawMessage(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - v1 := json.RawMessage("{}") - v2 := json.RawMessage("[]") - rows := dbt.mustQuery("SELECT ?, ?", v1, v2) - defer rows.Close() - if rows.Next() { - var o1, o2 json.RawMessage - if err := rows.Scan(&o1, &o2); err != nil { - dbt.Errorf("Got error: %v", err) - } - if !bytes.Equal(v1, o1) { - dbt.Errorf("expected %v, got %v", v1, o1) - } - if !bytes.Equal(v2, o2) { - dbt.Errorf("expected %v, got %v", v2, o2) - } - } else { - dbt.Errorf("no data") - } - }) -} - -type testValuer struct { - value string -} - -func (tv testValuer) Value() (driver.Value, error) { - return tv.value, nil -} - -func TestValuer(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - in := testValuer{"a_value"} - var out string - var rows *sql.Rows - - dbt.mustExec("CREATE TABLE test (value VARCHAR(255)) CHARACTER SET utf8") - dbt.mustExec("INSERT INTO test VALUES (?)", in) - rows = dbt.mustQuery("SELECT value FROM test") - if rows.Next() { - rows.Scan(&out) - if in.value != out { - dbt.Errorf("Valuer: %v != %s", in, out) - } - } else { - dbt.Errorf("Valuer: no data") - } - rows.Close() - - dbt.mustExec("DROP TABLE IF EXISTS test") - }) -} - -type testValuerWithValidation struct { - value string -} - -func (tv testValuerWithValidation) Value() (driver.Value, error) { - if len(tv.value) == 0 { - return nil, fmt.Errorf("Invalid string valuer. Value must not be empty") - } - - return tv.value, nil -} - -func TestValuerWithValidation(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - in := testValuerWithValidation{"a_value"} - var out string - var rows *sql.Rows - - dbt.mustExec("CREATE TABLE testValuer (value VARCHAR(255)) CHARACTER SET utf8") - dbt.mustExec("INSERT INTO testValuer VALUES (?)", in) - - rows = dbt.mustQuery("SELECT value FROM testValuer") - defer rows.Close() - - if rows.Next() { - rows.Scan(&out) - if in.value != out { - dbt.Errorf("Valuer: %v != %s", in, out) - } - } else { - dbt.Errorf("Valuer: no data") - } - - if _, err := dbt.db.Exec("INSERT INTO testValuer VALUES (?)", testValuerWithValidation{""}); err == nil { - dbt.Errorf("Failed to check valuer error") - } - - if _, err := dbt.db.Exec("INSERT INTO testValuer VALUES (?)", nil); err != nil { - dbt.Errorf("Failed to check nil") - } - - if _, err := dbt.db.Exec("INSERT INTO testValuer VALUES (?)", map[string]bool{}); err == nil { - dbt.Errorf("Failed to check not valuer") - } - - dbt.mustExec("DROP TABLE IF EXISTS testValuer") - }) -} - -type timeTests struct { - dbtype string - tlayout string - tests []timeTest -} - -type timeTest struct { - s string // leading "!": do not use t as value in queries - t time.Time -} - -type timeMode byte - -func (t timeMode) String() string { - switch t { - case binaryString: - return "binary:string" - case binaryTime: - return "binary:time.Time" - case textString: - return "text:string" - } - panic("unsupported timeMode") -} - -func (t timeMode) Binary() bool { - switch t { - case binaryString, binaryTime: - return true - } - return false -} - -const ( - binaryString timeMode = iota - binaryTime - textString -) - -func (t timeTest) genQuery(dbtype string, mode timeMode) string { - var inner string - if mode.Binary() { - inner = "?" - } else { - inner = `"%s"` - } - return `SELECT cast(` + inner + ` as ` + dbtype + `)` -} - -func (t timeTest) run(dbt *DBTest, dbtype, tlayout string, mode timeMode) { - var rows *sql.Rows - query := t.genQuery(dbtype, mode) - switch mode { - case binaryString: - rows = dbt.mustQuery(query, t.s) - case binaryTime: - rows = dbt.mustQuery(query, t.t) - case textString: - query = fmt.Sprintf(query, t.s) - rows = dbt.mustQuery(query) - default: - panic("unsupported mode") - } - defer rows.Close() - var err error - if !rows.Next() { - err = rows.Err() - if err == nil { - err = fmt.Errorf("no data") - } - dbt.Errorf("%s [%s]: %s", dbtype, mode, err) - return - } - var dst interface{} - err = rows.Scan(&dst) - if err != nil { - dbt.Errorf("%s [%s]: %s", dbtype, mode, err) - return - } - switch val := dst.(type) { - case []uint8: - str := string(val) - if str == t.s { - return - } - if mode.Binary() && dbtype == "DATETIME" && len(str) == 26 && str[:19] == t.s { - // a fix mainly for TravisCI: - // accept full microsecond resolution in result for DATETIME columns - // where the binary protocol was used - return - } - dbt.Errorf("%s [%s] to string: expected %q, got %q", - dbtype, mode, - t.s, str, - ) - case time.Time: - if val == t.t { - return - } - dbt.Errorf("%s [%s] to string: expected %q, got %q", - dbtype, mode, - t.s, val.Format(tlayout), - ) - default: - fmt.Printf("%#v\n", []interface{}{dbtype, tlayout, mode, t.s, t.t}) - dbt.Errorf("%s [%s]: unhandled type %T (is '%v')", - dbtype, mode, - val, val, - ) - } -} - -func TestDateTime(t *testing.T) { - afterTime := func(t time.Time, d string) time.Time { - dur, err := time.ParseDuration(d) - if err != nil { - panic(err) - } - return t.Add(dur) - } - // NOTE: MySQL rounds DATETIME(x) up - but that's not included in the tests - format := "2006-01-02 15:04:05.999999" - t0 := time.Time{} - tstr0 := "0000-00-00 00:00:00.000000" - testcases := []timeTests{ - {"DATE", format[:10], []timeTest{ - {t: time.Date(2011, 11, 20, 0, 0, 0, 0, time.UTC)}, - {t: t0, s: tstr0[:10]}, - }}, - {"DATETIME", format[:19], []timeTest{ - {t: time.Date(2011, 11, 20, 21, 27, 37, 0, time.UTC)}, - {t: t0, s: tstr0[:19]}, - }}, - {"DATETIME(0)", format[:21], []timeTest{ - {t: time.Date(2011, 11, 20, 21, 27, 37, 0, time.UTC)}, - {t: t0, s: tstr0[:19]}, - }}, - {"DATETIME(1)", format[:21], []timeTest{ - {t: time.Date(2011, 11, 20, 21, 27, 37, 100000000, time.UTC)}, - {t: t0, s: tstr0[:21]}, - }}, - {"DATETIME(6)", format, []timeTest{ - {t: time.Date(2011, 11, 20, 21, 27, 37, 123456000, time.UTC)}, - {t: t0, s: tstr0}, - }}, - {"TIME", format[11:19], []timeTest{ - {t: afterTime(t0, "12345s")}, - {s: "!-12:34:56"}, - {s: "!-838:59:59"}, - {s: "!838:59:59"}, - {t: t0, s: tstr0[11:19]}, - }}, - {"TIME(0)", format[11:19], []timeTest{ - {t: afterTime(t0, "12345s")}, - {s: "!-12:34:56"}, - {s: "!-838:59:59"}, - {s: "!838:59:59"}, - {t: t0, s: tstr0[11:19]}, - }}, - {"TIME(1)", format[11:21], []timeTest{ - {t: afterTime(t0, "12345600ms")}, - {s: "!-12:34:56.7"}, - {s: "!-838:59:58.9"}, - {s: "!838:59:58.9"}, - {t: t0, s: tstr0[11:21]}, - }}, - {"TIME(6)", format[11:], []timeTest{ - {t: afterTime(t0, "1234567890123000ns")}, - {s: "!-12:34:56.789012"}, - {s: "!-838:59:58.999999"}, - {s: "!838:59:58.999999"}, - {t: t0, s: tstr0[11:]}, - }}, - } - dsns := []string{ - dsn + "&parseTime=true", - dsn + "&parseTime=false", - } - for _, testdsn := range dsns { - runTests(t, testdsn, func(dbt *DBTest) { - microsecsSupported := false - zeroDateSupported := false - var rows *sql.Rows - var err error - rows, err = dbt.db.Query(`SELECT cast("00:00:00.1" as TIME(1)) = "00:00:00.1"`) - if err == nil { - rows.Scan(µsecsSupported) - rows.Close() - } - rows, err = dbt.db.Query(`SELECT cast("0000-00-00" as DATE) = "0000-00-00"`) - if err == nil { - rows.Scan(&zeroDateSupported) - rows.Close() - } - for _, setups := range testcases { - if t := setups.dbtype; !microsecsSupported && t[len(t)-1:] == ")" { - // skip fractional second tests if unsupported by server - continue - } - for _, setup := range setups.tests { - allowBinTime := true - if setup.s == "" { - // fill time string wherever Go can reliable produce it - setup.s = setup.t.Format(setups.tlayout) - } else if setup.s[0] == '!' { - // skip tests using setup.t as source in queries - allowBinTime = false - // fix setup.s - remove the "!" - setup.s = setup.s[1:] - } - if !zeroDateSupported && setup.s == tstr0[:len(setup.s)] { - // skip disallowed 0000-00-00 date - continue - } - setup.run(dbt, setups.dbtype, setups.tlayout, textString) - setup.run(dbt, setups.dbtype, setups.tlayout, binaryString) - if allowBinTime { - setup.run(dbt, setups.dbtype, setups.tlayout, binaryTime) - } - } - } - }) - } -} - -func TestTimestampMicros(t *testing.T) { - format := "2006-01-02 15:04:05.999999" - f0 := format[:19] - f1 := format[:21] - f6 := format[:26] - runTests(t, dsn, func(dbt *DBTest) { - // check if microseconds are supported. - // Do not use timestamp(x) for that check - before 5.5.6, x would mean display width - // and not precision. - // Se last paragraph at http://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html - microsecsSupported := false - if rows, err := dbt.db.Query(`SELECT cast("00:00:00.1" as TIME(1)) = "00:00:00.1"`); err == nil { - rows.Scan(µsecsSupported) - rows.Close() - } - if !microsecsSupported { - // skip test - return - } - _, err := dbt.db.Exec(` - CREATE TABLE test ( - value0 TIMESTAMP NOT NULL DEFAULT '` + f0 + `', - value1 TIMESTAMP(1) NOT NULL DEFAULT '` + f1 + `', - value6 TIMESTAMP(6) NOT NULL DEFAULT '` + f6 + `' - )`, - ) - if err != nil { - dbt.Error(err) - } - defer dbt.mustExec("DROP TABLE IF EXISTS test") - dbt.mustExec("INSERT INTO test SET value0=?, value1=?, value6=?", f0, f1, f6) - var res0, res1, res6 string - rows := dbt.mustQuery("SELECT * FROM test") - defer rows.Close() - if !rows.Next() { - dbt.Errorf("test contained no selectable values") - } - err = rows.Scan(&res0, &res1, &res6) - if err != nil { - dbt.Error(err) - } - if res0 != f0 { - dbt.Errorf("expected %q, got %q", f0, res0) - } - if res1 != f1 { - dbt.Errorf("expected %q, got %q", f1, res1) - } - if res6 != f6 { - dbt.Errorf("expected %q, got %q", f6, res6) - } - }) -} - -func TestNULL(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - nullStmt, err := dbt.db.Prepare("SELECT NULL") - if err != nil { - dbt.Fatal(err) - } - defer nullStmt.Close() - - nonNullStmt, err := dbt.db.Prepare("SELECT 1") - if err != nil { - dbt.Fatal(err) - } - defer nonNullStmt.Close() - - // NullBool - var nb sql.NullBool - // Invalid - if err = nullStmt.QueryRow().Scan(&nb); err != nil { - dbt.Fatal(err) - } - if nb.Valid { - dbt.Error("valid NullBool which should be invalid") - } - // Valid - if err = nonNullStmt.QueryRow().Scan(&nb); err != nil { - dbt.Fatal(err) - } - if !nb.Valid { - dbt.Error("invalid NullBool which should be valid") - } else if nb.Bool != true { - dbt.Errorf("Unexpected NullBool value: %t (should be true)", nb.Bool) - } - - // NullFloat64 - var nf sql.NullFloat64 - // Invalid - if err = nullStmt.QueryRow().Scan(&nf); err != nil { - dbt.Fatal(err) - } - if nf.Valid { - dbt.Error("valid NullFloat64 which should be invalid") - } - // Valid - if err = nonNullStmt.QueryRow().Scan(&nf); err != nil { - dbt.Fatal(err) - } - if !nf.Valid { - dbt.Error("invalid NullFloat64 which should be valid") - } else if nf.Float64 != float64(1) { - dbt.Errorf("unexpected NullFloat64 value: %f (should be 1.0)", nf.Float64) - } - - // NullInt64 - var ni sql.NullInt64 - // Invalid - if err = nullStmt.QueryRow().Scan(&ni); err != nil { - dbt.Fatal(err) - } - if ni.Valid { - dbt.Error("valid NullInt64 which should be invalid") - } - // Valid - if err = nonNullStmt.QueryRow().Scan(&ni); err != nil { - dbt.Fatal(err) - } - if !ni.Valid { - dbt.Error("invalid NullInt64 which should be valid") - } else if ni.Int64 != int64(1) { - dbt.Errorf("unexpected NullInt64 value: %d (should be 1)", ni.Int64) - } - - // NullString - var ns sql.NullString - // Invalid - if err = nullStmt.QueryRow().Scan(&ns); err != nil { - dbt.Fatal(err) - } - if ns.Valid { - dbt.Error("valid NullString which should be invalid") - } - // Valid - if err = nonNullStmt.QueryRow().Scan(&ns); err != nil { - dbt.Fatal(err) - } - if !ns.Valid { - dbt.Error("invalid NullString which should be valid") - } else if ns.String != `1` { - dbt.Error("unexpected NullString value:" + ns.String + " (should be `1`)") - } - - // nil-bytes - var b []byte - // Read nil - if err = nullStmt.QueryRow().Scan(&b); err != nil { - dbt.Fatal(err) - } - if b != nil { - dbt.Error("non-nil []byte which should be nil") - } - // Read non-nil - if err = nonNullStmt.QueryRow().Scan(&b); err != nil { - dbt.Fatal(err) - } - if b == nil { - dbt.Error("nil []byte which should be non-nil") - } - // Insert nil - b = nil - success := false - if err = dbt.db.QueryRow("SELECT ? IS NULL", b).Scan(&success); err != nil { - dbt.Fatal(err) - } - if !success { - dbt.Error("inserting []byte(nil) as NULL failed") - } - // Check input==output with input==nil - b = nil - if err = dbt.db.QueryRow("SELECT ?", b).Scan(&b); err != nil { - dbt.Fatal(err) - } - if b != nil { - dbt.Error("non-nil echo from nil input") - } - // Check input==output with input!=nil - b = []byte("") - if err = dbt.db.QueryRow("SELECT ?", b).Scan(&b); err != nil { - dbt.Fatal(err) - } - if b == nil { - dbt.Error("nil echo from non-nil input") - } - - // Insert NULL - dbt.mustExec("CREATE TABLE test (dummmy1 int, value int, dummy2 int)") - - dbt.mustExec("INSERT INTO test VALUES (?, ?, ?)", 1, nil, 2) - - var out interface{} - rows := dbt.mustQuery("SELECT * FROM test") - defer rows.Close() - if rows.Next() { - rows.Scan(&out) - if out != nil { - dbt.Errorf("%v != nil", out) - } - } else { - dbt.Error("no data") - } - }) -} - -func TestUint64(t *testing.T) { - const ( - u0 = uint64(0) - uall = ^u0 - uhigh = uall >> 1 - utop = ^uhigh - s0 = int64(0) - sall = ^s0 - shigh = int64(uhigh) - stop = ^shigh - ) - runTests(t, dsn, func(dbt *DBTest) { - stmt, err := dbt.db.Prepare(`SELECT ?, ?, ? ,?, ?, ?, ?, ?`) - if err != nil { - dbt.Fatal(err) - } - defer stmt.Close() - row := stmt.QueryRow( - u0, uhigh, utop, uall, - s0, shigh, stop, sall, - ) - - var ua, ub, uc, ud uint64 - var sa, sb, sc, sd int64 - - err = row.Scan(&ua, &ub, &uc, &ud, &sa, &sb, &sc, &sd) - if err != nil { - dbt.Fatal(err) - } - switch { - case ua != u0, - ub != uhigh, - uc != utop, - ud != uall, - sa != s0, - sb != shigh, - sc != stop, - sd != sall: - dbt.Fatal("unexpected result value") - } - }) -} - -func TestLongData(t *testing.T) { - runTests(t, dsn+"&maxAllowedPacket=0", func(dbt *DBTest) { - var maxAllowedPacketSize int - err := dbt.db.QueryRow("select @@max_allowed_packet").Scan(&maxAllowedPacketSize) - if err != nil { - dbt.Fatal(err) - } - maxAllowedPacketSize-- - - // don't get too ambitious - if maxAllowedPacketSize > 1<<25 { - maxAllowedPacketSize = 1 << 25 - } - - dbt.mustExec("CREATE TABLE test (value LONGBLOB)") - - in := strings.Repeat(`a`, maxAllowedPacketSize+1) - var out string - var rows *sql.Rows - - // Long text data - const nonDataQueryLen = 28 // length query w/o value - inS := in[:maxAllowedPacketSize-nonDataQueryLen] - dbt.mustExec("INSERT INTO test VALUES('" + inS + "')") - rows = dbt.mustQuery("SELECT value FROM test") - defer rows.Close() - if rows.Next() { - rows.Scan(&out) - if inS != out { - dbt.Fatalf("LONGBLOB: length in: %d, length out: %d", len(inS), len(out)) - } - if rows.Next() { - dbt.Error("LONGBLOB: unexpexted row") - } - } else { - dbt.Fatalf("LONGBLOB: no data") - } - - // Empty table - dbt.mustExec("TRUNCATE TABLE test") - - // Long binary data - dbt.mustExec("INSERT INTO test VALUES(?)", in) - rows = dbt.mustQuery("SELECT value FROM test WHERE 1=?", 1) - defer rows.Close() - if rows.Next() { - rows.Scan(&out) - if in != out { - dbt.Fatalf("LONGBLOB: length in: %d, length out: %d", len(in), len(out)) - } - if rows.Next() { - dbt.Error("LONGBLOB: unexpexted row") - } - } else { - if err = rows.Err(); err != nil { - dbt.Fatalf("LONGBLOB: no data (err: %s)", err.Error()) - } else { - dbt.Fatal("LONGBLOB: no data (err: )") - } - } - }) -} - -func TestLoadData(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - verifyLoadDataResult := func() { - rows, err := dbt.db.Query("SELECT * FROM test") - if err != nil { - dbt.Fatal(err.Error()) - } - - i := 0 - values := [4]string{ - "a string", - "a string containing a \t", - "a string containing a \n", - "a string containing both \t\n", - } - - var id int - var value string - - for rows.Next() { - i++ - err = rows.Scan(&id, &value) - if err != nil { - dbt.Fatal(err.Error()) - } - if i != id { - dbt.Fatalf("%d != %d", i, id) - } - if values[i-1] != value { - dbt.Fatalf("%q != %q", values[i-1], value) - } - } - err = rows.Err() - if err != nil { - dbt.Fatal(err.Error()) - } - - if i != 4 { - dbt.Fatalf("rows count mismatch. Got %d, want 4", i) - } - } - - dbt.db.Exec("DROP TABLE IF EXISTS test") - dbt.mustExec("CREATE TABLE test (id INT NOT NULL PRIMARY KEY, value TEXT NOT NULL) CHARACTER SET utf8") - - // Local File - file, err := ioutil.TempFile("", "gotest") - defer os.Remove(file.Name()) - if err != nil { - dbt.Fatal(err) - } - RegisterLocalFile(file.Name()) - - // Try first with empty file - dbt.mustExec(fmt.Sprintf("LOAD DATA LOCAL INFILE %q INTO TABLE test", file.Name())) - var count int - err = dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&count) - if err != nil { - dbt.Fatal(err.Error()) - } - if count != 0 { - dbt.Fatalf("unexpected row count: got %d, want 0", count) - } - - // Then fille File with data and try to load it - file.WriteString("1\ta string\n2\ta string containing a \\t\n3\ta string containing a \\n\n4\ta string containing both \\t\\n\n") - file.Close() - dbt.mustExec(fmt.Sprintf("LOAD DATA LOCAL INFILE %q INTO TABLE test", file.Name())) - verifyLoadDataResult() - - // Try with non-existing file - _, err = dbt.db.Exec("LOAD DATA LOCAL INFILE 'doesnotexist' INTO TABLE test") - if err == nil { - dbt.Fatal("load non-existent file didn't fail") - } else if err.Error() != "local file 'doesnotexist' is not registered" { - dbt.Fatal(err.Error()) - } - - // Empty table - dbt.mustExec("TRUNCATE TABLE test") - - // Reader - RegisterReaderHandler("test", func() io.Reader { - file, err = os.Open(file.Name()) - if err != nil { - dbt.Fatal(err) - } - return file - }) - dbt.mustExec("LOAD DATA LOCAL INFILE 'Reader::test' INTO TABLE test") - verifyLoadDataResult() - // negative test - _, err = dbt.db.Exec("LOAD DATA LOCAL INFILE 'Reader::doesnotexist' INTO TABLE test") - if err == nil { - dbt.Fatal("load non-existent Reader didn't fail") - } else if err.Error() != "Reader 'doesnotexist' is not registered" { - dbt.Fatal(err.Error()) - } - }) -} - -func TestFoundRows(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - dbt.mustExec("CREATE TABLE test (id INT NOT NULL ,data INT NOT NULL)") - dbt.mustExec("INSERT INTO test (id, data) VALUES (0, 0),(0, 0),(1, 0),(1, 0),(1, 1)") - - res := dbt.mustExec("UPDATE test SET data = 1 WHERE id = 0") - count, err := res.RowsAffected() - if err != nil { - dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) - } - if count != 2 { - dbt.Fatalf("Expected 2 affected rows, got %d", count) - } - res = dbt.mustExec("UPDATE test SET data = 1 WHERE id = 1") - count, err = res.RowsAffected() - if err != nil { - dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) - } - if count != 2 { - dbt.Fatalf("Expected 2 affected rows, got %d", count) - } - }) - runTests(t, dsn+"&clientFoundRows=true", func(dbt *DBTest) { - dbt.mustExec("CREATE TABLE test (id INT NOT NULL ,data INT NOT NULL)") - dbt.mustExec("INSERT INTO test (id, data) VALUES (0, 0),(0, 0),(1, 0),(1, 0),(1, 1)") - - res := dbt.mustExec("UPDATE test SET data = 1 WHERE id = 0") - count, err := res.RowsAffected() - if err != nil { - dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) - } - if count != 2 { - dbt.Fatalf("Expected 2 matched rows, got %d", count) - } - res = dbt.mustExec("UPDATE test SET data = 1 WHERE id = 1") - count, err = res.RowsAffected() - if err != nil { - dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error()) - } - if count != 3 { - dbt.Fatalf("Expected 3 matched rows, got %d", count) - } - }) -} - -func TestTLS(t *testing.T) { - tlsTestReq := func(dbt *DBTest) { - if err := dbt.db.Ping(); err != nil { - if err == ErrNoTLS { - dbt.Skip("server does not support TLS") - } else { - dbt.Fatalf("error on Ping: %s", err.Error()) - } - } - - rows := dbt.mustQuery("SHOW STATUS LIKE 'Ssl_cipher'") - defer rows.Close() - - var variable, value *sql.RawBytes - for rows.Next() { - if err := rows.Scan(&variable, &value); err != nil { - dbt.Fatal(err.Error()) - } - - if (*value == nil) || (len(*value) == 0) { - dbt.Fatalf("no Cipher") - } else { - dbt.Logf("Cipher: %s", *value) - } - } - } - tlsTestOpt := func(dbt *DBTest) { - if err := dbt.db.Ping(); err != nil { - dbt.Fatalf("error on Ping: %s", err.Error()) - } - } - - runTests(t, dsn+"&tls=preferred", tlsTestOpt) - runTests(t, dsn+"&tls=skip-verify", tlsTestReq) - - // Verify that registering / using a custom cfg works - RegisterTLSConfig("custom-skip-verify", &tls.Config{ - InsecureSkipVerify: true, - }) - runTests(t, dsn+"&tls=custom-skip-verify", tlsTestReq) -} - -func TestReuseClosedConnection(t *testing.T) { - // this test does not use sql.database, it uses the driver directly - if !available { - t.Skipf("MySQL server not running on %s", netAddr) - } - - md := &MySQLDriver{} - conn, err := md.Open(dsn) - if err != nil { - t.Fatalf("error connecting: %s", err.Error()) - } - stmt, err := conn.Prepare("DO 1") - if err != nil { - t.Fatalf("error preparing statement: %s", err.Error()) - } - _, err = stmt.Exec(nil) - if err != nil { - t.Fatalf("error executing statement: %s", err.Error()) - } - err = conn.Close() - if err != nil { - t.Fatalf("error closing connection: %s", err.Error()) - } - - defer func() { - if err := recover(); err != nil { - t.Errorf("panic after reusing a closed connection: %v", err) - } - }() - _, err = stmt.Exec(nil) - if err != nil && err != driver.ErrBadConn { - t.Errorf("unexpected error '%s', expected '%s'", - err.Error(), driver.ErrBadConn.Error()) - } -} - -func TestCharset(t *testing.T) { - if !available { - t.Skipf("MySQL server not running on %s", netAddr) - } - - mustSetCharset := func(charsetParam, expected string) { - runTests(t, dsn+"&"+charsetParam, func(dbt *DBTest) { - rows := dbt.mustQuery("SELECT @@character_set_connection") - defer rows.Close() - - if !rows.Next() { - dbt.Fatalf("error getting connection charset: %s", rows.Err()) - } - - var got string - rows.Scan(&got) - - if got != expected { - dbt.Fatalf("expected connection charset %s but got %s", expected, got) - } - }) - } - - // non utf8 test - mustSetCharset("charset=ascii", "ascii") - - // when the first charset is invalid, use the second - mustSetCharset("charset=none,utf8", "utf8") - - // when the first charset is valid, use it - mustSetCharset("charset=ascii,utf8", "ascii") - mustSetCharset("charset=utf8,ascii", "utf8") -} - -func TestFailingCharset(t *testing.T) { - runTests(t, dsn+"&charset=none", func(dbt *DBTest) { - // run query to really establish connection... - _, err := dbt.db.Exec("SELECT 1") - if err == nil { - dbt.db.Close() - t.Fatalf("connection must not succeed without a valid charset") - } - }) -} - -func TestCollation(t *testing.T) { - if !available { - t.Skipf("MySQL server not running on %s", netAddr) - } - - defaultCollation := "utf8mb4_general_ci" - testCollations := []string{ - "", // do not set - defaultCollation, // driver default - "latin1_general_ci", - "binary", - "utf8_unicode_ci", - "cp1257_bin", - } - - for _, collation := range testCollations { - var expected, tdsn string - if collation != "" { - tdsn = dsn + "&collation=" + collation - expected = collation - } else { - tdsn = dsn - expected = defaultCollation - } - - runTests(t, tdsn, func(dbt *DBTest) { - var got string - if err := dbt.db.QueryRow("SELECT @@collation_connection").Scan(&got); err != nil { - dbt.Fatal(err) - } - - if got != expected { - dbt.Fatalf("expected connection collation %s but got %s", expected, got) - } - }) - } -} - -func TestColumnsWithAlias(t *testing.T) { - runTests(t, dsn+"&columnsWithAlias=true", func(dbt *DBTest) { - rows := dbt.mustQuery("SELECT 1 AS A") - defer rows.Close() - cols, _ := rows.Columns() - if len(cols) != 1 { - t.Fatalf("expected 1 column, got %d", len(cols)) - } - if cols[0] != "A" { - t.Fatalf("expected column name \"A\", got \"%s\"", cols[0]) - } - - rows = dbt.mustQuery("SELECT * FROM (SELECT 1 AS one) AS A") - defer rows.Close() - cols, _ = rows.Columns() - if len(cols) != 1 { - t.Fatalf("expected 1 column, got %d", len(cols)) - } - if cols[0] != "A.one" { - t.Fatalf("expected column name \"A.one\", got \"%s\"", cols[0]) - } - }) -} - -func TestRawBytesResultExceedsBuffer(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - // defaultBufSize from buffer.go - expected := strings.Repeat("abc", defaultBufSize) - - rows := dbt.mustQuery("SELECT '" + expected + "'") - defer rows.Close() - if !rows.Next() { - dbt.Error("expected result, got none") - } - var result sql.RawBytes - rows.Scan(&result) - if expected != string(result) { - dbt.Error("result did not match expected value") - } - }) -} - -func TestTimezoneConversion(t *testing.T) { - zones := []string{"UTC", "US/Central", "US/Pacific", "Local"} - - // Regression test for timezone handling - tzTest := func(dbt *DBTest) { - // Create table - dbt.mustExec("CREATE TABLE test (ts TIMESTAMP)") - - // Insert local time into database (should be converted) - usCentral, _ := time.LoadLocation("US/Central") - reftime := time.Date(2014, 05, 30, 18, 03, 17, 0, time.UTC).In(usCentral) - dbt.mustExec("INSERT INTO test VALUE (?)", reftime) - - // Retrieve time from DB - rows := dbt.mustQuery("SELECT ts FROM test") - defer rows.Close() - if !rows.Next() { - dbt.Fatal("did not get any rows out") - } - - var dbTime time.Time - err := rows.Scan(&dbTime) - if err != nil { - dbt.Fatal("Err", err) - } - - // Check that dates match - if reftime.Unix() != dbTime.Unix() { - dbt.Errorf("times do not match.\n") - dbt.Errorf(" Now(%v)=%v\n", usCentral, reftime) - dbt.Errorf(" Now(UTC)=%v\n", dbTime) - } - } - - for _, tz := range zones { - runTests(t, dsn+"&parseTime=true&loc="+url.QueryEscape(tz), tzTest) - } -} - -// Special cases - -func TestRowsClose(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - rows, err := dbt.db.Query("SELECT 1") - if err != nil { - dbt.Fatal(err) - } - - err = rows.Close() - if err != nil { - dbt.Fatal(err) - } - - if rows.Next() { - dbt.Fatal("unexpected row after rows.Close()") - } - - err = rows.Err() - if err != nil { - dbt.Fatal(err) - } - }) -} - -// dangling statements -// http://code.google.com/p/go/issues/detail?id=3865 -func TestCloseStmtBeforeRows(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - stmt, err := dbt.db.Prepare("SELECT 1") - if err != nil { - dbt.Fatal(err) - } - - rows, err := stmt.Query() - if err != nil { - stmt.Close() - dbt.Fatal(err) - } - defer rows.Close() - - err = stmt.Close() - if err != nil { - dbt.Fatal(err) - } - - if !rows.Next() { - dbt.Fatal("getting row failed") - } else { - err = rows.Err() - if err != nil { - dbt.Fatal(err) - } - - var out bool - err = rows.Scan(&out) - if err != nil { - dbt.Fatalf("error on rows.Scan(): %s", err.Error()) - } - if out != true { - dbt.Errorf("true != %t", out) - } - } - }) -} - -// It is valid to have multiple Rows for the same Stmt -// http://code.google.com/p/go/issues/detail?id=3734 -func TestStmtMultiRows(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - stmt, err := dbt.db.Prepare("SELECT 1 UNION SELECT 0") - if err != nil { - dbt.Fatal(err) - } - - rows1, err := stmt.Query() - if err != nil { - stmt.Close() - dbt.Fatal(err) - } - defer rows1.Close() - - rows2, err := stmt.Query() - if err != nil { - stmt.Close() - dbt.Fatal(err) - } - defer rows2.Close() - - var out bool - - // 1 - if !rows1.Next() { - dbt.Fatal("first rows1.Next failed") - } else { - err = rows1.Err() - if err != nil { - dbt.Fatal(err) - } - - err = rows1.Scan(&out) - if err != nil { - dbt.Fatalf("error on rows.Scan(): %s", err.Error()) - } - if out != true { - dbt.Errorf("true != %t", out) - } - } - - if !rows2.Next() { - dbt.Fatal("first rows2.Next failed") - } else { - err = rows2.Err() - if err != nil { - dbt.Fatal(err) - } - - err = rows2.Scan(&out) - if err != nil { - dbt.Fatalf("error on rows.Scan(): %s", err.Error()) - } - if out != true { - dbt.Errorf("true != %t", out) - } - } - - // 2 - if !rows1.Next() { - dbt.Fatal("second rows1.Next failed") - } else { - err = rows1.Err() - if err != nil { - dbt.Fatal(err) - } - - err = rows1.Scan(&out) - if err != nil { - dbt.Fatalf("error on rows.Scan(): %s", err.Error()) - } - if out != false { - dbt.Errorf("false != %t", out) - } - - if rows1.Next() { - dbt.Fatal("unexpected row on rows1") - } - err = rows1.Close() - if err != nil { - dbt.Fatal(err) - } - } - - if !rows2.Next() { - dbt.Fatal("second rows2.Next failed") - } else { - err = rows2.Err() - if err != nil { - dbt.Fatal(err) - } - - err = rows2.Scan(&out) - if err != nil { - dbt.Fatalf("error on rows.Scan(): %s", err.Error()) - } - if out != false { - dbt.Errorf("false != %t", out) - } - - if rows2.Next() { - dbt.Fatal("unexpected row on rows2") - } - err = rows2.Close() - if err != nil { - dbt.Fatal(err) - } - } - }) -} - -// Regression test for -// * more than 32 NULL parameters (issue 209) -// * more parameters than fit into the buffer (issue 201) -// * parameters * 64 > max_allowed_packet (issue 734) -func TestPreparedManyCols(t *testing.T) { - numParams := 65535 - runTests(t, dsn, func(dbt *DBTest) { - query := "SELECT ?" + strings.Repeat(",?", numParams-1) - stmt, err := dbt.db.Prepare(query) - if err != nil { - dbt.Fatal(err) - } - defer stmt.Close() - - // create more parameters than fit into the buffer - // which will take nil-values - params := make([]interface{}, numParams) - rows, err := stmt.Query(params...) - if err != nil { - dbt.Fatal(err) - } - rows.Close() - - // Create 0byte string which we can't send via STMT_LONG_DATA. - for i := 0; i < numParams; i++ { - params[i] = "" - } - rows, err = stmt.Query(params...) - if err != nil { - dbt.Fatal(err) - } - rows.Close() - }) -} - -func TestConcurrent(t *testing.T) { - if enabled, _ := readBool(os.Getenv("MYSQL_TEST_CONCURRENT")); !enabled { - t.Skip("MYSQL_TEST_CONCURRENT env var not set") - } - - runTests(t, dsn, func(dbt *DBTest) { - var version string - if err := dbt.db.QueryRow("SELECT @@version").Scan(&version); err != nil { - dbt.Fatalf("%s", err.Error()) - } - if strings.Contains(strings.ToLower(version), "mariadb") { - t.Skip(`TODO: "fix commands out of sync. Did you run multiple statements at once?" on MariaDB`) - } - - var max int - err := dbt.db.QueryRow("SELECT @@max_connections").Scan(&max) - if err != nil { - dbt.Fatalf("%s", err.Error()) - } - dbt.Logf("testing up to %d concurrent connections \r\n", max) - - var remaining, succeeded int32 = int32(max), 0 - - var wg sync.WaitGroup - wg.Add(max) - - var fatalError string - var once sync.Once - fatalf := func(s string, vals ...interface{}) { - once.Do(func() { - fatalError = fmt.Sprintf(s, vals...) - }) - } - - for i := 0; i < max; i++ { - go func(id int) { - defer wg.Done() - - tx, err := dbt.db.Begin() - atomic.AddInt32(&remaining, -1) - - if err != nil { - if err.Error() != "Error 1040: Too many connections" { - fatalf("error on conn %d: %s", id, err.Error()) - } - return - } - - // keep the connection busy until all connections are open - for remaining > 0 { - if _, err = tx.Exec("DO 1"); err != nil { - fatalf("error on conn %d: %s", id, err.Error()) - return - } - } - - if err = tx.Commit(); err != nil { - fatalf("error on conn %d: %s", id, err.Error()) - return - } - - // everything went fine with this connection - atomic.AddInt32(&succeeded, 1) - }(i) - } - - // wait until all conections are open - wg.Wait() - - if fatalError != "" { - dbt.Fatal(fatalError) - } - - dbt.Logf("reached %d concurrent connections\r\n", succeeded) - }) -} - -func testDialError(t *testing.T, dialErr error, expectErr error) { - RegisterDialContext("mydial", func(ctx context.Context, addr string) (net.Conn, error) { - return nil, dialErr - }) - - db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mydial(%s)/%s?timeout=30s", user, pass, addr, dbname)) - if err != nil { - t.Fatalf("error connecting: %s", err.Error()) - } - defer db.Close() - - _, err = db.Exec("DO 1") - if err != expectErr { - t.Fatalf("was expecting %s. Got: %s", dialErr, err) - } -} - -func TestDialUnknownError(t *testing.T) { - testErr := fmt.Errorf("test") - testDialError(t, testErr, testErr) -} - -func TestDialNonRetryableNetErr(t *testing.T) { - testErr := netErrorMock{} - testDialError(t, testErr, testErr) -} - -func TestDialTemporaryNetErr(t *testing.T) { - testErr := netErrorMock{temporary: true} - testDialError(t, testErr, testErr) -} - -// Tests custom dial functions -func TestCustomDial(t *testing.T) { - if !available { - t.Skipf("MySQL server not running on %s", netAddr) - } - - // our custom dial function which justs wraps net.Dial here - RegisterDialContext("mydial", func(ctx context.Context, addr string) (net.Conn, error) { - var d net.Dialer - return d.DialContext(ctx, prot, addr) - }) - - db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mydial(%s)/%s?timeout=30s", user, pass, addr, dbname)) - if err != nil { - t.Fatalf("error connecting: %s", err.Error()) - } - defer db.Close() - - if _, err = db.Exec("DO 1"); err != nil { - t.Fatalf("connection failed: %s", err.Error()) - } -} - -func TestSQLInjection(t *testing.T) { - createTest := func(arg string) func(dbt *DBTest) { - return func(dbt *DBTest) { - dbt.mustExec("CREATE TABLE test (v INTEGER)") - dbt.mustExec("INSERT INTO test VALUES (?)", 1) - - var v int - // NULL can't be equal to anything, the idea here is to inject query so it returns row - // This test verifies that escapeQuotes and escapeBackslash are working properly - err := dbt.db.QueryRow("SELECT v FROM test WHERE NULL = ?", arg).Scan(&v) - if err == sql.ErrNoRows { - return // success, sql injection failed - } else if err == nil { - dbt.Errorf("sql injection successful with arg: %s", arg) - } else { - dbt.Errorf("error running query with arg: %s; err: %s", arg, err.Error()) - } - } - } - - dsns := []string{ - dsn, - dsn + "&sql_mode='NO_BACKSLASH_ESCAPES'", - } - for _, testdsn := range dsns { - runTests(t, testdsn, createTest("1 OR 1=1")) - runTests(t, testdsn, createTest("' OR '1'='1")) - } -} - -// Test if inserted data is correctly retrieved after being escaped -func TestInsertRetrieveEscapedData(t *testing.T) { - testData := func(dbt *DBTest) { - dbt.mustExec("CREATE TABLE test (v VARCHAR(255))") - - // All sequences that are escaped by escapeQuotes and escapeBackslash - v := "foo \x00\n\r\x1a\"'\\" - dbt.mustExec("INSERT INTO test VALUES (?)", v) - - var out string - err := dbt.db.QueryRow("SELECT v FROM test").Scan(&out) - if err != nil { - dbt.Fatalf("%s", err.Error()) - } - - if out != v { - dbt.Errorf("%q != %q", out, v) - } - } - - dsns := []string{ - dsn, - dsn + "&sql_mode='NO_BACKSLASH_ESCAPES'", - } - for _, testdsn := range dsns { - runTests(t, testdsn, testData) - } -} - -func TestUnixSocketAuthFail(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - // Save the current logger so we can restore it. - oldLogger := errLog - - // Set a new logger so we can capture its output. - buffer := bytes.NewBuffer(make([]byte, 0, 64)) - newLogger := log.New(buffer, "prefix: ", 0) - SetLogger(newLogger) - - // Restore the logger. - defer SetLogger(oldLogger) - - // Make a new DSN that uses the MySQL socket file and a bad password, which - // we can make by simply appending any character to the real password. - badPass := pass + "x" - socket := "" - if prot == "unix" { - socket = addr - } else { - // Get socket file from MySQL. - err := dbt.db.QueryRow("SELECT @@socket").Scan(&socket) - if err != nil { - t.Fatalf("error on SELECT @@socket: %s", err.Error()) - } - } - t.Logf("socket: %s", socket) - badDSN := fmt.Sprintf("%s:%s@unix(%s)/%s?timeout=30s", user, badPass, socket, dbname) - db, err := sql.Open("mysql", badDSN) - if err != nil { - t.Fatalf("error connecting: %s", err.Error()) - } - defer db.Close() - - // Connect to MySQL for real. This will cause an auth failure. - err = db.Ping() - if err == nil { - t.Error("expected Ping() to return an error") - } - - // The driver should not log anything. - if actual := buffer.String(); actual != "" { - t.Errorf("expected no output, got %q", actual) - } - }) -} - -// See Issue #422 -func TestInterruptBySignal(t *testing.T) { - runTestsWithMultiStatement(t, dsn, func(dbt *DBTest) { - dbt.mustExec(` - DROP PROCEDURE IF EXISTS test_signal; - CREATE PROCEDURE test_signal(ret INT) - BEGIN - SELECT ret; - SIGNAL SQLSTATE - '45001' - SET - MESSAGE_TEXT = "an error", - MYSQL_ERRNO = 45001; - END - `) - defer dbt.mustExec("DROP PROCEDURE test_signal") - - var val int - - // text protocol - rows, err := dbt.db.Query("CALL test_signal(42)") - if err != nil { - dbt.Fatalf("error on text query: %s", err.Error()) - } - for rows.Next() { - if err := rows.Scan(&val); err != nil { - dbt.Error(err) - } else if val != 42 { - dbt.Errorf("expected val to be 42") - } - } - rows.Close() - - // binary protocol - rows, err = dbt.db.Query("CALL test_signal(?)", 42) - if err != nil { - dbt.Fatalf("error on binary query: %s", err.Error()) - } - for rows.Next() { - if err := rows.Scan(&val); err != nil { - dbt.Error(err) - } else if val != 42 { - dbt.Errorf("expected val to be 42") - } - } - rows.Close() - }) -} - -func TestColumnsReusesSlice(t *testing.T) { - rows := mysqlRows{ - rs: resultSet{ - columns: []mysqlField{ - { - tableName: "test", - name: "A", - }, - { - tableName: "test", - name: "B", - }, - }, - }, - } - - allocs := testing.AllocsPerRun(1, func() { - cols := rows.Columns() - - if len(cols) != 2 { - t.Fatalf("expected 2 columns, got %d", len(cols)) - } - }) - - if allocs != 0 { - t.Fatalf("expected 0 allocations, got %d", int(allocs)) - } - - if rows.rs.columnNames == nil { - t.Fatalf("expected columnNames to be set, got nil") - } -} - -func TestRejectReadOnly(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - // Create Table - dbt.mustExec("CREATE TABLE test (value BOOL)") - // Set the session to read-only. We didn't set the `rejectReadOnly` - // option, so any writes after this should fail. - _, err := dbt.db.Exec("SET SESSION TRANSACTION READ ONLY") - // Error 1193: Unknown system variable 'TRANSACTION' => skip test, - // MySQL server version is too old - maybeSkip(t, err, 1193) - if _, err := dbt.db.Exec("DROP TABLE test"); err == nil { - t.Fatalf("writing to DB in read-only session without " + - "rejectReadOnly did not error") - } - // Set the session back to read-write so runTests() can properly clean - // up the table `test`. - dbt.mustExec("SET SESSION TRANSACTION READ WRITE") - }) - - // Enable the `rejectReadOnly` option. - runTests(t, dsn+"&rejectReadOnly=true", func(dbt *DBTest) { - // Create Table - dbt.mustExec("CREATE TABLE test (value BOOL)") - // Set the session to read only. Any writes after this should error on - // a driver.ErrBadConn, and cause `database/sql` to initiate a new - // connection. - dbt.mustExec("SET SESSION TRANSACTION READ ONLY") - // This would error, but `database/sql` should automatically retry on a - // new connection which is not read-only, and eventually succeed. - dbt.mustExec("DROP TABLE test") - }) -} - -func TestPing(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - if err := dbt.db.Ping(); err != nil { - dbt.fail("Ping", "Ping", err) - } - }) -} - -// See Issue #799 -func TestEmptyPassword(t *testing.T) { - if !available { - t.Skipf("MySQL server not running on %s", netAddr) - } - - dsn := fmt.Sprintf("%s:%s@%s/%s?timeout=30s", user, "", netAddr, dbname) - db, err := sql.Open("mysql", dsn) - if err == nil { - defer db.Close() - err = db.Ping() - } - - if pass == "" { - if err != nil { - t.Fatal(err.Error()) - } - } else { - if err == nil { - t.Fatal("expected authentication error") - } - if !strings.HasPrefix(err.Error(), "Error 1045") { - t.Fatal(err.Error()) - } - } -} - -// static interface implementation checks of mysqlConn -var ( - _ driver.ConnBeginTx = &mysqlConn{} - _ driver.ConnPrepareContext = &mysqlConn{} - _ driver.ExecerContext = &mysqlConn{} - _ driver.Pinger = &mysqlConn{} - _ driver.QueryerContext = &mysqlConn{} -) - -// static interface implementation checks of mysqlStmt -var ( - _ driver.StmtExecContext = &mysqlStmt{} - _ driver.StmtQueryContext = &mysqlStmt{} -) - -// Ensure that all the driver interfaces are implemented -var ( - // _ driver.RowsColumnTypeLength = &binaryRows{} - // _ driver.RowsColumnTypeLength = &textRows{} - _ driver.RowsColumnTypeDatabaseTypeName = &binaryRows{} - _ driver.RowsColumnTypeDatabaseTypeName = &textRows{} - _ driver.RowsColumnTypeNullable = &binaryRows{} - _ driver.RowsColumnTypeNullable = &textRows{} - _ driver.RowsColumnTypePrecisionScale = &binaryRows{} - _ driver.RowsColumnTypePrecisionScale = &textRows{} - _ driver.RowsColumnTypeScanType = &binaryRows{} - _ driver.RowsColumnTypeScanType = &textRows{} - _ driver.RowsNextResultSet = &binaryRows{} - _ driver.RowsNextResultSet = &textRows{} -) - -func TestMultiResultSet(t *testing.T) { - type result struct { - values [][]int - columns []string - } - - // checkRows is a helper test function to validate rows containing 3 result - // sets with specific values and columns. The basic query would look like this: - // - // SELECT 1 AS col1, 2 AS col2 UNION SELECT 3, 4; - // SELECT 0 UNION SELECT 1; - // SELECT 1 AS col1, 2 AS col2, 3 AS col3 UNION SELECT 4, 5, 6; - // - // to distinguish test cases the first string argument is put in front of - // every error or fatal message. - checkRows := func(desc string, rows *sql.Rows, dbt *DBTest) { - expected := []result{ - { - values: [][]int{{1, 2}, {3, 4}}, - columns: []string{"col1", "col2"}, - }, - { - values: [][]int{{1, 2, 3}, {4, 5, 6}}, - columns: []string{"col1", "col2", "col3"}, - }, - } - - var res1 result - for rows.Next() { - var res [2]int - if err := rows.Scan(&res[0], &res[1]); err != nil { - dbt.Fatal(err) - } - res1.values = append(res1.values, res[:]) - } - - cols, err := rows.Columns() - if err != nil { - dbt.Fatal(desc, err) - } - res1.columns = cols - - if !reflect.DeepEqual(expected[0], res1) { - dbt.Error(desc, "want =", expected[0], "got =", res1) - } - - if !rows.NextResultSet() { - dbt.Fatal(desc, "expected next result set") - } - - // ignoring one result set - - if !rows.NextResultSet() { - dbt.Fatal(desc, "expected next result set") - } - - var res2 result - cols, err = rows.Columns() - if err != nil { - dbt.Fatal(desc, err) - } - res2.columns = cols - - for rows.Next() { - var res [3]int - if err := rows.Scan(&res[0], &res[1], &res[2]); err != nil { - dbt.Fatal(desc, err) - } - res2.values = append(res2.values, res[:]) - } - - if !reflect.DeepEqual(expected[1], res2) { - dbt.Error(desc, "want =", expected[1], "got =", res2) - } - - if rows.NextResultSet() { - dbt.Error(desc, "unexpected next result set") - } - - if err := rows.Err(); err != nil { - dbt.Error(desc, err) - } - } - - runTestsWithMultiStatement(t, dsn, func(dbt *DBTest) { - rows := dbt.mustQuery(`DO 1; - SELECT 1 AS col1, 2 AS col2 UNION SELECT 3, 4; - DO 1; - SELECT 0 UNION SELECT 1; - SELECT 1 AS col1, 2 AS col2, 3 AS col3 UNION SELECT 4, 5, 6;`) - defer rows.Close() - checkRows("query: ", rows, dbt) - }) - - runTestsWithMultiStatement(t, dsn, func(dbt *DBTest) { - queries := []string{ - ` - DROP PROCEDURE IF EXISTS test_mrss; - CREATE PROCEDURE test_mrss() - BEGIN - DO 1; - SELECT 1 AS col1, 2 AS col2 UNION SELECT 3, 4; - DO 1; - SELECT 0 UNION SELECT 1; - SELECT 1 AS col1, 2 AS col2, 3 AS col3 UNION SELECT 4, 5, 6; - END - `, - ` - DROP PROCEDURE IF EXISTS test_mrss; - CREATE PROCEDURE test_mrss() - BEGIN - SELECT 1 AS col1, 2 AS col2 UNION SELECT 3, 4; - SELECT 0 UNION SELECT 1; - SELECT 1 AS col1, 2 AS col2, 3 AS col3 UNION SELECT 4, 5, 6; - END - `, - } - - defer dbt.mustExec("DROP PROCEDURE IF EXISTS test_mrss") - - for i, query := range queries { - dbt.mustExec(query) - - stmt, err := dbt.db.Prepare("CALL test_mrss()") - if err != nil { - dbt.Fatalf("%v (i=%d)", err, i) - } - defer stmt.Close() - - for j := 0; j < 2; j++ { - rows, err := stmt.Query() - if err != nil { - dbt.Fatalf("%v (i=%d) (j=%d)", err, i, j) - } - checkRows(fmt.Sprintf("prepared stmt query (i=%d) (j=%d): ", i, j), rows, dbt) - } - } - }) -} - -func TestMultiResultSetNoSelect(t *testing.T) { - runTestsWithMultiStatement(t, dsn, func(dbt *DBTest) { - rows := dbt.mustQuery("DO 1; DO 2;") - defer rows.Close() - - if rows.Next() { - dbt.Error("unexpected row") - } - - if rows.NextResultSet() { - dbt.Error("unexpected next result set") - } - - if err := rows.Err(); err != nil { - dbt.Error("expected nil; got ", err) - } - }) -} - -// tests if rows are set in a proper state if some results were ignored before -// calling rows.NextResultSet. -func TestSkipResults(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - rows := dbt.mustQuery("SELECT 1, 2") - defer rows.Close() - - if !rows.Next() { - dbt.Error("expected row") - } - - if rows.NextResultSet() { - dbt.Error("unexpected next result set") - } - - if err := rows.Err(); err != nil { - dbt.Error("expected nil; got ", err) - } - }) -} - -func TestPingContext(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - ctx, cancel := context.WithCancel(context.Background()) - cancel() - if err := dbt.db.PingContext(ctx); err != context.Canceled { - dbt.Errorf("expected context.Canceled, got %v", err) - } - }) -} - -func TestContextCancelExec(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - dbt.mustExec("CREATE TABLE test (v INTEGER)") - ctx, cancel := context.WithCancel(context.Background()) - - // Delay execution for just a bit until db.ExecContext has begun. - defer time.AfterFunc(250*time.Millisecond, cancel).Stop() - - // This query will be canceled. - startTime := time.Now() - if _, err := dbt.db.ExecContext(ctx, "INSERT INTO test VALUES (SLEEP(1))"); err != context.Canceled { - dbt.Errorf("expected context.Canceled, got %v", err) - } - if d := time.Since(startTime); d > 500*time.Millisecond { - dbt.Errorf("too long execution time: %s", d) - } - - // Wait for the INSERT query to be done. - time.Sleep(time.Second) - - // Check how many times the query is executed. - var v int - if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { - dbt.Fatalf("%s", err.Error()) - } - if v != 1 { // TODO: need to kill the query, and v should be 0. - dbt.Skipf("[WARN] expected val to be 1, got %d", v) - } - - // Context is already canceled, so error should come before execution. - if _, err := dbt.db.ExecContext(ctx, "INSERT INTO test VALUES (1)"); err == nil { - dbt.Error("expected error") - } else if err.Error() != "context canceled" { - dbt.Fatalf("unexpected error: %s", err) - } - - // The second insert query will fail, so the table has no changes. - if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { - dbt.Fatalf("%s", err.Error()) - } - if v != 1 { - dbt.Skipf("[WARN] expected val to be 1, got %d", v) - } - }) -} - -func TestContextCancelQuery(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - dbt.mustExec("CREATE TABLE test (v INTEGER)") - ctx, cancel := context.WithCancel(context.Background()) - - // Delay execution for just a bit until db.ExecContext has begun. - defer time.AfterFunc(250*time.Millisecond, cancel).Stop() - - // This query will be canceled. - startTime := time.Now() - if _, err := dbt.db.QueryContext(ctx, "INSERT INTO test VALUES (SLEEP(1))"); err != context.Canceled { - dbt.Errorf("expected context.Canceled, got %v", err) - } - if d := time.Since(startTime); d > 500*time.Millisecond { - dbt.Errorf("too long execution time: %s", d) - } - - // Wait for the INSERT query to be done. - time.Sleep(time.Second) - - // Check how many times the query is executed. - var v int - if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { - dbt.Fatalf("%s", err.Error()) - } - if v != 1 { // TODO: need to kill the query, and v should be 0. - dbt.Skipf("[WARN] expected val to be 1, got %d", v) - } - - // Context is already canceled, so error should come before execution. - if _, err := dbt.db.QueryContext(ctx, "INSERT INTO test VALUES (1)"); err != context.Canceled { - dbt.Errorf("expected context.Canceled, got %v", err) - } - - // The second insert query will fail, so the table has no changes. - if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { - dbt.Fatalf("%s", err.Error()) - } - if v != 1 { - dbt.Skipf("[WARN] expected val to be 1, got %d", v) - } - }) -} - -func TestContextCancelQueryRow(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - dbt.mustExec("CREATE TABLE test (v INTEGER)") - dbt.mustExec("INSERT INTO test VALUES (1), (2), (3)") - ctx, cancel := context.WithCancel(context.Background()) - - rows, err := dbt.db.QueryContext(ctx, "SELECT v FROM test") - if err != nil { - dbt.Fatalf("%s", err.Error()) - } - - // the first row will be succeed. - var v int - if !rows.Next() { - dbt.Fatalf("unexpected end") - } - if err := rows.Scan(&v); err != nil { - dbt.Fatalf("%s", err.Error()) - } - - cancel() - // make sure the driver receives the cancel request. - time.Sleep(100 * time.Millisecond) - - if rows.Next() { - dbt.Errorf("expected end, but not") - } - if err := rows.Err(); err != context.Canceled { - dbt.Errorf("expected context.Canceled, got %v", err) - } - }) -} - -func TestContextCancelPrepare(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - ctx, cancel := context.WithCancel(context.Background()) - cancel() - if _, err := dbt.db.PrepareContext(ctx, "SELECT 1"); err != context.Canceled { - dbt.Errorf("expected context.Canceled, got %v", err) - } - }) -} - -func TestContextCancelStmtExec(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - dbt.mustExec("CREATE TABLE test (v INTEGER)") - ctx, cancel := context.WithCancel(context.Background()) - stmt, err := dbt.db.PrepareContext(ctx, "INSERT INTO test VALUES (SLEEP(1))") - if err != nil { - dbt.Fatalf("unexpected error: %v", err) - } - - // Delay execution for just a bit until db.ExecContext has begun. - defer time.AfterFunc(250*time.Millisecond, cancel).Stop() - - // This query will be canceled. - startTime := time.Now() - if _, err := stmt.ExecContext(ctx); err != context.Canceled { - dbt.Errorf("expected context.Canceled, got %v", err) - } - if d := time.Since(startTime); d > 500*time.Millisecond { - dbt.Errorf("too long execution time: %s", d) - } - - // Wait for the INSERT query to be done. - time.Sleep(time.Second) - - // Check how many times the query is executed. - var v int - if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { - dbt.Fatalf("%s", err.Error()) - } - if v != 1 { // TODO: need to kill the query, and v should be 0. - dbt.Skipf("[WARN] expected val to be 1, got %d", v) - } - }) -} - -func TestContextCancelStmtQuery(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - dbt.mustExec("CREATE TABLE test (v INTEGER)") - ctx, cancel := context.WithCancel(context.Background()) - stmt, err := dbt.db.PrepareContext(ctx, "INSERT INTO test VALUES (SLEEP(1))") - if err != nil { - dbt.Fatalf("unexpected error: %v", err) - } - - // Delay execution for just a bit until db.ExecContext has begun. - defer time.AfterFunc(250*time.Millisecond, cancel).Stop() - - // This query will be canceled. - startTime := time.Now() - if _, err := stmt.QueryContext(ctx); err != context.Canceled { - dbt.Errorf("expected context.Canceled, got %v", err) - } - if d := time.Since(startTime); d > 500*time.Millisecond { - dbt.Errorf("too long execution time: %s", d) - } - - // Wait for the INSERT query has done. - time.Sleep(time.Second) - - // Check how many times the query is executed. - var v int - if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { - dbt.Fatalf("%s", err.Error()) - } - if v != 1 { // TODO: need to kill the query, and v should be 0. - dbt.Skipf("[WARN] expected val to be 1, got %d", v) - } - }) -} - -func TestContextCancelBegin(t *testing.T) { - if runtime.GOOS == "windows" || runtime.GOOS == "darwin" { - t.Skip(`FIXME: it sometime fails with "expected driver.ErrBadConn, got sql: connection is already closed" on windows and macOS`) - } - - runTests(t, dsn, func(dbt *DBTest) { - dbt.mustExec("CREATE TABLE test (v INTEGER)") - ctx, cancel := context.WithCancel(context.Background()) - conn, err := dbt.db.Conn(ctx) - if err != nil { - dbt.Fatal(err) - } - defer conn.Close() - tx, err := conn.BeginTx(ctx, nil) - if err != nil { - dbt.Fatal(err) - } - - // Delay execution for just a bit until db.ExecContext has begun. - defer time.AfterFunc(100*time.Millisecond, cancel).Stop() - - // This query will be canceled. - startTime := time.Now() - if _, err := tx.ExecContext(ctx, "INSERT INTO test VALUES (SLEEP(1))"); err != context.Canceled { - dbt.Errorf("expected context.Canceled, got %v", err) - } - if d := time.Since(startTime); d > 500*time.Millisecond { - dbt.Errorf("too long execution time: %s", d) - } - - // Transaction is canceled, so expect an error. - switch err := tx.Commit(); err { - case sql.ErrTxDone: - // because the transaction has already been rollbacked. - // the database/sql package watches ctx - // and rollbacks when ctx is canceled. - case context.Canceled: - // the database/sql package rollbacks on another goroutine, - // so the transaction may not be rollbacked depending on goroutine scheduling. - default: - dbt.Errorf("expected sql.ErrTxDone or context.Canceled, got %v", err) - } - - // The connection is now in an inoperable state - so performing other - // operations should fail with ErrBadConn - // Important to exercise isolation level too - it runs SET TRANSACTION ISOLATION - // LEVEL XXX first, which needs to return ErrBadConn if the connection's context - // is cancelled - _, err = conn.BeginTx(context.Background(), &sql.TxOptions{Isolation: sql.LevelReadCommitted}) - if err != driver.ErrBadConn { - dbt.Errorf("expected driver.ErrBadConn, got %v", err) - } - - // cannot begin a transaction (on a different conn) with a canceled context - if _, err := dbt.db.BeginTx(ctx, nil); err != context.Canceled { - dbt.Errorf("expected context.Canceled, got %v", err) - } - }) -} - -func TestContextBeginIsolationLevel(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - dbt.mustExec("CREATE TABLE test (v INTEGER)") - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - tx1, err := dbt.db.BeginTx(ctx, &sql.TxOptions{ - Isolation: sql.LevelRepeatableRead, - }) - if err != nil { - dbt.Fatal(err) - } - - tx2, err := dbt.db.BeginTx(ctx, &sql.TxOptions{ - Isolation: sql.LevelReadCommitted, - }) - if err != nil { - dbt.Fatal(err) - } - - _, err = tx1.ExecContext(ctx, "INSERT INTO test VALUES (1)") - if err != nil { - dbt.Fatal(err) - } - - var v int - row := tx2.QueryRowContext(ctx, "SELECT COUNT(*) FROM test") - if err := row.Scan(&v); err != nil { - dbt.Fatal(err) - } - // Because writer transaction wasn't commited yet, it should be available - if v != 0 { - dbt.Errorf("expected val to be 0, got %d", v) - } - - err = tx1.Commit() - if err != nil { - dbt.Fatal(err) - } - - row = tx2.QueryRowContext(ctx, "SELECT COUNT(*) FROM test") - if err := row.Scan(&v); err != nil { - dbt.Fatal(err) - } - // Data written by writer transaction is already commited, it should be selectable - if v != 1 { - dbt.Errorf("expected val to be 1, got %d", v) - } - tx2.Commit() - }) -} - -func TestContextBeginReadOnly(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - dbt.mustExec("CREATE TABLE test (v INTEGER)") - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - tx, err := dbt.db.BeginTx(ctx, &sql.TxOptions{ - ReadOnly: true, - }) - if _, ok := err.(*MySQLError); ok { - dbt.Skip("It seems that your MySQL does not support READ ONLY transactions") - return - } else if err != nil { - dbt.Fatal(err) - } - - // INSERT queries fail in a READ ONLY transaction. - _, err = tx.ExecContext(ctx, "INSERT INTO test VALUES (1)") - if _, ok := err.(*MySQLError); !ok { - dbt.Errorf("expected MySQLError, got %v", err) - } - - // SELECT queries can be executed. - var v int - row := tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM test") - if err := row.Scan(&v); err != nil { - dbt.Fatal(err) - } - if v != 0 { - dbt.Errorf("expected val to be 0, got %d", v) - } - - if err := tx.Commit(); err != nil { - dbt.Fatal(err) - } - }) -} - -func TestRowsColumnTypes(t *testing.T) { - niNULL := sql.NullInt64{Int64: 0, Valid: false} - ni0 := sql.NullInt64{Int64: 0, Valid: true} - ni1 := sql.NullInt64{Int64: 1, Valid: true} - ni42 := sql.NullInt64{Int64: 42, Valid: true} - nfNULL := sql.NullFloat64{Float64: 0.0, Valid: false} - nf0 := sql.NullFloat64{Float64: 0.0, Valid: true} - nf1337 := sql.NullFloat64{Float64: 13.37, Valid: true} - nt0 := nullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC), Valid: true} - nt1 := nullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 100000000, time.UTC), Valid: true} - nt2 := nullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 110000000, time.UTC), Valid: true} - nt6 := nullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 111111000, time.UTC), Valid: true} - nd1 := nullTime{Time: time.Date(2006, 01, 02, 0, 0, 0, 0, time.UTC), Valid: true} - nd2 := nullTime{Time: time.Date(2006, 03, 04, 0, 0, 0, 0, time.UTC), Valid: true} - ndNULL := nullTime{Time: time.Time{}, Valid: false} - rbNULL := sql.RawBytes(nil) - rb0 := sql.RawBytes("0") - rb42 := sql.RawBytes("42") - rbTest := sql.RawBytes("Test") - rb0pad4 := sql.RawBytes("0\x00\x00\x00") // BINARY right-pads values with 0x00 - rbx0 := sql.RawBytes("\x00") - rbx42 := sql.RawBytes("\x42") - - var columns = []struct { - name string - fieldType string // type used when creating table schema - databaseTypeName string // actual type used by MySQL - scanType reflect.Type - nullable bool - precision int64 // 0 if not ok - scale int64 - valuesIn [3]string - valuesOut [3]interface{} - }{ - {"bit8null", "BIT(8)", "BIT", scanTypeRawBytes, true, 0, 0, [3]string{"0x0", "NULL", "0x42"}, [3]interface{}{rbx0, rbNULL, rbx42}}, - {"boolnull", "BOOL", "TINYINT", scanTypeNullInt, true, 0, 0, [3]string{"NULL", "true", "0"}, [3]interface{}{niNULL, ni1, ni0}}, - {"bool", "BOOL NOT NULL", "TINYINT", scanTypeInt8, false, 0, 0, [3]string{"1", "0", "FALSE"}, [3]interface{}{int8(1), int8(0), int8(0)}}, - {"intnull", "INTEGER", "INT", scanTypeNullInt, true, 0, 0, [3]string{"0", "NULL", "42"}, [3]interface{}{ni0, niNULL, ni42}}, - {"smallint", "SMALLINT NOT NULL", "SMALLINT", scanTypeInt16, false, 0, 0, [3]string{"0", "-32768", "32767"}, [3]interface{}{int16(0), int16(-32768), int16(32767)}}, - {"smallintnull", "SMALLINT", "SMALLINT", scanTypeNullInt, true, 0, 0, [3]string{"0", "NULL", "42"}, [3]interface{}{ni0, niNULL, ni42}}, - {"int3null", "INT(3)", "INT", scanTypeNullInt, true, 0, 0, [3]string{"0", "NULL", "42"}, [3]interface{}{ni0, niNULL, ni42}}, - {"int7", "INT(7) NOT NULL", "INT", scanTypeInt32, false, 0, 0, [3]string{"0", "-1337", "42"}, [3]interface{}{int32(0), int32(-1337), int32(42)}}, - {"mediumintnull", "MEDIUMINT", "MEDIUMINT", scanTypeNullInt, true, 0, 0, [3]string{"0", "42", "NULL"}, [3]interface{}{ni0, ni42, niNULL}}, - {"bigint", "BIGINT NOT NULL", "BIGINT", scanTypeInt64, false, 0, 0, [3]string{"0", "65535", "-42"}, [3]interface{}{int64(0), int64(65535), int64(-42)}}, - {"bigintnull", "BIGINT", "BIGINT", scanTypeNullInt, true, 0, 0, [3]string{"NULL", "1", "42"}, [3]interface{}{niNULL, ni1, ni42}}, - {"tinyuint", "TINYINT UNSIGNED NOT NULL", "TINYINT", scanTypeUint8, false, 0, 0, [3]string{"0", "255", "42"}, [3]interface{}{uint8(0), uint8(255), uint8(42)}}, - {"smalluint", "SMALLINT UNSIGNED NOT NULL", "SMALLINT", scanTypeUint16, false, 0, 0, [3]string{"0", "65535", "42"}, [3]interface{}{uint16(0), uint16(65535), uint16(42)}}, - {"biguint", "BIGINT UNSIGNED NOT NULL", "BIGINT", scanTypeUint64, false, 0, 0, [3]string{"0", "65535", "42"}, [3]interface{}{uint64(0), uint64(65535), uint64(42)}}, - {"uint13", "INT(13) UNSIGNED NOT NULL", "INT", scanTypeUint32, false, 0, 0, [3]string{"0", "1337", "42"}, [3]interface{}{uint32(0), uint32(1337), uint32(42)}}, - {"float", "FLOAT NOT NULL", "FLOAT", scanTypeFloat32, false, math.MaxInt64, math.MaxInt64, [3]string{"0", "42", "13.37"}, [3]interface{}{float32(0), float32(42), float32(13.37)}}, - {"floatnull", "FLOAT", "FLOAT", scanTypeNullFloat, true, math.MaxInt64, math.MaxInt64, [3]string{"0", "NULL", "13.37"}, [3]interface{}{nf0, nfNULL, nf1337}}, - {"float74null", "FLOAT(7,4)", "FLOAT", scanTypeNullFloat, true, math.MaxInt64, 4, [3]string{"0", "NULL", "13.37"}, [3]interface{}{nf0, nfNULL, nf1337}}, - {"double", "DOUBLE NOT NULL", "DOUBLE", scanTypeFloat64, false, math.MaxInt64, math.MaxInt64, [3]string{"0", "42", "13.37"}, [3]interface{}{float64(0), float64(42), float64(13.37)}}, - {"doublenull", "DOUBLE", "DOUBLE", scanTypeNullFloat, true, math.MaxInt64, math.MaxInt64, [3]string{"0", "NULL", "13.37"}, [3]interface{}{nf0, nfNULL, nf1337}}, - {"decimal1", "DECIMAL(10,6) NOT NULL", "DECIMAL", scanTypeRawBytes, false, 10, 6, [3]string{"0", "13.37", "1234.123456"}, [3]interface{}{sql.RawBytes("0.000000"), sql.RawBytes("13.370000"), sql.RawBytes("1234.123456")}}, - {"decimal1null", "DECIMAL(10,6)", "DECIMAL", scanTypeRawBytes, true, 10, 6, [3]string{"0", "NULL", "1234.123456"}, [3]interface{}{sql.RawBytes("0.000000"), rbNULL, sql.RawBytes("1234.123456")}}, - {"decimal2", "DECIMAL(8,4) NOT NULL", "DECIMAL", scanTypeRawBytes, false, 8, 4, [3]string{"0", "13.37", "1234.123456"}, [3]interface{}{sql.RawBytes("0.0000"), sql.RawBytes("13.3700"), sql.RawBytes("1234.1235")}}, - {"decimal2null", "DECIMAL(8,4)", "DECIMAL", scanTypeRawBytes, true, 8, 4, [3]string{"0", "NULL", "1234.123456"}, [3]interface{}{sql.RawBytes("0.0000"), rbNULL, sql.RawBytes("1234.1235")}}, - {"decimal3", "DECIMAL(5,0) NOT NULL", "DECIMAL", scanTypeRawBytes, false, 5, 0, [3]string{"0", "13.37", "-12345.123456"}, [3]interface{}{rb0, sql.RawBytes("13"), sql.RawBytes("-12345")}}, - {"decimal3null", "DECIMAL(5,0)", "DECIMAL", scanTypeRawBytes, true, 5, 0, [3]string{"0", "NULL", "-12345.123456"}, [3]interface{}{rb0, rbNULL, sql.RawBytes("-12345")}}, - {"char25null", "CHAR(25)", "CHAR", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, - {"varchar42", "VARCHAR(42) NOT NULL", "VARCHAR", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, - {"binary4null", "BINARY(4)", "BINARY", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0pad4, rbNULL, rbTest}}, - {"varbinary42", "VARBINARY(42) NOT NULL", "VARBINARY", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, - {"tinyblobnull", "TINYBLOB", "BLOB", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, - {"tinytextnull", "TINYTEXT", "TEXT", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, - {"blobnull", "BLOB", "BLOB", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, - {"textnull", "TEXT", "TEXT", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, - {"mediumblob", "MEDIUMBLOB NOT NULL", "BLOB", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, - {"mediumtext", "MEDIUMTEXT NOT NULL", "TEXT", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, - {"longblob", "LONGBLOB NOT NULL", "BLOB", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, - {"longtext", "LONGTEXT NOT NULL", "TEXT", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, - {"datetime", "DATETIME", "DATETIME", scanTypeNullTime, true, 0, 0, [3]string{"'2006-01-02 15:04:05'", "'2006-01-02 15:04:05.1'", "'2006-01-02 15:04:05.111111'"}, [3]interface{}{nt0, nt0, nt0}}, - {"datetime2", "DATETIME(2)", "DATETIME", scanTypeNullTime, true, 2, 2, [3]string{"'2006-01-02 15:04:05'", "'2006-01-02 15:04:05.1'", "'2006-01-02 15:04:05.111111'"}, [3]interface{}{nt0, nt1, nt2}}, - {"datetime6", "DATETIME(6)", "DATETIME", scanTypeNullTime, true, 6, 6, [3]string{"'2006-01-02 15:04:05'", "'2006-01-02 15:04:05.1'", "'2006-01-02 15:04:05.111111'"}, [3]interface{}{nt0, nt1, nt6}}, - {"date", "DATE", "DATE", scanTypeNullTime, true, 0, 0, [3]string{"'2006-01-02'", "NULL", "'2006-03-04'"}, [3]interface{}{nd1, ndNULL, nd2}}, - {"year", "YEAR NOT NULL", "YEAR", scanTypeUint16, false, 0, 0, [3]string{"2006", "2000", "1994"}, [3]interface{}{uint16(2006), uint16(2000), uint16(1994)}}, - } - - schema := "" - values1 := "" - values2 := "" - values3 := "" - for _, column := range columns { - schema += fmt.Sprintf("`%s` %s, ", column.name, column.fieldType) - values1 += column.valuesIn[0] + ", " - values2 += column.valuesIn[1] + ", " - values3 += column.valuesIn[2] + ", " - } - schema = schema[:len(schema)-2] - values1 = values1[:len(values1)-2] - values2 = values2[:len(values2)-2] - values3 = values3[:len(values3)-2] - - runTests(t, dsn+"&parseTime=true", func(dbt *DBTest) { - dbt.mustExec("CREATE TABLE test (" + schema + ")") - dbt.mustExec("INSERT INTO test VALUES (" + values1 + "), (" + values2 + "), (" + values3 + ")") - - rows, err := dbt.db.Query("SELECT * FROM test") - if err != nil { - t.Fatalf("Query: %v", err) - } - - tt, err := rows.ColumnTypes() - if err != nil { - t.Fatalf("ColumnTypes: %v", err) - } - - if len(tt) != len(columns) { - t.Fatalf("unexpected number of columns: expected %d, got %d", len(columns), len(tt)) - } - - types := make([]reflect.Type, len(tt)) - for i, tp := range tt { - column := columns[i] - - // Name - name := tp.Name() - if name != column.name { - t.Errorf("column name mismatch %s != %s", name, column.name) - continue - } - - // DatabaseTypeName - databaseTypeName := tp.DatabaseTypeName() - if databaseTypeName != column.databaseTypeName { - t.Errorf("databasetypename name mismatch for column %q: %s != %s", name, databaseTypeName, column.databaseTypeName) - continue - } - - // ScanType - scanType := tp.ScanType() - if scanType != column.scanType { - if scanType == nil { - t.Errorf("scantype is null for column %q", name) - } else { - t.Errorf("scantype mismatch for column %q: %s != %s", name, scanType.Name(), column.scanType.Name()) - } - continue - } - types[i] = scanType - - // Nullable - nullable, ok := tp.Nullable() - if !ok { - t.Errorf("nullable not ok %q", name) - continue - } - if nullable != column.nullable { - t.Errorf("nullable mismatch for column %q: %t != %t", name, nullable, column.nullable) - } - - // Length - // length, ok := tp.Length() - // if length != column.length { - // if !ok { - // t.Errorf("length not ok for column %q", name) - // } else { - // t.Errorf("length mismatch for column %q: %d != %d", name, length, column.length) - // } - // continue - // } - - // Precision and Scale - precision, scale, ok := tp.DecimalSize() - if precision != column.precision { - if !ok { - t.Errorf("precision not ok for column %q", name) - } else { - t.Errorf("precision mismatch for column %q: %d != %d", name, precision, column.precision) - } - continue - } - if scale != column.scale { - if !ok { - t.Errorf("scale not ok for column %q", name) - } else { - t.Errorf("scale mismatch for column %q: %d != %d", name, scale, column.scale) - } - continue - } - } - - values := make([]interface{}, len(tt)) - for i := range values { - values[i] = reflect.New(types[i]).Interface() - } - i := 0 - for rows.Next() { - err = rows.Scan(values...) - if err != nil { - t.Fatalf("failed to scan values in %v", err) - } - for j := range values { - value := reflect.ValueOf(values[j]).Elem().Interface() - if !reflect.DeepEqual(value, columns[j].valuesOut[i]) { - if columns[j].scanType == scanTypeRawBytes { - t.Errorf("row %d, column %d: %v != %v", i, j, string(value.(sql.RawBytes)), string(columns[j].valuesOut[i].(sql.RawBytes))) - } else { - t.Errorf("row %d, column %d: %v != %v", i, j, value, columns[j].valuesOut[i]) - } - } - } - i++ - } - if i != 3 { - t.Errorf("expected 3 rows, got %d", i) - } - - if err := rows.Close(); err != nil { - t.Errorf("error closing rows: %s", err) - } - }) -} - -func TestValuerWithValueReceiverGivenNilValue(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { - dbt.mustExec("CREATE TABLE test (value VARCHAR(255))") - dbt.db.Exec("INSERT INTO test VALUES (?)", (*testValuer)(nil)) - // This test will panic on the INSERT if ConvertValue() does not check for typed nil before calling Value() - }) -} - -// TestRawBytesAreNotModified checks for a race condition that arises when a query context -// is canceled while a user is calling rows.Scan. This is a more stringent test than the one -// proposed in https://github.com/golang/go/issues/23519. Here we're explicitly using -// `sql.RawBytes` to check the contents of our internal buffers are not modified after an implicit -// call to `Rows.Close`, so Context cancellation should **not** invalidate the backing buffers. -func TestRawBytesAreNotModified(t *testing.T) { - const blob = "abcdefghijklmnop" - const contextRaceIterations = 20 - const blobSize = defaultBufSize * 3 / 4 // Second row overwrites first row. - const insertRows = 4 - - var sqlBlobs = [2]string{ - strings.Repeat(blob, blobSize/len(blob)), - strings.Repeat(strings.ToUpper(blob), blobSize/len(blob)), - } - - runTests(t, dsn, func(dbt *DBTest) { - dbt.mustExec("CREATE TABLE test (id int, value BLOB) CHARACTER SET utf8") - for i := 0; i < insertRows; i++ { - dbt.mustExec("INSERT INTO test VALUES (?, ?)", i+1, sqlBlobs[i&1]) - } - - for i := 0; i < contextRaceIterations; i++ { - func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - rows, err := dbt.db.QueryContext(ctx, `SELECT id, value FROM test`) - if err != nil { - t.Fatal(err) - } - - var b int - var raw sql.RawBytes - for rows.Next() { - if err := rows.Scan(&b, &raw); err != nil { - t.Fatal(err) - } - - before := string(raw) - // Ensure cancelling the query does not corrupt the contents of `raw` - cancel() - time.Sleep(time.Microsecond * 100) - after := string(raw) - - if before != after { - t.Fatalf("the backing storage for sql.RawBytes has been modified (i=%v)", i) - } - } - rows.Close() - }() - } - }) -} - -var _ driver.DriverContext = &MySQLDriver{} - -type dialCtxKey struct{} - -func TestConnectorObeysDialTimeouts(t *testing.T) { - if !available { - t.Skipf("MySQL server not running on %s", netAddr) - } - - RegisterDialContext("dialctxtest", func(ctx context.Context, addr string) (net.Conn, error) { - var d net.Dialer - if !ctx.Value(dialCtxKey{}).(bool) { - return nil, fmt.Errorf("test error: query context is not propagated to our dialer") - } - return d.DialContext(ctx, prot, addr) - }) - - db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@dialctxtest(%s)/%s?timeout=30s", user, pass, addr, dbname)) - if err != nil { - t.Fatalf("error connecting: %s", err.Error()) - } - defer db.Close() - - ctx := context.WithValue(context.Background(), dialCtxKey{}, true) - - _, err = db.ExecContext(ctx, "DO 1") - if err != nil { - t.Fatal(err) - } -} - -func configForTests(t *testing.T) *Config { - if !available { - t.Skipf("MySQL server not running on %s", netAddr) - } - - mycnf := NewConfig() - mycnf.User = user - mycnf.Passwd = pass - mycnf.Addr = addr - mycnf.Net = prot - mycnf.DBName = dbname - return mycnf -} - -func TestNewConnector(t *testing.T) { - mycnf := configForTests(t) - conn, err := NewConnector(mycnf) - if err != nil { - t.Fatal(err) - } - - db := sql.OpenDB(conn) - defer db.Close() - - if err := db.Ping(); err != nil { - t.Fatal(err) - } -} - -type slowConnection struct { - net.Conn - slowdown time.Duration -} - -func (sc *slowConnection) Read(b []byte) (int, error) { - time.Sleep(sc.slowdown) - return sc.Conn.Read(b) -} - -type connectorHijack struct { - driver.Connector - connErr error -} - -func (cw *connectorHijack) Connect(ctx context.Context) (driver.Conn, error) { - var conn driver.Conn - conn, cw.connErr = cw.Connector.Connect(ctx) - return conn, cw.connErr -} - -func TestConnectorTimeoutsDuringOpen(t *testing.T) { - RegisterDialContext("slowconn", func(ctx context.Context, addr string) (net.Conn, error) { - var d net.Dialer - conn, err := d.DialContext(ctx, prot, addr) - if err != nil { - return nil, err - } - return &slowConnection{Conn: conn, slowdown: 100 * time.Millisecond}, nil - }) - - mycnf := configForTests(t) - mycnf.Net = "slowconn" - - conn, err := NewConnector(mycnf) - if err != nil { - t.Fatal(err) - } - - hijack := &connectorHijack{Connector: conn} - - db := sql.OpenDB(hijack) - defer db.Close() - - ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) - defer cancel() - - _, err = db.ExecContext(ctx, "DO 1") - if err != context.DeadlineExceeded { - t.Fatalf("ExecContext should have timed out") - } - if hijack.connErr != context.DeadlineExceeded { - t.Fatalf("(*Connector).Connect should have timed out") - } -} - -// A connection which can only be closed. -type dummyConnection struct { - net.Conn - closed bool -} - -func (d *dummyConnection) Close() error { - d.closed = true - return nil -} - -func TestConnectorTimeoutsWatchCancel(t *testing.T) { - var ( - cancel func() // Used to cancel the context just after connecting. - created *dummyConnection // The created connection. - ) - - RegisterDialContext("TestConnectorTimeoutsWatchCancel", func(ctx context.Context, addr string) (net.Conn, error) { - // Canceling at this time triggers the watchCancel error branch in Connect(). - cancel() - created = &dummyConnection{} - return created, nil - }) - - mycnf := NewConfig() - mycnf.User = "root" - mycnf.Addr = "foo" - mycnf.Net = "TestConnectorTimeoutsWatchCancel" - - conn, err := NewConnector(mycnf) - if err != nil { - t.Fatal(err) - } - - db := sql.OpenDB(conn) - defer db.Close() - - var ctx context.Context - ctx, cancel = context.WithCancel(context.Background()) - defer cancel() - - if _, err := db.Conn(ctx); err != context.Canceled { - t.Errorf("got %v, want context.Canceled", err) - } - - if created == nil { - t.Fatal("no connection created") - } - if !created.closed { - t.Errorf("connection not closed") - } -} diff --git a/proxy_go/public/mysql@v1.6.0/dsn.go b/proxy_go/public/mysql@v1.6.0/dsn.go deleted file mode 100644 index 93f3548..0000000 --- a/proxy_go/public/mysql@v1.6.0/dsn.go +++ /dev/null @@ -1,560 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2016 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "bytes" - "crypto/rsa" - "crypto/tls" - "errors" - "fmt" - "math/big" - "net" - "net/url" - "sort" - "strconv" - "strings" - "time" -) - -var ( - errInvalidDSNUnescaped = errors.New("invalid DSN: did you forget to escape a param value?") - errInvalidDSNAddr = errors.New("invalid DSN: network address not terminated (missing closing brace)") - errInvalidDSNNoSlash = errors.New("invalid DSN: missing the slash separating the database name") - errInvalidDSNUnsafeCollation = errors.New("invalid DSN: interpolateParams can not be used with unsafe collations") -) - -// Config is a configuration parsed from a DSN string. -// If a new Config is created instead of being parsed from a DSN string, -// the NewConfig function should be used, which sets default values. -type Config struct { - User string // Username - Passwd string // Password (requires User) - Net string // Network type - Addr string // Network address (requires Net) - DBName string // Database name - Params map[string]string // Connection parameters - Collation string // Connection collation - Loc *time.Location // Location for time.Time values - MaxAllowedPacket int // Max packet size allowed - ServerPubKey string // Server public key name - pubKey *rsa.PublicKey // Server public key - TLSConfig string // TLS configuration name - tls *tls.Config // TLS configuration - Timeout time.Duration // Dial timeout - ReadTimeout time.Duration // I/O read timeout - WriteTimeout time.Duration // I/O write timeout - - AllowAllFiles bool // Allow all files to be used with LOAD DATA LOCAL INFILE - AllowCleartextPasswords bool // Allows the cleartext client side plugin - AllowNativePasswords bool // Allows the native password authentication method - AllowOldPasswords bool // Allows the old insecure password method - CheckConnLiveness bool // Check connections for liveness before using them - ClientFoundRows bool // Return number of matching rows instead of rows changed - ColumnsWithAlias bool // Prepend table alias to column names - InterpolateParams bool // Interpolate placeholders into query string - MultiStatements bool // Allow multiple statements in one query - ParseTime bool // Parse time values to time.Time - RejectReadOnly bool // Reject read-only connections -} - -// NewConfig creates a new Config and sets default values. -func NewConfig() *Config { - return &Config{ - Collation: defaultCollation, - Loc: time.UTC, - MaxAllowedPacket: defaultMaxAllowedPacket, - AllowNativePasswords: true, - CheckConnLiveness: true, - } -} - -func (cfg *Config) Clone() *Config { - cp := *cfg - if cp.tls != nil { - cp.tls = cfg.tls.Clone() - } - if len(cp.Params) > 0 { - cp.Params = make(map[string]string, len(cfg.Params)) - for k, v := range cfg.Params { - cp.Params[k] = v - } - } - if cfg.pubKey != nil { - cp.pubKey = &rsa.PublicKey{ - N: new(big.Int).Set(cfg.pubKey.N), - E: cfg.pubKey.E, - } - } - return &cp -} - -func (cfg *Config) normalize() error { - if cfg.InterpolateParams && unsafeCollations[cfg.Collation] { - return errInvalidDSNUnsafeCollation - } - - // Set default network if empty - if cfg.Net == "" { - cfg.Net = "tcp" - } - - // Set default address if empty - if cfg.Addr == "" { - switch cfg.Net { - case "tcp": - cfg.Addr = "127.0.0.1:3306" - case "unix": - cfg.Addr = "/tmp/mysql.sock" - default: - return errors.New("default addr for network '" + cfg.Net + "' unknown") - } - } else if cfg.Net == "tcp" { - cfg.Addr = ensureHavePort(cfg.Addr) - } - - switch cfg.TLSConfig { - case "false", "": - // don't set anything - case "true": - cfg.tls = &tls.Config{} - case "skip-verify", "preferred": - cfg.tls = &tls.Config{InsecureSkipVerify: true} - default: - cfg.tls = getTLSConfigClone(cfg.TLSConfig) - if cfg.tls == nil { - return errors.New("invalid value / unknown config name: " + cfg.TLSConfig) - } - } - - if cfg.tls != nil && cfg.tls.ServerName == "" && !cfg.tls.InsecureSkipVerify { - host, _, err := net.SplitHostPort(cfg.Addr) - if err == nil { - cfg.tls.ServerName = host - } - } - - if cfg.ServerPubKey != "" { - cfg.pubKey = getServerPubKey(cfg.ServerPubKey) - if cfg.pubKey == nil { - return errors.New("invalid value / unknown server pub key name: " + cfg.ServerPubKey) - } - } - - return nil -} - -func writeDSNParam(buf *bytes.Buffer, hasParam *bool, name, value string) { - buf.Grow(1 + len(name) + 1 + len(value)) - if !*hasParam { - *hasParam = true - buf.WriteByte('?') - } else { - buf.WriteByte('&') - } - buf.WriteString(name) - buf.WriteByte('=') - buf.WriteString(value) -} - -// FormatDSN formats the given Config into a DSN string which can be passed to -// the driver. -func (cfg *Config) FormatDSN() string { - var buf bytes.Buffer - - // [username[:password]@] - if len(cfg.User) > 0 { - buf.WriteString(cfg.User) - if len(cfg.Passwd) > 0 { - buf.WriteByte(':') - buf.WriteString(cfg.Passwd) - } - buf.WriteByte('@') - } - - // [protocol[(address)]] - if len(cfg.Net) > 0 { - buf.WriteString(cfg.Net) - if len(cfg.Addr) > 0 { - buf.WriteByte('(') - buf.WriteString(cfg.Addr) - buf.WriteByte(')') - } - } - - // /dbname - buf.WriteByte('/') - buf.WriteString(cfg.DBName) - - // [?param1=value1&...¶mN=valueN] - hasParam := false - - if cfg.AllowAllFiles { - hasParam = true - buf.WriteString("?allowAllFiles=true") - } - - if cfg.AllowCleartextPasswords { - writeDSNParam(&buf, &hasParam, "allowCleartextPasswords", "true") - } - - if !cfg.AllowNativePasswords { - writeDSNParam(&buf, &hasParam, "allowNativePasswords", "false") - } - - if cfg.AllowOldPasswords { - writeDSNParam(&buf, &hasParam, "allowOldPasswords", "true") - } - - if !cfg.CheckConnLiveness { - writeDSNParam(&buf, &hasParam, "checkConnLiveness", "false") - } - - if cfg.ClientFoundRows { - writeDSNParam(&buf, &hasParam, "clientFoundRows", "true") - } - - if col := cfg.Collation; col != defaultCollation && len(col) > 0 { - writeDSNParam(&buf, &hasParam, "collation", col) - } - - if cfg.ColumnsWithAlias { - writeDSNParam(&buf, &hasParam, "columnsWithAlias", "true") - } - - if cfg.InterpolateParams { - writeDSNParam(&buf, &hasParam, "interpolateParams", "true") - } - - if cfg.Loc != time.UTC && cfg.Loc != nil { - writeDSNParam(&buf, &hasParam, "loc", url.QueryEscape(cfg.Loc.String())) - } - - if cfg.MultiStatements { - writeDSNParam(&buf, &hasParam, "multiStatements", "true") - } - - if cfg.ParseTime { - writeDSNParam(&buf, &hasParam, "parseTime", "true") - } - - if cfg.ReadTimeout > 0 { - writeDSNParam(&buf, &hasParam, "readTimeout", cfg.ReadTimeout.String()) - } - - if cfg.RejectReadOnly { - writeDSNParam(&buf, &hasParam, "rejectReadOnly", "true") - } - - if len(cfg.ServerPubKey) > 0 { - writeDSNParam(&buf, &hasParam, "serverPubKey", url.QueryEscape(cfg.ServerPubKey)) - } - - if cfg.Timeout > 0 { - writeDSNParam(&buf, &hasParam, "timeout", cfg.Timeout.String()) - } - - if len(cfg.TLSConfig) > 0 { - writeDSNParam(&buf, &hasParam, "tls", url.QueryEscape(cfg.TLSConfig)) - } - - if cfg.WriteTimeout > 0 { - writeDSNParam(&buf, &hasParam, "writeTimeout", cfg.WriteTimeout.String()) - } - - if cfg.MaxAllowedPacket != defaultMaxAllowedPacket { - writeDSNParam(&buf, &hasParam, "maxAllowedPacket", strconv.Itoa(cfg.MaxAllowedPacket)) - } - - // other params - if cfg.Params != nil { - var params []string - for param := range cfg.Params { - params = append(params, param) - } - sort.Strings(params) - for _, param := range params { - writeDSNParam(&buf, &hasParam, param, url.QueryEscape(cfg.Params[param])) - } - } - - return buf.String() -} - -// ParseDSN parses the DSN string to a Config -func ParseDSN(dsn string) (cfg *Config, err error) { - // New config with some default values - cfg = NewConfig() - - // [user[:password]@][net[(addr)]]/dbname[?param1=value1¶mN=valueN] - // Find the last '/' (since the password or the net addr might contain a '/') - foundSlash := false - for i := len(dsn) - 1; i >= 0; i-- { - if dsn[i] == '/' { - foundSlash = true - var j, k int - - // left part is empty if i <= 0 - if i > 0 { - // [username[:password]@][protocol[(address)]] - // Find the last '@' in dsn[:i] - for j = i; j >= 0; j-- { - if dsn[j] == '@' { - // username[:password] - // Find the first ':' in dsn[:j] - for k = 0; k < j; k++ { - if dsn[k] == ':' { - cfg.Passwd = dsn[k+1 : j] - break - } - } - cfg.User = dsn[:k] - - break - } - } - - // [protocol[(address)]] - // Find the first '(' in dsn[j+1:i] - for k = j + 1; k < i; k++ { - if dsn[k] == '(' { - // dsn[i-1] must be == ')' if an address is specified - if dsn[i-1] != ')' { - if strings.ContainsRune(dsn[k+1:i], ')') { - return nil, errInvalidDSNUnescaped - } - return nil, errInvalidDSNAddr - } - cfg.Addr = dsn[k+1 : i-1] - break - } - } - cfg.Net = dsn[j+1 : k] - } - - // dbname[?param1=value1&...¶mN=valueN] - // Find the first '?' in dsn[i+1:] - for j = i + 1; j < len(dsn); j++ { - if dsn[j] == '?' { - if err = parseDSNParams(cfg, dsn[j+1:]); err != nil { - return - } - break - } - } - cfg.DBName = dsn[i+1 : j] - - break - } - } - - if !foundSlash && len(dsn) > 0 { - return nil, errInvalidDSNNoSlash - } - - if err = cfg.normalize(); err != nil { - return nil, err - } - return -} - -// parseDSNParams parses the DSN "query string" -// Values must be url.QueryEscape'ed -func parseDSNParams(cfg *Config, params string) (err error) { - for _, v := range strings.Split(params, "&") { - param := strings.SplitN(v, "=", 2) - if len(param) != 2 { - continue - } - - // cfg params - switch value := param[1]; param[0] { - // Disable INFILE allowlist / enable all files - case "allowAllFiles": - var isBool bool - cfg.AllowAllFiles, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Use cleartext authentication mode (MySQL 5.5.10+) - case "allowCleartextPasswords": - var isBool bool - cfg.AllowCleartextPasswords, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Use native password authentication - case "allowNativePasswords": - var isBool bool - cfg.AllowNativePasswords, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Use old authentication mode (pre MySQL 4.1) - case "allowOldPasswords": - var isBool bool - cfg.AllowOldPasswords, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Check connections for Liveness before using them - case "checkConnLiveness": - var isBool bool - cfg.CheckConnLiveness, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Switch "rowsAffected" mode - case "clientFoundRows": - var isBool bool - cfg.ClientFoundRows, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Collation - case "collation": - cfg.Collation = value - break - - case "columnsWithAlias": - var isBool bool - cfg.ColumnsWithAlias, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Compression - case "compress": - return errors.New("compression not implemented yet") - - // Enable client side placeholder substitution - case "interpolateParams": - var isBool bool - cfg.InterpolateParams, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Time Location - case "loc": - if value, err = url.QueryUnescape(value); err != nil { - return - } - cfg.Loc, err = time.LoadLocation(value) - if err != nil { - return - } - - // multiple statements in one query - case "multiStatements": - var isBool bool - cfg.MultiStatements, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // time.Time parsing - case "parseTime": - var isBool bool - cfg.ParseTime, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // I/O read Timeout - case "readTimeout": - cfg.ReadTimeout, err = time.ParseDuration(value) - if err != nil { - return - } - - // Reject read-only connections - case "rejectReadOnly": - var isBool bool - cfg.RejectReadOnly, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Server public key - case "serverPubKey": - name, err := url.QueryUnescape(value) - if err != nil { - return fmt.Errorf("invalid value for server pub key name: %v", err) - } - cfg.ServerPubKey = name - - // Strict mode - case "strict": - panic("strict mode has been removed. See https://github.com/go-sql-driver/mysql/wiki/strict-mode") - - // Dial Timeout - case "timeout": - cfg.Timeout, err = time.ParseDuration(value) - if err != nil { - return - } - - // TLS-Encryption - case "tls": - boolValue, isBool := readBool(value) - if isBool { - if boolValue { - cfg.TLSConfig = "true" - } else { - cfg.TLSConfig = "false" - } - } else if vl := strings.ToLower(value); vl == "skip-verify" || vl == "preferred" { - cfg.TLSConfig = vl - } else { - name, err := url.QueryUnescape(value) - if err != nil { - return fmt.Errorf("invalid value for TLS config name: %v", err) - } - cfg.TLSConfig = name - } - - // I/O write Timeout - case "writeTimeout": - cfg.WriteTimeout, err = time.ParseDuration(value) - if err != nil { - return - } - case "maxAllowedPacket": - cfg.MaxAllowedPacket, err = strconv.Atoi(value) - if err != nil { - return - } - default: - // lazy init - if cfg.Params == nil { - cfg.Params = make(map[string]string) - } - - if cfg.Params[param[0]], err = url.QueryUnescape(value); err != nil { - return - } - } - } - - return -} - -func ensureHavePort(addr string) string { - if _, _, err := net.SplitHostPort(addr); err != nil { - return net.JoinHostPort(addr, "3306") - } - return addr -} diff --git a/proxy_go/public/mysql@v1.6.0/dsn_test.go b/proxy_go/public/mysql@v1.6.0/dsn_test.go deleted file mode 100644 index 89815b3..0000000 --- a/proxy_go/public/mysql@v1.6.0/dsn_test.go +++ /dev/null @@ -1,415 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2016 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "crypto/tls" - "fmt" - "net/url" - "reflect" - "testing" - "time" -) - -var testDSNs = []struct { - in string - out *Config -}{{ - "username:password@protocol(address)/dbname?param=value", - &Config{User: "username", Passwd: "password", Net: "protocol", Addr: "address", DBName: "dbname", Params: map[string]string{"param": "value"}, Collation: "utf8mb4_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, CheckConnLiveness: true}, -}, { - "username:password@protocol(address)/dbname?param=value&columnsWithAlias=true", - &Config{User: "username", Passwd: "password", Net: "protocol", Addr: "address", DBName: "dbname", Params: map[string]string{"param": "value"}, Collation: "utf8mb4_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, CheckConnLiveness: true, ColumnsWithAlias: true}, -}, { - "username:password@protocol(address)/dbname?param=value&columnsWithAlias=true&multiStatements=true", - &Config{User: "username", Passwd: "password", Net: "protocol", Addr: "address", DBName: "dbname", Params: map[string]string{"param": "value"}, Collation: "utf8mb4_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, CheckConnLiveness: true, ColumnsWithAlias: true, MultiStatements: true}, -}, { - "user@unix(/path/to/socket)/dbname?charset=utf8", - &Config{User: "user", Net: "unix", Addr: "/path/to/socket", DBName: "dbname", Params: map[string]string{"charset": "utf8"}, Collation: "utf8mb4_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, CheckConnLiveness: true}, -}, { - "user:password@tcp(localhost:5555)/dbname?charset=utf8&tls=true", - &Config{User: "user", Passwd: "password", Net: "tcp", Addr: "localhost:5555", DBName: "dbname", Params: map[string]string{"charset": "utf8"}, Collation: "utf8mb4_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, CheckConnLiveness: true, TLSConfig: "true"}, -}, { - "user:password@tcp(localhost:5555)/dbname?charset=utf8mb4,utf8&tls=skip-verify", - &Config{User: "user", Passwd: "password", Net: "tcp", Addr: "localhost:5555", DBName: "dbname", Params: map[string]string{"charset": "utf8mb4,utf8"}, Collation: "utf8mb4_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, CheckConnLiveness: true, TLSConfig: "skip-verify"}, -}, { - "user:password@/dbname?loc=UTC&timeout=30s&readTimeout=1s&writeTimeout=1s&allowAllFiles=1&clientFoundRows=true&allowOldPasswords=TRUE&collation=utf8mb4_unicode_ci&maxAllowedPacket=16777216&tls=false&allowCleartextPasswords=true&parseTime=true&rejectReadOnly=true", - &Config{User: "user", Passwd: "password", Net: "tcp", Addr: "127.0.0.1:3306", DBName: "dbname", Collation: "utf8mb4_unicode_ci", Loc: time.UTC, TLSConfig: "false", AllowCleartextPasswords: true, AllowNativePasswords: true, Timeout: 30 * time.Second, ReadTimeout: time.Second, WriteTimeout: time.Second, AllowAllFiles: true, AllowOldPasswords: true, CheckConnLiveness: true, ClientFoundRows: true, MaxAllowedPacket: 16777216, ParseTime: true, RejectReadOnly: true}, -}, { - "user:password@/dbname?allowNativePasswords=false&checkConnLiveness=false&maxAllowedPacket=0", - &Config{User: "user", Passwd: "password", Net: "tcp", Addr: "127.0.0.1:3306", DBName: "dbname", Collation: "utf8mb4_general_ci", Loc: time.UTC, MaxAllowedPacket: 0, AllowNativePasswords: false, CheckConnLiveness: false}, -}, { - "user:p@ss(word)@tcp([de:ad:be:ef::ca:fe]:80)/dbname?loc=Local", - &Config{User: "user", Passwd: "p@ss(word)", Net: "tcp", Addr: "[de:ad:be:ef::ca:fe]:80", DBName: "dbname", Collation: "utf8mb4_general_ci", Loc: time.Local, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, CheckConnLiveness: true}, -}, { - "/dbname", - &Config{Net: "tcp", Addr: "127.0.0.1:3306", DBName: "dbname", Collation: "utf8mb4_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, CheckConnLiveness: true}, -}, { - "@/", - &Config{Net: "tcp", Addr: "127.0.0.1:3306", Collation: "utf8mb4_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, CheckConnLiveness: true}, -}, { - "/", - &Config{Net: "tcp", Addr: "127.0.0.1:3306", Collation: "utf8mb4_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, CheckConnLiveness: true}, -}, { - "", - &Config{Net: "tcp", Addr: "127.0.0.1:3306", Collation: "utf8mb4_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, CheckConnLiveness: true}, -}, { - "user:p@/ssword@/", - &Config{User: "user", Passwd: "p@/ssword", Net: "tcp", Addr: "127.0.0.1:3306", Collation: "utf8mb4_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, CheckConnLiveness: true}, -}, { - "unix/?arg=%2Fsome%2Fpath.ext", - &Config{Net: "unix", Addr: "/tmp/mysql.sock", Params: map[string]string{"arg": "/some/path.ext"}, Collation: "utf8mb4_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, CheckConnLiveness: true}, -}, { - "tcp(127.0.0.1)/dbname", - &Config{Net: "tcp", Addr: "127.0.0.1:3306", DBName: "dbname", Collation: "utf8mb4_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, CheckConnLiveness: true}, -}, { - "tcp(de:ad:be:ef::ca:fe)/dbname", - &Config{Net: "tcp", Addr: "[de:ad:be:ef::ca:fe]:3306", DBName: "dbname", Collation: "utf8mb4_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, CheckConnLiveness: true}, -}, -} - -func TestDSNParser(t *testing.T) { - for i, tst := range testDSNs { - cfg, err := ParseDSN(tst.in) - if err != nil { - t.Error(err.Error()) - } - - // pointer not static - cfg.tls = nil - - if !reflect.DeepEqual(cfg, tst.out) { - t.Errorf("%d. ParseDSN(%q) mismatch:\ngot %+v\nwant %+v", i, tst.in, cfg, tst.out) - } - } -} - -func TestDSNParserInvalid(t *testing.T) { - var invalidDSNs = []string{ - "@net(addr/", // no closing brace - "@tcp(/", // no closing brace - "tcp(/", // no closing brace - "(/", // no closing brace - "net(addr)//", // unescaped - "User:pass@tcp(1.2.3.4:3306)", // no trailing slash - "net()/", // unknown default addr - //"/dbname?arg=/some/unescaped/path", - } - - for i, tst := range invalidDSNs { - if _, err := ParseDSN(tst); err == nil { - t.Errorf("invalid DSN #%d. (%s) didn't error!", i, tst) - } - } -} - -func TestDSNReformat(t *testing.T) { - for i, tst := range testDSNs { - dsn1 := tst.in - cfg1, err := ParseDSN(dsn1) - if err != nil { - t.Error(err.Error()) - continue - } - cfg1.tls = nil // pointer not static - res1 := fmt.Sprintf("%+v", cfg1) - - dsn2 := cfg1.FormatDSN() - cfg2, err := ParseDSN(dsn2) - if err != nil { - t.Error(err.Error()) - continue - } - cfg2.tls = nil // pointer not static - res2 := fmt.Sprintf("%+v", cfg2) - - if res1 != res2 { - t.Errorf("%d. %q does not match %q", i, res2, res1) - } - } -} - -func TestDSNServerPubKey(t *testing.T) { - baseDSN := "User:password@tcp(localhost:5555)/dbname?serverPubKey=" - - RegisterServerPubKey("testKey", testPubKeyRSA) - defer DeregisterServerPubKey("testKey") - - tst := baseDSN + "testKey" - cfg, err := ParseDSN(tst) - if err != nil { - t.Error(err.Error()) - } - - if cfg.ServerPubKey != "testKey" { - t.Errorf("unexpected cfg.ServerPubKey value: %v", cfg.ServerPubKey) - } - if cfg.pubKey != testPubKeyRSA { - t.Error("pub key pointer doesn't match") - } - - // Key is missing - tst = baseDSN + "invalid_name" - cfg, err = ParseDSN(tst) - if err == nil { - t.Errorf("invalid name in DSN (%s) but did not error. Got config: %#v", tst, cfg) - } -} - -func TestDSNServerPubKeyQueryEscape(t *testing.T) { - const name = "&%!:" - dsn := "User:password@tcp(localhost:5555)/dbname?serverPubKey=" + url.QueryEscape(name) - - RegisterServerPubKey(name, testPubKeyRSA) - defer DeregisterServerPubKey(name) - - cfg, err := ParseDSN(dsn) - if err != nil { - t.Error(err.Error()) - } - - if cfg.pubKey != testPubKeyRSA { - t.Error("pub key pointer doesn't match") - } -} - -func TestDSNWithCustomTLS(t *testing.T) { - baseDSN := "User:password@tcp(localhost:5555)/dbname?tls=" - tlsCfg := tls.Config{} - - RegisterTLSConfig("utils_test", &tlsCfg) - defer DeregisterTLSConfig("utils_test") - - // Custom TLS is missing - tst := baseDSN + "invalid_tls" - cfg, err := ParseDSN(tst) - if err == nil { - t.Errorf("invalid custom TLS in DSN (%s) but did not error. Got config: %#v", tst, cfg) - } - - tst = baseDSN + "utils_test" - - // Custom TLS with a server name - name := "foohost" - tlsCfg.ServerName = name - cfg, err = ParseDSN(tst) - - if err != nil { - t.Error(err.Error()) - } else if cfg.tls.ServerName != name { - t.Errorf("did not get the correct TLS ServerName (%s) parsing DSN (%s).", name, tst) - } - - // Custom TLS without a server name - name = "localhost" - tlsCfg.ServerName = "" - cfg, err = ParseDSN(tst) - - if err != nil { - t.Error(err.Error()) - } else if cfg.tls.ServerName != name { - t.Errorf("did not get the correct ServerName (%s) parsing DSN (%s).", name, tst) - } else if tlsCfg.ServerName != "" { - t.Errorf("tlsCfg was mutated ServerName (%s) should be empty parsing DSN (%s).", name, tst) - } -} - -func TestDSNTLSConfig(t *testing.T) { - expectedServerName := "example.com" - dsn := "tcp(example.com:1234)/?tls=true" - - cfg, err := ParseDSN(dsn) - if err != nil { - t.Error(err.Error()) - } - if cfg.tls == nil { - t.Error("cfg.tls should not be nil") - } - if cfg.tls.ServerName != expectedServerName { - t.Errorf("cfg.tls.ServerName should be %q, got %q (host with port)", expectedServerName, cfg.tls.ServerName) - } - - dsn = "tcp(example.com)/?tls=true" - cfg, err = ParseDSN(dsn) - if err != nil { - t.Error(err.Error()) - } - if cfg.tls == nil { - t.Error("cfg.tls should not be nil") - } - if cfg.tls.ServerName != expectedServerName { - t.Errorf("cfg.tls.ServerName should be %q, got %q (host without port)", expectedServerName, cfg.tls.ServerName) - } -} - -func TestDSNWithCustomTLSQueryEscape(t *testing.T) { - const configKey = "&%!:" - dsn := "User:password@tcp(localhost:5555)/dbname?tls=" + url.QueryEscape(configKey) - name := "foohost" - tlsCfg := tls.Config{ServerName: name} - - RegisterTLSConfig(configKey, &tlsCfg) - defer DeregisterTLSConfig(configKey) - - cfg, err := ParseDSN(dsn) - - if err != nil { - t.Error(err.Error()) - } else if cfg.tls.ServerName != name { - t.Errorf("did not get the correct TLS ServerName (%s) parsing DSN (%s).", name, dsn) - } -} - -func TestDSNUnsafeCollation(t *testing.T) { - _, err := ParseDSN("/dbname?collation=gbk_chinese_ci&interpolateParams=true") - if err != errInvalidDSNUnsafeCollation { - t.Errorf("expected %v, got %v", errInvalidDSNUnsafeCollation, err) - } - - _, err = ParseDSN("/dbname?collation=gbk_chinese_ci&interpolateParams=false") - if err != nil { - t.Errorf("expected %v, got %v", nil, err) - } - - _, err = ParseDSN("/dbname?collation=gbk_chinese_ci") - if err != nil { - t.Errorf("expected %v, got %v", nil, err) - } - - _, err = ParseDSN("/dbname?collation=ascii_bin&interpolateParams=true") - if err != nil { - t.Errorf("expected %v, got %v", nil, err) - } - - _, err = ParseDSN("/dbname?collation=latin1_german1_ci&interpolateParams=true") - if err != nil { - t.Errorf("expected %v, got %v", nil, err) - } - - _, err = ParseDSN("/dbname?collation=utf8_general_ci&interpolateParams=true") - if err != nil { - t.Errorf("expected %v, got %v", nil, err) - } - - _, err = ParseDSN("/dbname?collation=utf8mb4_general_ci&interpolateParams=true") - if err != nil { - t.Errorf("expected %v, got %v", nil, err) - } -} - -func TestParamsAreSorted(t *testing.T) { - expected := "/dbname?interpolateParams=true&foobar=baz&quux=loo" - cfg := NewConfig() - cfg.DBName = "dbname" - cfg.InterpolateParams = true - cfg.Params = map[string]string{ - "quux": "loo", - "foobar": "baz", - } - actual := cfg.FormatDSN() - if actual != expected { - t.Errorf("generic Config.Params were not sorted: want %#v, got %#v", expected, actual) - } -} - -func TestCloneConfig(t *testing.T) { - RegisterServerPubKey("testKey", testPubKeyRSA) - defer DeregisterServerPubKey("testKey") - - expectedServerName := "example.com" - dsn := "tcp(example.com:1234)/?tls=true&foobar=baz&serverPubKey=testKey" - cfg, err := ParseDSN(dsn) - if err != nil { - t.Fatal(err.Error()) - } - - cfg2 := cfg.Clone() - if cfg == cfg2 { - t.Errorf("Config.Clone did not create a separate config struct") - } - - if cfg2.tls.ServerName != expectedServerName { - t.Errorf("cfg.tls.ServerName should be %q, got %q (host with port)", expectedServerName, cfg.tls.ServerName) - } - - cfg2.tls.ServerName = "example2.com" - if cfg.tls.ServerName == cfg2.tls.ServerName { - t.Errorf("changed cfg.tls.Server name should not propagate to original Config") - } - - if _, ok := cfg2.Params["foobar"]; !ok { - t.Errorf("cloned Config is missing custom params") - } - - delete(cfg2.Params, "foobar") - - if _, ok := cfg.Params["foobar"]; !ok { - t.Errorf("custom params in cloned Config should not propagate to original Config") - } - - if !reflect.DeepEqual(cfg.pubKey, cfg2.pubKey) { - t.Errorf("public key in Config should be identical") - } -} - -func TestNormalizeTLSConfig(t *testing.T) { - tt := []struct { - tlsConfig string - want *tls.Config - }{ - {"", nil}, - {"false", nil}, - {"true", &tls.Config{ServerName: "myserver"}}, - {"skip-verify", &tls.Config{InsecureSkipVerify: true}}, - {"preferred", &tls.Config{InsecureSkipVerify: true}}, - {"test_tls_config", &tls.Config{ServerName: "myServerName"}}, - } - - RegisterTLSConfig("test_tls_config", &tls.Config{ServerName: "myServerName"}) - defer func() { DeregisterTLSConfig("test_tls_config") }() - - for _, tc := range tt { - t.Run(tc.tlsConfig, func(t *testing.T) { - cfg := &Config{ - Addr: "myserver:3306", - TLSConfig: tc.tlsConfig, - } - - cfg.normalize() - - if cfg.tls == nil { - if tc.want != nil { - t.Fatal("wanted a tls config but got nil instead") - } - return - } - - if cfg.tls.ServerName != tc.want.ServerName { - t.Errorf("tls.ServerName doesn't match (want: '%s', got: '%s')", - tc.want.ServerName, cfg.tls.ServerName) - } - if cfg.tls.InsecureSkipVerify != tc.want.InsecureSkipVerify { - t.Errorf("tls.InsecureSkipVerify doesn't match (want: %T, got :%T)", - tc.want.InsecureSkipVerify, cfg.tls.InsecureSkipVerify) - } - }) - } -} - -func BenchmarkParseDSN(b *testing.B) { - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - for _, tst := range testDSNs { - if _, err := ParseDSN(tst.in); err != nil { - b.Error(err.Error()) - } - } - } -} diff --git a/proxy_go/public/mysql@v1.6.0/errors.go b/proxy_go/public/mysql@v1.6.0/errors.go deleted file mode 100644 index 760782f..0000000 --- a/proxy_go/public/mysql@v1.6.0/errors.go +++ /dev/null @@ -1,65 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "errors" - "fmt" - "log" - "os" -) - -// Various errors the driver might return. Can change between driver versions. -var ( - ErrInvalidConn = errors.New("invalid connection") - ErrMalformPkt = errors.New("malformed packet") - ErrNoTLS = errors.New("TLS requested but server does not support TLS") - ErrCleartextPassword = errors.New("this user requires clear text authentication. If you still want to use it, please add 'allowCleartextPasswords=1' to your DSN") - ErrNativePassword = errors.New("this user requires mysql native password authentication.") - ErrOldPassword = errors.New("this user requires old password authentication. If you still want to use it, please add 'allowOldPasswords=1' to your DSN. See also https://github.com/go-sql-driver/mysql/wiki/old_passwords") - ErrUnknownPlugin = errors.New("this authentication plugin is not supported") - ErrOldProtocol = errors.New("MySQL server does not support required protocol 41+") - ErrPktSync = errors.New("commands out of sync. You can't run this command now") - ErrPktSyncMul = errors.New("commands out of sync. Did you run multiple statements at once?") - ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server") - ErrBusyBuffer = errors.New("busy buffer") - - // errBadConnNoWrite is used for connection errors where nothing was sent to the database yet. - // If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn - // to trigger a resend. - // See https://github.com/go-sql-driver/mysql/pull/302 - errBadConnNoWrite = errors.New("bad connection") -) - -var errLog = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime|log.Lshortfile)) - -// Logger is used to log critical error messages. -type Logger interface { - Print(v ...interface{}) -} - -// SetLogger is used to set the logger for critical errors. -// The initial logger is os.Stderr. -func SetLogger(logger Logger) error { - if logger == nil { - return errors.New("logger is nil") - } - errLog = logger - return nil -} - -// MySQLError is an error type which represents a single MySQL error -type MySQLError struct { - Number uint16 - Message string -} - -func (me *MySQLError) Error() string { - return fmt.Sprintf("Error %d: %s", me.Number, me.Message) -} diff --git a/proxy_go/public/mysql@v1.6.0/errors_test.go b/proxy_go/public/mysql@v1.6.0/errors_test.go deleted file mode 100644 index 96f9126..0000000 --- a/proxy_go/public/mysql@v1.6.0/errors_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "bytes" - "log" - "testing" -) - -func TestErrorsSetLogger(t *testing.T) { - previous := errLog - defer func() { - errLog = previous - }() - - // set up logger - const expected = "prefix: test\n" - buffer := bytes.NewBuffer(make([]byte, 0, 64)) - logger := log.New(buffer, "prefix: ", 0) - - // print - SetLogger(logger) - errLog.Print("test") - - // check result - if actual := buffer.String(); actual != expected { - t.Errorf("expected %q, got %q", expected, actual) - } -} - -func TestErrorsStrictIgnoreNotes(t *testing.T) { - runTests(t, dsn+"&sql_notes=false", func(dbt *DBTest) { - dbt.mustExec("DROP TABLE IF EXISTS does_not_exist") - }) -} diff --git a/proxy_go/public/mysql@v1.6.0/fields.go b/proxy_go/public/mysql@v1.6.0/fields.go deleted file mode 100644 index ed6c7a3..0000000 --- a/proxy_go/public/mysql@v1.6.0/fields.go +++ /dev/null @@ -1,194 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "database/sql" - "reflect" -) - -func (mf *mysqlField) typeDatabaseName() string { - switch mf.fieldType { - case fieldTypeBit: - return "BIT" - case fieldTypeBLOB: - if mf.charSet != collations[binaryCollation] { - return "TEXT" - } - return "BLOB" - case fieldTypeDate: - return "DATE" - case fieldTypeDateTime: - return "DATETIME" - case fieldTypeDecimal: - return "DECIMAL" - case fieldTypeDouble: - return "DOUBLE" - case fieldTypeEnum: - return "ENUM" - case fieldTypeFloat: - return "FLOAT" - case fieldTypeGeometry: - return "GEOMETRY" - case fieldTypeInt24: - return "MEDIUMINT" - case fieldTypeJSON: - return "JSON" - case fieldTypeLong: - return "INT" - case fieldTypeLongBLOB: - if mf.charSet != collations[binaryCollation] { - return "LONGTEXT" - } - return "LONGBLOB" - case fieldTypeLongLong: - return "BIGINT" - case fieldTypeMediumBLOB: - if mf.charSet != collations[binaryCollation] { - return "MEDIUMTEXT" - } - return "MEDIUMBLOB" - case fieldTypeNewDate: - return "DATE" - case fieldTypeNewDecimal: - return "DECIMAL" - case fieldTypeNULL: - return "NULL" - case fieldTypeSet: - return "SET" - case fieldTypeShort: - return "SMALLINT" - case fieldTypeString: - if mf.charSet == collations[binaryCollation] { - return "BINARY" - } - return "CHAR" - case fieldTypeTime: - return "TIME" - case fieldTypeTimestamp: - return "TIMESTAMP" - case fieldTypeTiny: - return "TINYINT" - case fieldTypeTinyBLOB: - if mf.charSet != collations[binaryCollation] { - return "TINYTEXT" - } - return "TINYBLOB" - case fieldTypeVarChar: - if mf.charSet == collations[binaryCollation] { - return "VARBINARY" - } - return "VARCHAR" - case fieldTypeVarString: - if mf.charSet == collations[binaryCollation] { - return "VARBINARY" - } - return "VARCHAR" - case fieldTypeYear: - return "YEAR" - default: - return "" - } -} - -var ( - scanTypeFloat32 = reflect.TypeOf(float32(0)) - scanTypeFloat64 = reflect.TypeOf(float64(0)) - scanTypeInt8 = reflect.TypeOf(int8(0)) - scanTypeInt16 = reflect.TypeOf(int16(0)) - scanTypeInt32 = reflect.TypeOf(int32(0)) - scanTypeInt64 = reflect.TypeOf(int64(0)) - scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{}) - scanTypeNullInt = reflect.TypeOf(sql.NullInt64{}) - scanTypeNullTime = reflect.TypeOf(nullTime{}) - scanTypeUint8 = reflect.TypeOf(uint8(0)) - scanTypeUint16 = reflect.TypeOf(uint16(0)) - scanTypeUint32 = reflect.TypeOf(uint32(0)) - scanTypeUint64 = reflect.TypeOf(uint64(0)) - scanTypeRawBytes = reflect.TypeOf(sql.RawBytes{}) - scanTypeUnknown = reflect.TypeOf(new(interface{})) -) - -type mysqlField struct { - tableName string - name string - length uint32 - flags fieldFlag - fieldType fieldType - decimals byte - charSet uint8 -} - -func (mf *mysqlField) scanType() reflect.Type { - switch mf.fieldType { - case fieldTypeTiny: - if mf.flags&flagNotNULL != 0 { - if mf.flags&flagUnsigned != 0 { - return scanTypeUint8 - } - return scanTypeInt8 - } - return scanTypeNullInt - - case fieldTypeShort, fieldTypeYear: - if mf.flags&flagNotNULL != 0 { - if mf.flags&flagUnsigned != 0 { - return scanTypeUint16 - } - return scanTypeInt16 - } - return scanTypeNullInt - - case fieldTypeInt24, fieldTypeLong: - if mf.flags&flagNotNULL != 0 { - if mf.flags&flagUnsigned != 0 { - return scanTypeUint32 - } - return scanTypeInt32 - } - return scanTypeNullInt - - case fieldTypeLongLong: - if mf.flags&flagNotNULL != 0 { - if mf.flags&flagUnsigned != 0 { - return scanTypeUint64 - } - return scanTypeInt64 - } - return scanTypeNullInt - - case fieldTypeFloat: - if mf.flags&flagNotNULL != 0 { - return scanTypeFloat32 - } - return scanTypeNullFloat - - case fieldTypeDouble: - if mf.flags&flagNotNULL != 0 { - return scanTypeFloat64 - } - return scanTypeNullFloat - - case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar, - fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB, - fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB, - fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON, - fieldTypeTime: - return scanTypeRawBytes - - case fieldTypeDate, fieldTypeNewDate, - fieldTypeTimestamp, fieldTypeDateTime: - // NullTime is always returned for more consistent behavior as it can - // handle both cases of parseTime regardless if the field is nullable. - return scanTypeNullTime - - default: - return scanTypeUnknown - } -} diff --git a/proxy_go/public/mysql@v1.6.0/fuzz.go b/proxy_go/public/mysql@v1.6.0/fuzz.go deleted file mode 100644 index fa75adf..0000000 --- a/proxy_go/public/mysql@v1.6.0/fuzz.go +++ /dev/null @@ -1,24 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package. -// -// Copyright 2020 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -// +build gofuzz - -package mysql - -import ( - "database/sql" -) - -func Fuzz(data []byte) int { - db, err := sql.Open("mysql", string(data)) - if err != nil { - return 0 - } - db.Close() - return 1 -} diff --git a/proxy_go/public/mysql@v1.6.0/infile.go b/proxy_go/public/mysql@v1.6.0/infile.go deleted file mode 100644 index 60effdf..0000000 --- a/proxy_go/public/mysql@v1.6.0/infile.go +++ /dev/null @@ -1,182 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "fmt" - "io" - "os" - "strings" - "sync" -) - -var ( - fileRegister map[string]bool - fileRegisterLock sync.RWMutex - readerRegister map[string]func() io.Reader - readerRegisterLock sync.RWMutex -) - -// RegisterLocalFile adds the given file to the file allowlist, -// so that it can be used by "LOAD DATA LOCAL INFILE ". -// Alternatively you can allow the use of all local files with -// the DSN parameter 'allowAllFiles=true' -// -// filePath := "/home/gopher/data.csv" -// mysql.RegisterLocalFile(filePath) -// err := db.Exec("LOAD DATA LOCAL INFILE '" + filePath + "' INTO TABLE foo") -// if err != nil { -// ... -// -func RegisterLocalFile(filePath string) { - fileRegisterLock.Lock() - // lazy map init - if fileRegister == nil { - fileRegister = make(map[string]bool) - } - - fileRegister[strings.Trim(filePath, `"`)] = true - fileRegisterLock.Unlock() -} - -// DeregisterLocalFile removes the given filepath from the allowlist. -func DeregisterLocalFile(filePath string) { - fileRegisterLock.Lock() - delete(fileRegister, strings.Trim(filePath, `"`)) - fileRegisterLock.Unlock() -} - -// RegisterReaderHandler registers a handler function which is used -// to receive a io.Reader. -// The Reader can be used by "LOAD DATA LOCAL INFILE Reader::". -// If the handler returns a io.ReadCloser Close() is called when the -// request is finished. -// -// mysql.RegisterReaderHandler("data", func() io.Reader { -// var csvReader io.Reader // Some Reader that returns CSV data -// ... // Open Reader here -// return csvReader -// }) -// err := db.Exec("LOAD DATA LOCAL INFILE 'Reader::data' INTO TABLE foo") -// if err != nil { -// ... -// -func RegisterReaderHandler(name string, handler func() io.Reader) { - readerRegisterLock.Lock() - // lazy map init - if readerRegister == nil { - readerRegister = make(map[string]func() io.Reader) - } - - readerRegister[name] = handler - readerRegisterLock.Unlock() -} - -// DeregisterReaderHandler removes the ReaderHandler function with -// the given name from the registry. -func DeregisterReaderHandler(name string) { - readerRegisterLock.Lock() - delete(readerRegister, name) - readerRegisterLock.Unlock() -} - -func deferredClose(err *error, closer io.Closer) { - closeErr := closer.Close() - if *err == nil { - *err = closeErr - } -} - -func (mc *mysqlConn) handleInFileRequest(name string) (err error) { - var rdr io.Reader - var data []byte - packetSize := 16 * 1024 // 16KB is small enough for disk readahead and large enough for TCP - if mc.maxWriteSize < packetSize { - packetSize = mc.maxWriteSize - } - - if idx := strings.Index(name, "Reader::"); idx == 0 || (idx > 0 && name[idx-1] == '/') { // io.Reader - // The server might return an an absolute path. See issue #355. - name = name[idx+8:] - - readerRegisterLock.RLock() - handler, inMap := readerRegister[name] - readerRegisterLock.RUnlock() - - if inMap { - rdr = handler() - if rdr != nil { - if cl, ok := rdr.(io.Closer); ok { - defer deferredClose(&err, cl) - } - } else { - err = fmt.Errorf("Reader '%s' is ", name) - } - } else { - err = fmt.Errorf("Reader '%s' is not registered", name) - } - } else { // File - name = strings.Trim(name, `"`) - fileRegisterLock.RLock() - fr := fileRegister[name] - fileRegisterLock.RUnlock() - if mc.cfg.AllowAllFiles || fr { - var file *os.File - var fi os.FileInfo - - if file, err = os.Open(name); err == nil { - defer deferredClose(&err, file) - - // get file size - if fi, err = file.Stat(); err == nil { - rdr = file - if fileSize := int(fi.Size()); fileSize < packetSize { - packetSize = fileSize - } - } - } - } else { - err = fmt.Errorf("local file '%s' is not registered", name) - } - } - - // send content packets - // if packetSize == 0, the Reader contains no data - if err == nil && packetSize > 0 { - data := make([]byte, 4+packetSize) - var n int - for err == nil { - n, err = rdr.Read(data[4:]) - if n > 0 { - if ioErr := mc.writePacket(data[:4+n]); ioErr != nil { - return ioErr - } - } - } - if err == io.EOF { - err = nil - } - } - - // send empty packet (termination) - if data == nil { - data = make([]byte, 4) - } - if ioErr := mc.writePacket(data[:4]); ioErr != nil { - return ioErr - } - - // read OK packet - if err == nil { - return mc.readResultOK() - } - - mc.readPacket() - return err -} diff --git a/proxy_go/public/mysql@v1.6.0/nulltime.go b/proxy_go/public/mysql@v1.6.0/nulltime.go deleted file mode 100644 index 651723a..0000000 --- a/proxy_go/public/mysql@v1.6.0/nulltime.go +++ /dev/null @@ -1,50 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "database/sql/driver" - "fmt" - "time" -) - -// Scan implements the Scanner interface. -// The value type must be time.Time or string / []byte (formatted time-string), -// otherwise Scan fails. -func (nt *NullTime) Scan(value interface{}) (err error) { - if value == nil { - nt.Time, nt.Valid = time.Time{}, false - return - } - - switch v := value.(type) { - case time.Time: - nt.Time, nt.Valid = v, true - return - case []byte: - nt.Time, err = parseDateTime(v, time.UTC) - nt.Valid = (err == nil) - return - case string: - nt.Time, err = parseDateTime([]byte(v), time.UTC) - nt.Valid = (err == nil) - return - } - - nt.Valid = false - return fmt.Errorf("Can't convert %T to time.Time", value) -} - -// Value implements the driver Valuer interface. -func (nt NullTime) Value() (driver.Value, error) { - if !nt.Valid { - return nil, nil - } - return nt.Time, nil -} diff --git a/proxy_go/public/mysql@v1.6.0/nulltime_go113.go b/proxy_go/public/mysql@v1.6.0/nulltime_go113.go deleted file mode 100644 index 453b4b3..0000000 --- a/proxy_go/public/mysql@v1.6.0/nulltime_go113.go +++ /dev/null @@ -1,40 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -// +build go1.13 - -package mysql - -import ( - "database/sql" -) - -// NullTime represents a time.Time that may be NULL. -// NullTime implements the Scanner interface so -// it can be used as a scan destination: -// -// var nt NullTime -// err := db.QueryRow("SELECT time FROM foo WHERE id=?", id).Scan(&nt) -// ... -// if nt.Valid { -// // use nt.Time -// } else { -// // NULL value -// } -// -// This NullTime implementation is not driver-specific -// -// Deprecated: NullTime doesn't honor the loc DSN parameter. -// NullTime.Scan interprets a time as UTC, not the loc DSN parameter. -// Use sql.NullTime instead. -type NullTime sql.NullTime - -// for internal use. -// the mysql package uses sql.NullTime if it is available. -// if not, the package uses mysql.NullTime. -type nullTime = sql.NullTime // sql.NullTime is available diff --git a/proxy_go/public/mysql@v1.6.0/nulltime_legacy.go b/proxy_go/public/mysql@v1.6.0/nulltime_legacy.go deleted file mode 100644 index 9f7ae27..0000000 --- a/proxy_go/public/mysql@v1.6.0/nulltime_legacy.go +++ /dev/null @@ -1,39 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -// +build !go1.13 - -package mysql - -import ( - "time" -) - -// NullTime represents a time.Time that may be NULL. -// NullTime implements the Scanner interface so -// it can be used as a scan destination: -// -// var nt NullTime -// err := db.QueryRow("SELECT time FROM foo WHERE id=?", id).Scan(&nt) -// ... -// if nt.Valid { -// // use nt.Time -// } else { -// // NULL value -// } -// -// This NullTime implementation is not driver-specific -type NullTime struct { - Time time.Time - Valid bool // Valid is true if Time is not NULL -} - -// for internal use. -// the mysql package uses sql.NullTime if it is available. -// if not, the package uses mysql.NullTime. -type nullTime = NullTime // sql.NullTime is not available diff --git a/proxy_go/public/mysql@v1.6.0/nulltime_test.go b/proxy_go/public/mysql@v1.6.0/nulltime_test.go deleted file mode 100644 index a14ec06..0000000 --- a/proxy_go/public/mysql@v1.6.0/nulltime_test.go +++ /dev/null @@ -1,62 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "database/sql" - "database/sql/driver" - "testing" - "time" -) - -var ( - // Check implementation of interfaces - _ driver.Valuer = NullTime{} - _ sql.Scanner = (*NullTime)(nil) -) - -func TestScanNullTime(t *testing.T) { - var scanTests = []struct { - in interface{} - error bool - valid bool - time time.Time - }{ - {tDate, false, true, tDate}, - {sDate, false, true, tDate}, - {[]byte(sDate), false, true, tDate}, - {tDateTime, false, true, tDateTime}, - {sDateTime, false, true, tDateTime}, - {[]byte(sDateTime), false, true, tDateTime}, - {tDate0, false, true, tDate0}, - {sDate0, false, true, tDate0}, - {[]byte(sDate0), false, true, tDate0}, - {sDateTime0, false, true, tDate0}, - {[]byte(sDateTime0), false, true, tDate0}, - {"", true, false, tDate0}, - {"1234", true, false, tDate0}, - {0, true, false, tDate0}, - } - - var nt = NullTime{} - var err error - - for _, tst := range scanTests { - err = nt.Scan(tst.in) - if (err != nil) != tst.error { - t.Errorf("%v: expected error status %t, got %t", tst.in, tst.error, (err != nil)) - } - if nt.Valid != tst.valid { - t.Errorf("%v: expected valid status %t, got %t", tst.in, tst.valid, nt.Valid) - } - if nt.Time != tst.time { - t.Errorf("%v: expected time %v, got %v", tst.in, tst.time, nt.Time) - } - } -} diff --git a/proxy_go/public/mysql@v1.6.0/packets.go b/proxy_go/public/mysql@v1.6.0/packets.go deleted file mode 100644 index 6664e5a..0000000 --- a/proxy_go/public/mysql@v1.6.0/packets.go +++ /dev/null @@ -1,1349 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "bytes" - "crypto/tls" - "database/sql/driver" - "encoding/binary" - "encoding/json" - "errors" - "fmt" - "io" - "math" - "time" -) - -// Packets documentation: -// http://dev.mysql.com/doc/internals/en/client-server-protocol.html - -// Read packet to buffer 'data' -func (mc *mysqlConn) readPacket() ([]byte, error) { - var prevData []byte - for { - // read packet header - data, err := mc.buf.readNext(4) - if err != nil { - if cerr := mc.canceled.Value(); cerr != nil { - return nil, cerr - } - errLog.Print(err) - mc.Close() - return nil, ErrInvalidConn - } - - // packet length [24 bit] - pktLen := int(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16) - - // check packet sync [8 bit] - if data[3] != mc.sequence { - if data[3] > mc.sequence { - return nil, ErrPktSyncMul - } - return nil, ErrPktSync - } - mc.sequence++ - - // packets with length 0 terminate a previous packet which is a - // multiple of (2^24)-1 bytes long - if pktLen == 0 { - // there was no previous packet - if prevData == nil { - errLog.Print(ErrMalformPkt) - mc.Close() - return nil, ErrInvalidConn - } - - return prevData, nil - } - - // read packet body [pktLen bytes] - data, err = mc.buf.readNext(pktLen) - if err != nil { - if cerr := mc.canceled.Value(); cerr != nil { - return nil, cerr - } - errLog.Print(err) - mc.Close() - return nil, ErrInvalidConn - } - - // return data if this was the last packet - if pktLen < maxPacketSize { - // zero allocations for non-split packets - if prevData == nil { - return data, nil - } - - return append(prevData, data...), nil - } - - prevData = append(prevData, data...) - } -} - -// Write packet buffer 'data' -func (mc *mysqlConn) writePacket(data []byte) error { - pktLen := len(data) - 4 - - if pktLen > mc.maxAllowedPacket { - return ErrPktTooLarge - } - - // Perform a stale connection check. We only perform this check for - // the first query on a connection that has been checked out of the - // connection pool: a fresh connection from the pool is more likely - // to be stale, and it has not performed any previous writes that - // could cause data corruption, so it's safe to return ErrBadConn - // if the check fails. - if mc.reset { - mc.reset = false - conn := mc.netConn - if mc.rawConn != nil { - conn = mc.rawConn - } - var err error - // If this connection has a ReadTimeout which we've been setting on - // reads, reset it to its default value before we attempt a non-blocking - // read, otherwise the scheduler will just time us out before we can read - if mc.cfg.ReadTimeout != 0 { - err = conn.SetReadDeadline(time.Time{}) - } - if err == nil && mc.cfg.CheckConnLiveness { - err = connCheck(conn) - } - if err != nil { - errLog.Print("closing bad idle connection: ", err) - mc.Close() - return driver.ErrBadConn - } - } - - for { - var size int - if pktLen >= maxPacketSize { - data[0] = 0xff - data[1] = 0xff - data[2] = 0xff - size = maxPacketSize - } else { - data[0] = byte(pktLen) - data[1] = byte(pktLen >> 8) - data[2] = byte(pktLen >> 16) - size = pktLen - } - data[3] = mc.sequence - - // Write packet - if mc.writeTimeout > 0 { - if err := mc.netConn.SetWriteDeadline(time.Now().Add(mc.writeTimeout)); err != nil { - return err - } - } - - n, err := mc.netConn.Write(data[:4+size]) - if err == nil && n == 4+size { - mc.sequence++ - if size != maxPacketSize { - return nil - } - pktLen -= size - data = data[size:] - continue - } - - // Handle error - if err == nil { // n != len(data) - mc.cleanup() - errLog.Print(ErrMalformPkt) - } else { - if cerr := mc.canceled.Value(); cerr != nil { - return cerr - } - if n == 0 && pktLen == len(data)-4 { - // only for the first loop iteration when nothing was written yet - return errBadConnNoWrite - } - mc.cleanup() - errLog.Print(err) - } - return ErrInvalidConn - } -} - -/****************************************************************************** -* Initialization Process * -******************************************************************************/ - -// Handshake Initialization Packet -// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake -func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err error) { - data, err = mc.readPacket() - if err != nil { - // for init we can rewrite this to ErrBadConn for sql.Driver to retry, since - // in connection initialization we don't risk retrying non-idempotent actions. - if err == ErrInvalidConn { - return nil, "", driver.ErrBadConn - } - return - } - - if data[0] == iERR { - return nil, "", mc.handleErrorPacket(data) - } - - // protocol version [1 byte] - if data[0] < minProtocolVersion { - return nil, "", fmt.Errorf( - "unsupported protocol version %d. Version %d or higher is required", - data[0], - minProtocolVersion, - ) - } - - // server version [null terminated string] - // connection id [4 bytes] - pos := 1 + bytes.IndexByte(data[1:], 0x00) + 1 + 4 - - // first part of the password cipher [8 bytes] - authData := data[pos : pos+8] - - // (filler) always 0x00 [1 byte] - pos += 8 + 1 - - // capability flags (lower 2 bytes) [2 bytes] - mc.flags = clientFlag(binary.LittleEndian.Uint16(data[pos : pos+2])) - if mc.flags&clientProtocol41 == 0 { - return nil, "", ErrOldProtocol - } - if mc.flags&clientSSL == 0 && mc.cfg.tls != nil { - if mc.cfg.TLSConfig == "preferred" { - mc.cfg.tls = nil - } else { - return nil, "", ErrNoTLS - } - } - pos += 2 - - if len(data) > pos { - // character set [1 byte] - // status flags [2 bytes] - // capability flags (upper 2 bytes) [2 bytes] - // length of auth-plugin-data [1 byte] - // reserved (all [00]) [10 bytes] - pos += 1 + 2 + 2 + 1 + 10 - - // second part of the password cipher [mininum 13 bytes], - // where len=MAX(13, length of auth-plugin-data - 8) - // - // The web documentation is ambiguous about the length. However, - // according to mysql-5.7/sql/auth/sql_authentication.cc line 538, - // the 13th byte is "\0 byte, terminating the second part of - // a scramble". So the second part of the password cipher is - // a NULL terminated string that's at least 13 bytes with the - // last byte being NULL. - // - // The official Python library uses the fixed length 12 - // which seems to work but technically could have a hidden bug. - authData = append(authData, data[pos:pos+12]...) - pos += 13 - - // EOF if version (>= 5.5.7 and < 5.5.10) or (>= 5.6.0 and < 5.6.2) - // \NUL otherwise - if end := bytes.IndexByte(data[pos:], 0x00); end != -1 { - plugin = string(data[pos : pos+end]) - } else { - plugin = string(data[pos:]) - } - - // make a memory safe copy of the cipher slice - var b [20]byte - copy(b[:], authData) - return b[:], plugin, nil - } - - // make a memory safe copy of the cipher slice - var b [8]byte - copy(b[:], authData) - return b[:], plugin, nil -} - -// Client Authentication Packet -// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse -func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string) error { - // Adjust client flags based on server support - clientFlags := clientProtocol41 | - clientSecureConn | - clientLongPassword | - clientTransactions | - clientLocalFiles | - clientPluginAuth | - clientMultiResults | - mc.flags&clientLongFlag - - if mc.cfg.ClientFoundRows { - clientFlags |= clientFoundRows - } - - // To enable TLS / SSL - if mc.cfg.tls != nil { - clientFlags |= clientSSL - } - - if mc.cfg.MultiStatements { - clientFlags |= clientMultiStatements - } - - // encode length of the auth plugin data - var authRespLEIBuf [9]byte - authRespLen := len(authResp) - authRespLEI := appendLengthEncodedInteger(authRespLEIBuf[:0], uint64(authRespLen)) - if len(authRespLEI) > 1 { - // if the length can not be written in 1 byte, it must be written as a - // length encoded integer - clientFlags |= clientPluginAuthLenEncClientData - } - - pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 + len(authRespLEI) + len(authResp) + 21 + 1 - - // To specify a db name - if n := len(mc.cfg.DBName); n > 0 { - clientFlags |= clientConnectWithDB - pktLen += n + 1 - } - - // Calculate packet length and get buffer with that size - data, err := mc.buf.takeSmallBuffer(pktLen + 4) - if err != nil { - // cannot take the buffer. Something must be wrong with the connection - errLog.Print(err) - return errBadConnNoWrite - } - - // ClientFlags [32 bit] - data[4] = byte(clientFlags) - data[5] = byte(clientFlags >> 8) - data[6] = byte(clientFlags >> 16) - data[7] = byte(clientFlags >> 24) - - // MaxPacketSize [32 bit] (none) - data[8] = 0x00 - data[9] = 0x00 - data[10] = 0x00 - data[11] = 0x00 - - // Charset [1 byte] - var found bool - data[12], found = collations[mc.cfg.Collation] - if !found { - // Note possibility for false negatives: - // could be triggered although the collation is valid if the - // collations map does not contain entries the server supports. - return errors.New("unknown collation") - } - - // Filler [23 bytes] (all 0x00) - pos := 13 - for ; pos < 13+23; pos++ { - data[pos] = 0 - } - - // SSL Connection Request Packet - // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::SSLRequest - if mc.cfg.tls != nil { - // Send TLS / SSL request packet - if err := mc.writePacket(data[:(4+4+1+23)+4]); err != nil { - return err - } - - // Switch to TLS - tlsConn := tls.Client(mc.netConn, mc.cfg.tls) - if err := tlsConn.Handshake(); err != nil { - return err - } - mc.rawConn = mc.netConn - mc.netConn = tlsConn - mc.buf.nc = tlsConn - } - - // User [null terminated string] - if len(mc.cfg.User) > 0 { - pos += copy(data[pos:], mc.cfg.User) - } - data[pos] = 0x00 - pos++ - - // Auth Data [length encoded integer] - pos += copy(data[pos:], authRespLEI) - pos += copy(data[pos:], authResp) - - // Databasename [null terminated string] - if len(mc.cfg.DBName) > 0 { - pos += copy(data[pos:], mc.cfg.DBName) - data[pos] = 0x00 - pos++ - } - - pos += copy(data[pos:], plugin) - data[pos] = 0x00 - pos++ - - // Send Auth packet - return mc.writePacket(data[:pos]) -} - -// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse -func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error { - pktLen := 4 + len(authData) - data, err := mc.buf.takeSmallBuffer(pktLen) - if err != nil { - // cannot take the buffer. Something must be wrong with the connection - errLog.Print(err) - return errBadConnNoWrite - } - - // Add the auth data [EOF] - copy(data[4:], authData) - return mc.writePacket(data) -} - -/****************************************************************************** -* Command Packets * -******************************************************************************/ - -func (mc *mysqlConn) writeCommandPacket(command byte) error { - // Reset Packet Sequence - mc.sequence = 0 - - data, err := mc.buf.takeSmallBuffer(4 + 1) - if err != nil { - // cannot take the buffer. Something must be wrong with the connection - errLog.Print(err) - return errBadConnNoWrite - } - - // Add command byte - data[4] = command - - // Send CMD packet - return mc.writePacket(data) -} - -func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error { - // Reset Packet Sequence - mc.sequence = 0 - - pktLen := 1 + len(arg) - data, err := mc.buf.takeBuffer(pktLen + 4) - if err != nil { - // cannot take the buffer. Something must be wrong with the connection - errLog.Print(err) - return errBadConnNoWrite - } - - // Add command byte - data[4] = command - - // Add arg - copy(data[5:], arg) - - // Send CMD packet - return mc.writePacket(data) -} - -func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error { - // Reset Packet Sequence - mc.sequence = 0 - - data, err := mc.buf.takeSmallBuffer(4 + 1 + 4) - if err != nil { - // cannot take the buffer. Something must be wrong with the connection - errLog.Print(err) - return errBadConnNoWrite - } - - // Add command byte - data[4] = command - - // Add arg [32 bit] - data[5] = byte(arg) - data[6] = byte(arg >> 8) - data[7] = byte(arg >> 16) - data[8] = byte(arg >> 24) - - // Send CMD packet - return mc.writePacket(data) -} - -/****************************************************************************** -* Result Packets * -******************************************************************************/ - -func (mc *mysqlConn) readAuthResult() ([]byte, string, error) { - data, err := mc.readPacket() - if err != nil { - return nil, "", err - } - - // packet indicator - switch data[0] { - - case iOK: - return nil, "", mc.handleOkPacket(data) - - case iAuthMoreData: - return data[1:], "", err - - case iEOF: - if len(data) == 1 { - // https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest - return nil, "mysql_old_password", nil - } - pluginEndIndex := bytes.IndexByte(data, 0x00) - if pluginEndIndex < 0 { - return nil, "", ErrMalformPkt - } - plugin := string(data[1:pluginEndIndex]) - authData := data[pluginEndIndex+1:] - return authData, plugin, nil - - default: // Error otherwise - return nil, "", mc.handleErrorPacket(data) - } -} - -// Returns error if Packet is not an 'Result OK'-Packet -func (mc *mysqlConn) readResultOK() error { - data, err := mc.readPacket() - if err != nil { - return err - } - - if data[0] == iOK { - return mc.handleOkPacket(data) - } - return mc.handleErrorPacket(data) -} - -// Result Set Header Packet -// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::Resultset -func (mc *mysqlConn) readResultSetHeaderPacket() (int, error) { - data, err := mc.readPacket() - if err == nil { - switch data[0] { - - case iOK: - return 0, mc.handleOkPacket(data) - - case iERR: - return 0, mc.handleErrorPacket(data) - - case iLocalInFile: - return 0, mc.handleInFileRequest(string(data[1:])) - } - - // column count - num, _, n := readLengthEncodedInteger(data) - if n-len(data) == 0 { - return int(num), nil - } - - return 0, ErrMalformPkt - } - return 0, err -} - -// Error Packet -// http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-ERR_Packet -func (mc *mysqlConn) handleErrorPacket(data []byte) error { - if data[0] != iERR { - return ErrMalformPkt - } - - // 0xff [1 byte] - - // Error Number [16 bit uint] - errno := binary.LittleEndian.Uint16(data[1:3]) - - // 1792: ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION - // 1290: ER_OPTION_PREVENTS_STATEMENT (returned by Aurora during failover) - if (errno == 1792 || errno == 1290) && mc.cfg.RejectReadOnly { - // Oops; we are connected to a read-only connection, and won't be able - // to issue any write statements. Since RejectReadOnly is configured, - // we throw away this connection hoping this one would have write - // permission. This is specifically for a possible race condition - // during failover (e.g. on AWS Aurora). See README.md for more. - // - // We explicitly close the connection before returning - // driver.ErrBadConn to ensure that `database/sql` purges this - // connection and initiates a new one for next statement next time. - mc.Close() - return driver.ErrBadConn - } - - pos := 3 - - // SQL State [optional: # + 5bytes string] - if data[3] == 0x23 { - //sqlstate := string(data[4 : 4+5]) - pos = 9 - } - - // Error Message [string] - return &MySQLError{ - Number: errno, - Message: string(data[pos:]), - } -} - -func readStatus(b []byte) statusFlag { - return statusFlag(b[0]) | statusFlag(b[1])<<8 -} - -// Ok Packet -// http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-OK_Packet -func (mc *mysqlConn) handleOkPacket(data []byte) error { - var n, m int - - // 0x00 [1 byte] - - // Affected rows [Length Coded Binary] - mc.affectedRows, _, n = readLengthEncodedInteger(data[1:]) - - // Insert id [Length Coded Binary] - mc.insertId, _, m = readLengthEncodedInteger(data[1+n:]) - - // server_status [2 bytes] - mc.status = readStatus(data[1+n+m : 1+n+m+2]) - if mc.status&statusMoreResultsExists != 0 { - return nil - } - - // warning count [2 bytes] - - return nil -} - -// Read Packets as Field Packets until EOF-Packet or an Error appears -// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnDefinition41 -func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) { - columns := make([]mysqlField, count) - - for i := 0; ; i++ { - data, err := mc.readPacket() - if err != nil { - return nil, err - } - - // EOF Packet - if data[0] == iEOF && (len(data) == 5 || len(data) == 1) { - if i == count { - return columns, nil - } - return nil, fmt.Errorf("column count mismatch n:%d len:%d", count, len(columns)) - } - - // Catalog - pos, err := skipLengthEncodedString(data) - if err != nil { - return nil, err - } - - // Database [len coded string] - n, err := skipLengthEncodedString(data[pos:]) - if err != nil { - return nil, err - } - pos += n - - // Table [len coded string] - if mc.cfg.ColumnsWithAlias { - tableName, _, n, err := readLengthEncodedString(data[pos:]) - if err != nil { - return nil, err - } - pos += n - columns[i].tableName = string(tableName) - } else { - n, err = skipLengthEncodedString(data[pos:]) - if err != nil { - return nil, err - } - pos += n - } - - // Original table [len coded string] - n, err = skipLengthEncodedString(data[pos:]) - if err != nil { - return nil, err - } - pos += n - - // Name [len coded string] - name, _, n, err := readLengthEncodedString(data[pos:]) - if err != nil { - return nil, err - } - columns[i].name = string(name) - pos += n - - // Original name [len coded string] - n, err = skipLengthEncodedString(data[pos:]) - if err != nil { - return nil, err - } - pos += n - - // Filler [uint8] - pos++ - - // Charset [charset, collation uint8] - columns[i].charSet = data[pos] - pos += 2 - - // Length [uint32] - columns[i].length = binary.LittleEndian.Uint32(data[pos : pos+4]) - pos += 4 - - // Field type [uint8] - columns[i].fieldType = fieldType(data[pos]) - pos++ - - // Flags [uint16] - columns[i].flags = fieldFlag(binary.LittleEndian.Uint16(data[pos : pos+2])) - pos += 2 - - // Decimals [uint8] - columns[i].decimals = data[pos] - //pos++ - - // Default value [len coded binary] - //if pos < len(data) { - // defaultVal, _, err = bytesToLengthCodedBinary(data[pos:]) - //} - } -} - -// Read Packets as Field Packets until EOF-Packet or an Error appears -// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::ResultsetRow -func (rows *textRows) readRow(dest []driver.Value) error { - mc := rows.mc - - if rows.rs.done { - return io.EOF - } - - data, err := mc.readPacket() - if err != nil { - return err - } - - // EOF Packet - if data[0] == iEOF && len(data) == 5 { - // server_status [2 bytes] - rows.mc.status = readStatus(data[3:]) - rows.rs.done = true - if !rows.HasNextResultSet() { - rows.mc = nil - } - return io.EOF - } - if data[0] == iERR { - rows.mc = nil - return mc.handleErrorPacket(data) - } - - // RowSet Packet - var n int - var isNull bool - pos := 0 - - for i := range dest { - // Read bytes and convert to string - dest[i], isNull, n, err = readLengthEncodedString(data[pos:]) - pos += n - if err == nil { - if !isNull { - if !mc.parseTime { - continue - } else { - switch rows.rs.columns[i].fieldType { - case fieldTypeTimestamp, fieldTypeDateTime, - fieldTypeDate, fieldTypeNewDate: - dest[i], err = parseDateTime( - dest[i].([]byte), - mc.cfg.Loc, - ) - if err == nil { - continue - } - default: - continue - } - } - - } else { - dest[i] = nil - continue - } - } - return err // err != nil - } - - return nil -} - -// Reads Packets until EOF-Packet or an Error appears. Returns count of Packets read -func (mc *mysqlConn) readUntilEOF() error { - for { - data, err := mc.readPacket() - if err != nil { - return err - } - - switch data[0] { - case iERR: - return mc.handleErrorPacket(data) - case iEOF: - if len(data) == 5 { - mc.status = readStatus(data[3:]) - } - return nil - } - } -} - -/****************************************************************************** -* Prepared Statements * -******************************************************************************/ - -// Prepare Result Packets -// http://dev.mysql.com/doc/internals/en/com-stmt-prepare-response.html -func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) { - data, err := stmt.mc.readPacket() - if err == nil { - // packet indicator [1 byte] - if data[0] != iOK { - return 0, stmt.mc.handleErrorPacket(data) - } - - // statement id [4 bytes] - stmt.id = binary.LittleEndian.Uint32(data[1:5]) - - // Column count [16 bit uint] - columnCount := binary.LittleEndian.Uint16(data[5:7]) - - // Param count [16 bit uint] - stmt.paramCount = int(binary.LittleEndian.Uint16(data[7:9])) - - // Reserved [8 bit] - - // Warning count [16 bit uint] - - return columnCount, nil - } - return 0, err -} - -// http://dev.mysql.com/doc/internals/en/com-stmt-send-long-data.html -func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error { - maxLen := stmt.mc.maxAllowedPacket - 1 - pktLen := maxLen - - // After the header (bytes 0-3) follows before the data: - // 1 byte command - // 4 bytes stmtID - // 2 bytes paramID - const dataOffset = 1 + 4 + 2 - - // Cannot use the write buffer since - // a) the buffer is too small - // b) it is in use - data := make([]byte, 4+1+4+2+len(arg)) - - copy(data[4+dataOffset:], arg) - - for argLen := len(arg); argLen > 0; argLen -= pktLen - dataOffset { - if dataOffset+argLen < maxLen { - pktLen = dataOffset + argLen - } - - stmt.mc.sequence = 0 - // Add command byte [1 byte] - data[4] = comStmtSendLongData - - // Add stmtID [32 bit] - data[5] = byte(stmt.id) - data[6] = byte(stmt.id >> 8) - data[7] = byte(stmt.id >> 16) - data[8] = byte(stmt.id >> 24) - - // Add paramID [16 bit] - data[9] = byte(paramID) - data[10] = byte(paramID >> 8) - - // Send CMD packet - err := stmt.mc.writePacket(data[:4+pktLen]) - if err == nil { - data = data[pktLen-dataOffset:] - continue - } - return err - - } - - // Reset Packet Sequence - stmt.mc.sequence = 0 - return nil -} - -// Execute Prepared Statement -// http://dev.mysql.com/doc/internals/en/com-stmt-execute.html -func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { - if len(args) != stmt.paramCount { - return fmt.Errorf( - "argument count mismatch (got: %d; has: %d)", - len(args), - stmt.paramCount, - ) - } - - const minPktLen = 4 + 1 + 4 + 1 + 4 - mc := stmt.mc - - // Determine threshold dynamically to avoid packet size shortage. - longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1) - if longDataSize < 64 { - longDataSize = 64 - } - - // Reset packet-sequence - mc.sequence = 0 - - var data []byte - var err error - - if len(args) == 0 { - data, err = mc.buf.takeBuffer(minPktLen) - } else { - data, err = mc.buf.takeCompleteBuffer() - // In this case the len(data) == cap(data) which is used to optimise the flow below. - } - if err != nil { - // cannot take the buffer. Something must be wrong with the connection - errLog.Print(err) - return errBadConnNoWrite - } - - // command [1 byte] - data[4] = comStmtExecute - - // statement_id [4 bytes] - data[5] = byte(stmt.id) - data[6] = byte(stmt.id >> 8) - data[7] = byte(stmt.id >> 16) - data[8] = byte(stmt.id >> 24) - - // flags (0: CURSOR_TYPE_NO_CURSOR) [1 byte] - data[9] = 0x00 - - // iteration_count (uint32(1)) [4 bytes] - data[10] = 0x01 - data[11] = 0x00 - data[12] = 0x00 - data[13] = 0x00 - - if len(args) > 0 { - pos := minPktLen - - var nullMask []byte - if maskLen, typesLen := (len(args)+7)/8, 1+2*len(args); pos+maskLen+typesLen >= cap(data) { - // buffer has to be extended but we don't know by how much so - // we depend on append after all data with known sizes fit. - // We stop at that because we deal with a lot of columns here - // which makes the required allocation size hard to guess. - tmp := make([]byte, pos+maskLen+typesLen) - copy(tmp[:pos], data[:pos]) - data = tmp - nullMask = data[pos : pos+maskLen] - // No need to clean nullMask as make ensures that. - pos += maskLen - } else { - nullMask = data[pos : pos+maskLen] - for i := range nullMask { - nullMask[i] = 0 - } - pos += maskLen - } - - // newParameterBoundFlag 1 [1 byte] - data[pos] = 0x01 - pos++ - - // type of each parameter [len(args)*2 bytes] - paramTypes := data[pos:] - pos += len(args) * 2 - - // value of each parameter [n bytes] - paramValues := data[pos:pos] - valuesCap := cap(paramValues) - - for i, arg := range args { - // build NULL-bitmap - if arg == nil { - nullMask[i/8] |= 1 << (uint(i) & 7) - paramTypes[i+i] = byte(fieldTypeNULL) - paramTypes[i+i+1] = 0x00 - continue - } - - if v, ok := arg.(json.RawMessage); ok { - arg = []byte(v) - } - // cache types and values - switch v := arg.(type) { - case int64: - paramTypes[i+i] = byte(fieldTypeLongLong) - paramTypes[i+i+1] = 0x00 - - if cap(paramValues)-len(paramValues)-8 >= 0 { - paramValues = paramValues[:len(paramValues)+8] - binary.LittleEndian.PutUint64( - paramValues[len(paramValues)-8:], - uint64(v), - ) - } else { - paramValues = append(paramValues, - uint64ToBytes(uint64(v))..., - ) - } - - case uint64: - paramTypes[i+i] = byte(fieldTypeLongLong) - paramTypes[i+i+1] = 0x80 // type is unsigned - - if cap(paramValues)-len(paramValues)-8 >= 0 { - paramValues = paramValues[:len(paramValues)+8] - binary.LittleEndian.PutUint64( - paramValues[len(paramValues)-8:], - uint64(v), - ) - } else { - paramValues = append(paramValues, - uint64ToBytes(uint64(v))..., - ) - } - - case float64: - paramTypes[i+i] = byte(fieldTypeDouble) - paramTypes[i+i+1] = 0x00 - - if cap(paramValues)-len(paramValues)-8 >= 0 { - paramValues = paramValues[:len(paramValues)+8] - binary.LittleEndian.PutUint64( - paramValues[len(paramValues)-8:], - math.Float64bits(v), - ) - } else { - paramValues = append(paramValues, - uint64ToBytes(math.Float64bits(v))..., - ) - } - - case bool: - paramTypes[i+i] = byte(fieldTypeTiny) - paramTypes[i+i+1] = 0x00 - - if v { - paramValues = append(paramValues, 0x01) - } else { - paramValues = append(paramValues, 0x00) - } - - case []byte: - // Common case (non-nil value) first - if v != nil { - paramTypes[i+i] = byte(fieldTypeString) - paramTypes[i+i+1] = 0x00 - - if len(v) < longDataSize { - paramValues = appendLengthEncodedInteger(paramValues, - uint64(len(v)), - ) - paramValues = append(paramValues, v...) - } else { - if err := stmt.writeCommandLongData(i, v); err != nil { - return err - } - } - continue - } - - // Handle []byte(nil) as a NULL value - nullMask[i/8] |= 1 << (uint(i) & 7) - paramTypes[i+i] = byte(fieldTypeNULL) - paramTypes[i+i+1] = 0x00 - - case string: - paramTypes[i+i] = byte(fieldTypeString) - paramTypes[i+i+1] = 0x00 - - if len(v) < longDataSize { - paramValues = appendLengthEncodedInteger(paramValues, - uint64(len(v)), - ) - paramValues = append(paramValues, v...) - } else { - if err := stmt.writeCommandLongData(i, []byte(v)); err != nil { - return err - } - } - - case time.Time: - paramTypes[i+i] = byte(fieldTypeString) - paramTypes[i+i+1] = 0x00 - - var a [64]byte - var b = a[:0] - - if v.IsZero() { - b = append(b, "0000-00-00"...) - } else { - b, err = appendDateTime(b, v.In(mc.cfg.Loc)) - if err != nil { - return err - } - } - - paramValues = appendLengthEncodedInteger(paramValues, - uint64(len(b)), - ) - paramValues = append(paramValues, b...) - - default: - return fmt.Errorf("cannot convert type: %T", arg) - } - } - - // Check if param values exceeded the available buffer - // In that case we must build the data packet with the new values buffer - if valuesCap != cap(paramValues) { - data = append(data[:pos], paramValues...) - if err = mc.buf.store(data); err != nil { - errLog.Print(err) - return errBadConnNoWrite - } - } - - pos += len(paramValues) - data = data[:pos] - } - - return mc.writePacket(data) -} - -func (mc *mysqlConn) discardResults() error { - for mc.status&statusMoreResultsExists != 0 { - resLen, err := mc.readResultSetHeaderPacket() - if err != nil { - return err - } - if resLen > 0 { - // columns - if err := mc.readUntilEOF(); err != nil { - return err - } - // rows - if err := mc.readUntilEOF(); err != nil { - return err - } - } - } - return nil -} - -// http://dev.mysql.com/doc/internals/en/binary-protocol-resultset-row.html -func (rows *binaryRows) readRow(dest []driver.Value) error { - data, err := rows.mc.readPacket() - if err != nil { - return err - } - - // packet indicator [1 byte] - if data[0] != iOK { - // EOF Packet - if data[0] == iEOF && len(data) == 5 { - rows.mc.status = readStatus(data[3:]) - rows.rs.done = true - if !rows.HasNextResultSet() { - rows.mc = nil - } - return io.EOF - } - mc := rows.mc - rows.mc = nil - - // Error otherwise - return mc.handleErrorPacket(data) - } - - // NULL-bitmap, [(column-count + 7 + 2) / 8 bytes] - pos := 1 + (len(dest)+7+2)>>3 - nullMask := data[1:pos] - - for i := range dest { - // Field is NULL - // (byte >> bit-pos) % 2 == 1 - if ((nullMask[(i+2)>>3] >> uint((i+2)&7)) & 1) == 1 { - dest[i] = nil - continue - } - - // Convert to byte-coded string - switch rows.rs.columns[i].fieldType { - case fieldTypeNULL: - dest[i] = nil - continue - - // Numeric Types - case fieldTypeTiny: - if rows.rs.columns[i].flags&flagUnsigned != 0 { - dest[i] = int64(data[pos]) - } else { - dest[i] = int64(int8(data[pos])) - } - pos++ - continue - - case fieldTypeShort, fieldTypeYear: - if rows.rs.columns[i].flags&flagUnsigned != 0 { - dest[i] = int64(binary.LittleEndian.Uint16(data[pos : pos+2])) - } else { - dest[i] = int64(int16(binary.LittleEndian.Uint16(data[pos : pos+2]))) - } - pos += 2 - continue - - case fieldTypeInt24, fieldTypeLong: - if rows.rs.columns[i].flags&flagUnsigned != 0 { - dest[i] = int64(binary.LittleEndian.Uint32(data[pos : pos+4])) - } else { - dest[i] = int64(int32(binary.LittleEndian.Uint32(data[pos : pos+4]))) - } - pos += 4 - continue - - case fieldTypeLongLong: - if rows.rs.columns[i].flags&flagUnsigned != 0 { - val := binary.LittleEndian.Uint64(data[pos : pos+8]) - if val > math.MaxInt64 { - dest[i] = uint64ToString(val) - } else { - dest[i] = int64(val) - } - } else { - dest[i] = int64(binary.LittleEndian.Uint64(data[pos : pos+8])) - } - pos += 8 - continue - - case fieldTypeFloat: - dest[i] = math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4])) - pos += 4 - continue - - case fieldTypeDouble: - dest[i] = math.Float64frombits(binary.LittleEndian.Uint64(data[pos : pos+8])) - pos += 8 - continue - - // Length coded Binary Strings - case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar, - fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB, - fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB, - fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON: - var isNull bool - var n int - dest[i], isNull, n, err = readLengthEncodedString(data[pos:]) - pos += n - if err == nil { - if !isNull { - continue - } else { - dest[i] = nil - continue - } - } - return err - - case - fieldTypeDate, fieldTypeNewDate, // Date YYYY-MM-DD - fieldTypeTime, // Time [-][H]HH:MM:SS[.fractal] - fieldTypeTimestamp, fieldTypeDateTime: // Timestamp YYYY-MM-DD HH:MM:SS[.fractal] - - num, isNull, n := readLengthEncodedInteger(data[pos:]) - pos += n - - switch { - case isNull: - dest[i] = nil - continue - case rows.rs.columns[i].fieldType == fieldTypeTime: - // database/sql does not support an equivalent to TIME, return a string - var dstlen uint8 - switch decimals := rows.rs.columns[i].decimals; decimals { - case 0x00, 0x1f: - dstlen = 8 - case 1, 2, 3, 4, 5, 6: - dstlen = 8 + 1 + decimals - default: - return fmt.Errorf( - "protocol error, illegal decimals value %d", - rows.rs.columns[i].decimals, - ) - } - dest[i], err = formatBinaryTime(data[pos:pos+int(num)], dstlen) - case rows.mc.parseTime: - dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc) - default: - var dstlen uint8 - if rows.rs.columns[i].fieldType == fieldTypeDate { - dstlen = 10 - } else { - switch decimals := rows.rs.columns[i].decimals; decimals { - case 0x00, 0x1f: - dstlen = 19 - case 1, 2, 3, 4, 5, 6: - dstlen = 19 + 1 + decimals - default: - return fmt.Errorf( - "protocol error, illegal decimals value %d", - rows.rs.columns[i].decimals, - ) - } - } - dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen) - } - - if err == nil { - pos += int(num) - continue - } else { - return err - } - - // Please report if this happens! - default: - return fmt.Errorf("unknown field type %d", rows.rs.columns[i].fieldType) - } - } - - return nil -} diff --git a/proxy_go/public/mysql@v1.6.0/packets_test.go b/proxy_go/public/mysql@v1.6.0/packets_test.go deleted file mode 100644 index b61e4db..0000000 --- a/proxy_go/public/mysql@v1.6.0/packets_test.go +++ /dev/null @@ -1,336 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2016 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "bytes" - "errors" - "net" - "testing" - "time" -) - -var ( - errConnClosed = errors.New("connection is closed") - errConnTooManyReads = errors.New("too many reads") - errConnTooManyWrites = errors.New("too many writes") -) - -// struct to mock a net.Conn for testing purposes -type mockConn struct { - laddr net.Addr - raddr net.Addr - data []byte - written []byte - queuedReplies [][]byte - closed bool - read int - reads int - writes int - maxReads int - maxWrites int -} - -func (m *mockConn) Read(b []byte) (n int, err error) { - if m.closed { - return 0, errConnClosed - } - - m.reads++ - if m.maxReads > 0 && m.reads > m.maxReads { - return 0, errConnTooManyReads - } - - n = copy(b, m.data) - m.read += n - m.data = m.data[n:] - return -} -func (m *mockConn) Write(b []byte) (n int, err error) { - if m.closed { - return 0, errConnClosed - } - - m.writes++ - if m.maxWrites > 0 && m.writes > m.maxWrites { - return 0, errConnTooManyWrites - } - - n = len(b) - m.written = append(m.written, b...) - - if n > 0 && len(m.queuedReplies) > 0 { - m.data = m.queuedReplies[0] - m.queuedReplies = m.queuedReplies[1:] - } - return -} -func (m *mockConn) Close() error { - m.closed = true - return nil -} -func (m *mockConn) LocalAddr() net.Addr { - return m.laddr -} -func (m *mockConn) RemoteAddr() net.Addr { - return m.raddr -} -func (m *mockConn) SetDeadline(t time.Time) error { - return nil -} -func (m *mockConn) SetReadDeadline(t time.Time) error { - return nil -} -func (m *mockConn) SetWriteDeadline(t time.Time) error { - return nil -} - -// make sure mockConn implements the net.Conn interface -var _ net.Conn = new(mockConn) - -func newRWMockConn(sequence uint8) (*mockConn, *mysqlConn) { - conn := new(mockConn) - mc := &mysqlConn{ - buf: newBuffer(conn), - cfg: NewConfig(), - netConn: conn, - closech: make(chan struct{}), - maxAllowedPacket: defaultMaxAllowedPacket, - sequence: sequence, - } - return conn, mc -} - -func TestReadPacketSingleByte(t *testing.T) { - conn := new(mockConn) - mc := &mysqlConn{ - buf: newBuffer(conn), - } - - conn.data = []byte{0x01, 0x00, 0x00, 0x00, 0xff} - conn.maxReads = 1 - packet, err := mc.readPacket() - if err != nil { - t.Fatal(err) - } - if len(packet) != 1 { - t.Fatalf("unexpected packet length: expected %d, got %d", 1, len(packet)) - } - if packet[0] != 0xff { - t.Fatalf("unexpected packet content: expected %x, got %x", 0xff, packet[0]) - } -} - -func TestReadPacketWrongSequenceID(t *testing.T) { - conn := new(mockConn) - mc := &mysqlConn{ - buf: newBuffer(conn), - } - - // too low sequence id - conn.data = []byte{0x01, 0x00, 0x00, 0x00, 0xff} - conn.maxReads = 1 - mc.sequence = 1 - _, err := mc.readPacket() - if err != ErrPktSync { - t.Errorf("expected ErrPktSync, got %v", err) - } - - // reset - conn.reads = 0 - mc.sequence = 0 - mc.buf = newBuffer(conn) - - // too high sequence id - conn.data = []byte{0x01, 0x00, 0x00, 0x42, 0xff} - _, err = mc.readPacket() - if err != ErrPktSyncMul { - t.Errorf("expected ErrPktSyncMul, got %v", err) - } -} - -func TestReadPacketSplit(t *testing.T) { - conn := new(mockConn) - mc := &mysqlConn{ - buf: newBuffer(conn), - } - - data := make([]byte, maxPacketSize*2+4*3) - const pkt2ofs = maxPacketSize + 4 - const pkt3ofs = 2 * (maxPacketSize + 4) - - // case 1: payload has length maxPacketSize - data = data[:pkt2ofs+4] - - // 1st packet has maxPacketSize length and sequence id 0 - // ff ff ff 00 ... - data[0] = 0xff - data[1] = 0xff - data[2] = 0xff - - // mark the payload start and end of 1st packet so that we can check if the - // content was correctly appended - data[4] = 0x11 - data[maxPacketSize+3] = 0x22 - - // 2nd packet has payload length 0 and squence id 1 - // 00 00 00 01 - data[pkt2ofs+3] = 0x01 - - conn.data = data - conn.maxReads = 3 - packet, err := mc.readPacket() - if err != nil { - t.Fatal(err) - } - if len(packet) != maxPacketSize { - t.Fatalf("unexpected packet length: expected %d, got %d", maxPacketSize, len(packet)) - } - if packet[0] != 0x11 { - t.Fatalf("unexpected payload start: expected %x, got %x", 0x11, packet[0]) - } - if packet[maxPacketSize-1] != 0x22 { - t.Fatalf("unexpected payload end: expected %x, got %x", 0x22, packet[maxPacketSize-1]) - } - - // case 2: payload has length which is a multiple of maxPacketSize - data = data[:cap(data)] - - // 2nd packet now has maxPacketSize length - data[pkt2ofs] = 0xff - data[pkt2ofs+1] = 0xff - data[pkt2ofs+2] = 0xff - - // mark the payload start and end of the 2nd packet - data[pkt2ofs+4] = 0x33 - data[pkt2ofs+maxPacketSize+3] = 0x44 - - // 3rd packet has payload length 0 and squence id 2 - // 00 00 00 02 - data[pkt3ofs+3] = 0x02 - - conn.data = data - conn.reads = 0 - conn.maxReads = 5 - mc.sequence = 0 - packet, err = mc.readPacket() - if err != nil { - t.Fatal(err) - } - if len(packet) != 2*maxPacketSize { - t.Fatalf("unexpected packet length: expected %d, got %d", 2*maxPacketSize, len(packet)) - } - if packet[0] != 0x11 { - t.Fatalf("unexpected payload start: expected %x, got %x", 0x11, packet[0]) - } - if packet[2*maxPacketSize-1] != 0x44 { - t.Fatalf("unexpected payload end: expected %x, got %x", 0x44, packet[2*maxPacketSize-1]) - } - - // case 3: payload has a length larger maxPacketSize, which is not an exact - // multiple of it - data = data[:pkt2ofs+4+42] - data[pkt2ofs] = 0x2a - data[pkt2ofs+1] = 0x00 - data[pkt2ofs+2] = 0x00 - data[pkt2ofs+4+41] = 0x44 - - conn.data = data - conn.reads = 0 - conn.maxReads = 4 - mc.sequence = 0 - packet, err = mc.readPacket() - if err != nil { - t.Fatal(err) - } - if len(packet) != maxPacketSize+42 { - t.Fatalf("unexpected packet length: expected %d, got %d", maxPacketSize+42, len(packet)) - } - if packet[0] != 0x11 { - t.Fatalf("unexpected payload start: expected %x, got %x", 0x11, packet[0]) - } - if packet[maxPacketSize+41] != 0x44 { - t.Fatalf("unexpected payload end: expected %x, got %x", 0x44, packet[maxPacketSize+41]) - } -} - -func TestReadPacketFail(t *testing.T) { - conn := new(mockConn) - mc := &mysqlConn{ - buf: newBuffer(conn), - closech: make(chan struct{}), - } - - // illegal empty (stand-alone) packet - conn.data = []byte{0x00, 0x00, 0x00, 0x00} - conn.maxReads = 1 - _, err := mc.readPacket() - if err != ErrInvalidConn { - t.Errorf("expected ErrInvalidConn, got %v", err) - } - - // reset - conn.reads = 0 - mc.sequence = 0 - mc.buf = newBuffer(conn) - - // fail to read header - conn.closed = true - _, err = mc.readPacket() - if err != ErrInvalidConn { - t.Errorf("expected ErrInvalidConn, got %v", err) - } - - // reset - conn.closed = false - conn.reads = 0 - mc.sequence = 0 - mc.buf = newBuffer(conn) - - // fail to read body - conn.maxReads = 1 - _, err = mc.readPacket() - if err != ErrInvalidConn { - t.Errorf("expected ErrInvalidConn, got %v", err) - } -} - -// https://github.com/go-sql-driver/mysql/pull/801 -// not-NUL terminated plugin_name in init packet -func TestRegression801(t *testing.T) { - conn := new(mockConn) - mc := &mysqlConn{ - buf: newBuffer(conn), - cfg: new(Config), - sequence: 42, - closech: make(chan struct{}), - } - - conn.data = []byte{72, 0, 0, 42, 10, 53, 46, 53, 46, 56, 0, 165, 0, 0, 0, - 60, 70, 63, 58, 68, 104, 34, 97, 0, 223, 247, 33, 2, 0, 15, 128, 21, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 120, 114, 47, 85, 75, 109, 99, 51, 77, - 50, 64, 0, 109, 121, 115, 113, 108, 95, 110, 97, 116, 105, 118, 101, 95, - 112, 97, 115, 115, 119, 111, 114, 100} - conn.maxReads = 1 - - authData, pluginName, err := mc.readHandshakePacket() - if err != nil { - t.Fatalf("got error: %v", err) - } - - if pluginName != "mysql_native_password" { - t.Errorf("expected plugin name 'mysql_native_password', got '%s'", pluginName) - } - - expectedAuthData := []byte{60, 70, 63, 58, 68, 104, 34, 97, 98, 120, 114, - 47, 85, 75, 109, 99, 51, 77, 50, 64} - if !bytes.Equal(authData, expectedAuthData) { - t.Errorf("expected authData '%v', got '%v'", expectedAuthData, authData) - } -} diff --git a/proxy_go/public/mysql@v1.6.0/result.go b/proxy_go/public/mysql@v1.6.0/result.go deleted file mode 100644 index c6438d0..0000000 --- a/proxy_go/public/mysql@v1.6.0/result.go +++ /dev/null @@ -1,22 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -type mysqlResult struct { - affectedRows int64 - insertId int64 -} - -func (res *mysqlResult) LastInsertId() (int64, error) { - return res.insertId, nil -} - -func (res *mysqlResult) RowsAffected() (int64, error) { - return res.affectedRows, nil -} diff --git a/proxy_go/public/mysql@v1.6.0/rows.go b/proxy_go/public/mysql@v1.6.0/rows.go deleted file mode 100644 index 888bdb5..0000000 --- a/proxy_go/public/mysql@v1.6.0/rows.go +++ /dev/null @@ -1,223 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "database/sql/driver" - "io" - "math" - "reflect" -) - -type resultSet struct { - columns []mysqlField - columnNames []string - done bool -} - -type mysqlRows struct { - mc *mysqlConn - rs resultSet - finish func() -} - -type binaryRows struct { - mysqlRows -} - -type textRows struct { - mysqlRows -} - -func (rows *mysqlRows) Columns() []string { - if rows.rs.columnNames != nil { - return rows.rs.columnNames - } - - columns := make([]string, len(rows.rs.columns)) - if rows.mc != nil && rows.mc.cfg.ColumnsWithAlias { - for i := range columns { - if tableName := rows.rs.columns[i].tableName; len(tableName) > 0 { - columns[i] = tableName + "." + rows.rs.columns[i].name - } else { - columns[i] = rows.rs.columns[i].name - } - } - } else { - for i := range columns { - columns[i] = rows.rs.columns[i].name - } - } - - rows.rs.columnNames = columns - return columns -} - -func (rows *mysqlRows) ColumnTypeDatabaseTypeName(i int) string { - return rows.rs.columns[i].typeDatabaseName() -} - -// func (rows *mysqlRows) ColumnTypeLength(i int) (length int64, ok bool) { -// return int64(rows.rs.columns[i].length), true -// } - -func (rows *mysqlRows) ColumnTypeNullable(i int) (nullable, ok bool) { - return rows.rs.columns[i].flags&flagNotNULL == 0, true -} - -func (rows *mysqlRows) ColumnTypePrecisionScale(i int) (int64, int64, bool) { - column := rows.rs.columns[i] - decimals := int64(column.decimals) - - switch column.fieldType { - case fieldTypeDecimal, fieldTypeNewDecimal: - if decimals > 0 { - return int64(column.length) - 2, decimals, true - } - return int64(column.length) - 1, decimals, true - case fieldTypeTimestamp, fieldTypeDateTime, fieldTypeTime: - return decimals, decimals, true - case fieldTypeFloat, fieldTypeDouble: - if decimals == 0x1f { - return math.MaxInt64, math.MaxInt64, true - } - return math.MaxInt64, decimals, true - } - - return 0, 0, false -} - -func (rows *mysqlRows) ColumnTypeScanType(i int) reflect.Type { - return rows.rs.columns[i].scanType() -} - -func (rows *mysqlRows) Close() (err error) { - if f := rows.finish; f != nil { - f() - rows.finish = nil - } - - mc := rows.mc - if mc == nil { - return nil - } - if err := mc.error(); err != nil { - return err - } - - // flip the buffer for this connection if we need to drain it. - // note that for a successful query (i.e. one where rows.next() - // has been called until it returns false), `rows.mc` will be nil - // by the time the user calls `(*Rows).Close`, so we won't reach this - // see: https://github.com/golang/go/commit/651ddbdb5056ded455f47f9c494c67b389622a47 - mc.buf.flip() - - // Remove unread packets from stream - if !rows.rs.done { - err = mc.readUntilEOF() - } - if err == nil { - if err = mc.discardResults(); err != nil { - return err - } - } - - rows.mc = nil - return err -} - -func (rows *mysqlRows) HasNextResultSet() (b bool) { - if rows.mc == nil { - return false - } - return rows.mc.status&statusMoreResultsExists != 0 -} - -func (rows *mysqlRows) nextResultSet() (int, error) { - if rows.mc == nil { - return 0, io.EOF - } - if err := rows.mc.error(); err != nil { - return 0, err - } - - // Remove unread packets from stream - if !rows.rs.done { - if err := rows.mc.readUntilEOF(); err != nil { - return 0, err - } - rows.rs.done = true - } - - if !rows.HasNextResultSet() { - rows.mc = nil - return 0, io.EOF - } - rows.rs = resultSet{} - return rows.mc.readResultSetHeaderPacket() -} - -func (rows *mysqlRows) nextNotEmptyResultSet() (int, error) { - for { - resLen, err := rows.nextResultSet() - if err != nil { - return 0, err - } - - if resLen > 0 { - return resLen, nil - } - - rows.rs.done = true - } -} - -func (rows *binaryRows) NextResultSet() error { - resLen, err := rows.nextNotEmptyResultSet() - if err != nil { - return err - } - - rows.rs.columns, err = rows.mc.readColumns(resLen) - return err -} - -func (rows *binaryRows) Next(dest []driver.Value) error { - if mc := rows.mc; mc != nil { - if err := mc.error(); err != nil { - return err - } - - // Fetch next row from stream - return rows.readRow(dest) - } - return io.EOF -} - -func (rows *textRows) NextResultSet() (err error) { - resLen, err := rows.nextNotEmptyResultSet() - if err != nil { - return err - } - - rows.rs.columns, err = rows.mc.readColumns(resLen) - return err -} - -func (rows *textRows) Next(dest []driver.Value) error { - if mc := rows.mc; mc != nil { - if err := mc.error(); err != nil { - return err - } - - // Fetch next row from stream - return rows.readRow(dest) - } - return io.EOF -} diff --git a/proxy_go/public/mysql@v1.6.0/statement.go b/proxy_go/public/mysql@v1.6.0/statement.go deleted file mode 100644 index 18a3ae4..0000000 --- a/proxy_go/public/mysql@v1.6.0/statement.go +++ /dev/null @@ -1,220 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "database/sql/driver" - "encoding/json" - "fmt" - "io" - "reflect" -) - -type mysqlStmt struct { - mc *mysqlConn - id uint32 - paramCount int -} - -func (stmt *mysqlStmt) Close() error { - if stmt.mc == nil || stmt.mc.closed.IsSet() { - // driver.Stmt.Close can be called more than once, thus this function - // has to be idempotent. - // See also Issue #450 and golang/go#16019. - //errLog.Print(ErrInvalidConn) - return driver.ErrBadConn - } - - err := stmt.mc.writeCommandPacketUint32(comStmtClose, stmt.id) - stmt.mc = nil - return err -} - -func (stmt *mysqlStmt) NumInput() int { - return stmt.paramCount -} - -func (stmt *mysqlStmt) ColumnConverter(idx int) driver.ValueConverter { - return converter{} -} - -func (stmt *mysqlStmt) CheckNamedValue(nv *driver.NamedValue) (err error) { - nv.Value, err = converter{}.ConvertValue(nv.Value) - return -} - -func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) { - if stmt.mc.closed.IsSet() { - errLog.Print(ErrInvalidConn) - return nil, driver.ErrBadConn - } - // Send command - err := stmt.writeExecutePacket(args) - if err != nil { - return nil, stmt.mc.markBadConn(err) - } - - mc := stmt.mc - - mc.affectedRows = 0 - mc.insertId = 0 - - // Read Result - resLen, err := mc.readResultSetHeaderPacket() - if err != nil { - return nil, err - } - - if resLen > 0 { - // Columns - if err = mc.readUntilEOF(); err != nil { - return nil, err - } - - // Rows - if err := mc.readUntilEOF(); err != nil { - return nil, err - } - } - - if err := mc.discardResults(); err != nil { - return nil, err - } - - return &mysqlResult{ - affectedRows: int64(mc.affectedRows), - insertId: int64(mc.insertId), - }, nil -} - -func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) { - return stmt.query(args) -} - -func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) { - if stmt.mc.closed.IsSet() { - errLog.Print(ErrInvalidConn) - return nil, driver.ErrBadConn - } - // Send command - err := stmt.writeExecutePacket(args) - if err != nil { - return nil, stmt.mc.markBadConn(err) - } - - mc := stmt.mc - - // Read Result - resLen, err := mc.readResultSetHeaderPacket() - if err != nil { - return nil, err - } - - rows := new(binaryRows) - - if resLen > 0 { - rows.mc = mc - rows.rs.columns, err = mc.readColumns(resLen) - } else { - rows.rs.done = true - - switch err := rows.NextResultSet(); err { - case nil, io.EOF: - return rows, nil - default: - return nil, err - } - } - - return rows, err -} - -var jsonType = reflect.TypeOf(json.RawMessage{}) - -type converter struct{} - -// ConvertValue mirrors the reference/default converter in database/sql/driver -// with _one_ exception. We support uint64 with their high bit and the default -// implementation does not. This function should be kept in sync with -// database/sql/driver defaultConverter.ConvertValue() except for that -// deliberate difference. -func (c converter) ConvertValue(v interface{}) (driver.Value, error) { - if driver.IsValue(v) { - return v, nil - } - - if vr, ok := v.(driver.Valuer); ok { - sv, err := callValuerValue(vr) - if err != nil { - return nil, err - } - if driver.IsValue(sv) { - return sv, nil - } - // A value returend from the Valuer interface can be "a type handled by - // a database driver's NamedValueChecker interface" so we should accept - // uint64 here as well. - if u, ok := sv.(uint64); ok { - return u, nil - } - return nil, fmt.Errorf("non-Value type %T returned from Value", sv) - } - rv := reflect.ValueOf(v) - switch rv.Kind() { - case reflect.Ptr: - // indirect pointers - if rv.IsNil() { - return nil, nil - } else { - return c.ConvertValue(rv.Elem().Interface()) - } - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return rv.Int(), nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return rv.Uint(), nil - case reflect.Float32, reflect.Float64: - return rv.Float(), nil - case reflect.Bool: - return rv.Bool(), nil - case reflect.Slice: - switch t := rv.Type(); { - case t == jsonType: - return v, nil - case t.Elem().Kind() == reflect.Uint8: - return rv.Bytes(), nil - default: - return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, t.Elem().Kind()) - } - case reflect.String: - return rv.String(), nil - } - return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind()) -} - -var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem() - -// callValuerValue returns vr.Value(), with one exception: -// If vr.Value is an auto-generated method on a pointer type and the -// pointer is nil, it would panic at runtime in the panicwrap -// method. Treat it like nil instead. -// -// This is so people can implement driver.Value on value types and -// still use nil pointers to those types to mean nil/NULL, just like -// string/*string. -// -// This is an exact copy of the same-named unexported function from the -// database/sql package. -func callValuerValue(vr driver.Valuer) (v driver.Value, err error) { - if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr && - rv.IsNil() && - rv.Type().Elem().Implements(valuerReflectType) { - return nil, nil - } - return vr.Value() -} diff --git a/proxy_go/public/mysql@v1.6.0/statement_test.go b/proxy_go/public/mysql@v1.6.0/statement_test.go deleted file mode 100644 index ac6b92d..0000000 --- a/proxy_go/public/mysql@v1.6.0/statement_test.go +++ /dev/null @@ -1,151 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "bytes" - "database/sql/driver" - "encoding/json" - "testing" -) - -func TestConvertDerivedString(t *testing.T) { - type derived string - - output, err := converter{}.ConvertValue(derived("value")) - if err != nil { - t.Fatal("Derived string type not convertible", err) - } - - if output != "value" { - t.Fatalf("Derived string type not converted, got %#v %T", output, output) - } -} - -func TestConvertDerivedByteSlice(t *testing.T) { - type derived []uint8 - - output, err := converter{}.ConvertValue(derived("value")) - if err != nil { - t.Fatal("Byte slice not convertible", err) - } - - if bytes.Compare(output.([]byte), []byte("value")) != 0 { - t.Fatalf("Byte slice not converted, got %#v %T", output, output) - } -} - -func TestConvertDerivedUnsupportedSlice(t *testing.T) { - type derived []int - - _, err := converter{}.ConvertValue(derived{1}) - if err == nil || err.Error() != "unsupported type mysql.derived, a slice of int" { - t.Fatal("Unexpected error", err) - } -} - -func TestConvertDerivedBool(t *testing.T) { - type derived bool - - output, err := converter{}.ConvertValue(derived(true)) - if err != nil { - t.Fatal("Derived bool type not convertible", err) - } - - if output != true { - t.Fatalf("Derived bool type not converted, got %#v %T", output, output) - } -} - -func TestConvertPointer(t *testing.T) { - str := "value" - - output, err := converter{}.ConvertValue(&str) - if err != nil { - t.Fatal("Pointer type not convertible", err) - } - - if output != "value" { - t.Fatalf("Pointer type not converted, got %#v %T", output, output) - } -} - -func TestConvertSignedIntegers(t *testing.T) { - values := []interface{}{ - int8(-42), - int16(-42), - int32(-42), - int64(-42), - int(-42), - } - - for _, value := range values { - output, err := converter{}.ConvertValue(value) - if err != nil { - t.Fatalf("%T type not convertible %s", value, err) - } - - if output != int64(-42) { - t.Fatalf("%T type not converted, got %#v %T", value, output, output) - } - } -} - -type myUint64 struct { - value uint64 -} - -func (u myUint64) Value() (driver.Value, error) { - return u.value, nil -} - -func TestConvertUnsignedIntegers(t *testing.T) { - values := []interface{}{ - uint8(42), - uint16(42), - uint32(42), - uint64(42), - uint(42), - myUint64{uint64(42)}, - } - - for _, value := range values { - output, err := converter{}.ConvertValue(value) - if err != nil { - t.Fatalf("%T type not convertible %s", value, err) - } - - if output != uint64(42) { - t.Fatalf("%T type not converted, got %#v %T", value, output, output) - } - } - - output, err := converter{}.ConvertValue(^uint64(0)) - if err != nil { - t.Fatal("uint64 high-bit not convertible", err) - } - - if output != ^uint64(0) { - t.Fatalf("uint64 high-bit converted, got %#v %T", output, output) - } -} - -func TestConvertJSON(t *testing.T) { - raw := json.RawMessage("{}") - - out, err := converter{}.ConvertValue(raw) - - if err != nil { - t.Fatal("json.RawMessage was failed in convert", err) - } - - if _, ok := out.(json.RawMessage); !ok { - t.Fatalf("json.RawMessage converted, got %#v %T", out, out) - } -} diff --git a/proxy_go/public/mysql@v1.6.0/transaction.go b/proxy_go/public/mysql@v1.6.0/transaction.go deleted file mode 100644 index 417d727..0000000 --- a/proxy_go/public/mysql@v1.6.0/transaction.go +++ /dev/null @@ -1,31 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -type mysqlTx struct { - mc *mysqlConn -} - -func (tx *mysqlTx) Commit() (err error) { - if tx.mc == nil || tx.mc.closed.IsSet() { - return ErrInvalidConn - } - err = tx.mc.exec("COMMIT") - tx.mc = nil - return -} - -func (tx *mysqlTx) Rollback() (err error) { - if tx.mc == nil || tx.mc.closed.IsSet() { - return ErrInvalidConn - } - err = tx.mc.exec("ROLLBACK") - tx.mc = nil - return -} diff --git a/proxy_go/public/mysql@v1.6.0/utils.go b/proxy_go/public/mysql@v1.6.0/utils.go deleted file mode 100644 index d6545f5..0000000 --- a/proxy_go/public/mysql@v1.6.0/utils.go +++ /dev/null @@ -1,868 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "crypto/tls" - "database/sql" - "database/sql/driver" - "encoding/binary" - "errors" - "fmt" - "io" - "strconv" - "strings" - "sync" - "sync/atomic" - "time" -) - -// Registry for custom tls.Configs -var ( - tlsConfigLock sync.RWMutex - tlsConfigRegistry map[string]*tls.Config -) - -// RegisterTLSConfig registers a custom tls.Config to be used with sql.Open. -// Use the key as a value in the DSN where tls=value. -// -// Note: The provided tls.Config is exclusively owned by the driver after -// registering it. -// -// rootCertPool := x509.NewCertPool() -// pem, err := ioutil.ReadFile("/path/ca-cert.pem") -// if err != nil { -// log.Fatal(err) -// } -// if ok := rootCertPool.AppendCertsFromPEM(pem); !ok { -// log.Fatal("Failed to append PEM.") -// } -// clientCert := make([]tls.Certificate, 0, 1) -// certs, err := tls.LoadX509KeyPair("/path/client-cert.pem", "/path/client-key.pem") -// if err != nil { -// log.Fatal(err) -// } -// clientCert = append(clientCert, certs) -// mysql.RegisterTLSConfig("custom", &tls.Config{ -// RootCAs: rootCertPool, -// Certificates: clientCert, -// }) -// db, err := sql.Open("mysql", "user@tcp(localhost:3306)/test?tls=custom") -// -func RegisterTLSConfig(key string, config *tls.Config) error { - if _, isBool := readBool(key); isBool || strings.ToLower(key) == "skip-verify" || strings.ToLower(key) == "preferred" { - return fmt.Errorf("key '%s' is reserved", key) - } - - tlsConfigLock.Lock() - if tlsConfigRegistry == nil { - tlsConfigRegistry = make(map[string]*tls.Config) - } - - tlsConfigRegistry[key] = config - tlsConfigLock.Unlock() - return nil -} - -// DeregisterTLSConfig removes the tls.Config associated with key. -func DeregisterTLSConfig(key string) { - tlsConfigLock.Lock() - if tlsConfigRegistry != nil { - delete(tlsConfigRegistry, key) - } - tlsConfigLock.Unlock() -} - -func getTLSConfigClone(key string) (config *tls.Config) { - tlsConfigLock.RLock() - if v, ok := tlsConfigRegistry[key]; ok { - config = v.Clone() - } - tlsConfigLock.RUnlock() - return -} - -// Returns the bool value of the input. -// The 2nd return value indicates if the input was a valid bool value -func readBool(input string) (value bool, valid bool) { - switch input { - case "1", "true", "TRUE", "True": - return true, true - case "0", "false", "FALSE", "False": - return false, true - } - - // Not a valid bool value - return -} - -/****************************************************************************** -* Time related utils * -******************************************************************************/ - -func parseDateTime(b []byte, loc *time.Location) (time.Time, error) { - const base = "0000-00-00 00:00:00.000000" - switch len(b) { - case 10, 19, 21, 22, 23, 24, 25, 26: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM" - if string(b) == base[:len(b)] { - return time.Time{}, nil - } - - year, err := parseByteYear(b) - if err != nil { - return time.Time{}, err - } - if year <= 0 { - year = 1 - } - - if b[4] != '-' { - return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[4]) - } - - m, err := parseByte2Digits(b[5], b[6]) - if err != nil { - return time.Time{}, err - } - if m <= 0 { - m = 1 - } - month := time.Month(m) - - if b[7] != '-' { - return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[7]) - } - - day, err := parseByte2Digits(b[8], b[9]) - if err != nil { - return time.Time{}, err - } - if day <= 0 { - day = 1 - } - if len(b) == 10 { - return time.Date(year, month, day, 0, 0, 0, 0, loc), nil - } - - if b[10] != ' ' { - return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[10]) - } - - hour, err := parseByte2Digits(b[11], b[12]) - if err != nil { - return time.Time{}, err - } - if b[13] != ':' { - return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[13]) - } - - min, err := parseByte2Digits(b[14], b[15]) - if err != nil { - return time.Time{}, err - } - if b[16] != ':' { - return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[16]) - } - - sec, err := parseByte2Digits(b[17], b[18]) - if err != nil { - return time.Time{}, err - } - if len(b) == 19 { - return time.Date(year, month, day, hour, min, sec, 0, loc), nil - } - - if b[19] != '.' { - return time.Time{}, fmt.Errorf("bad value for field: `%c`", b[19]) - } - nsec, err := parseByteNanoSec(b[20:]) - if err != nil { - return time.Time{}, err - } - return time.Date(year, month, day, hour, min, sec, nsec, loc), nil - default: - return time.Time{}, fmt.Errorf("invalid time bytes: %s", b) - } -} - -func parseByteYear(b []byte) (int, error) { - year, n := 0, 1000 - for i := 0; i < 4; i++ { - v, err := bToi(b[i]) - if err != nil { - return 0, err - } - year += v * n - n = n / 10 - } - return year, nil -} - -func parseByte2Digits(b1, b2 byte) (int, error) { - d1, err := bToi(b1) - if err != nil { - return 0, err - } - d2, err := bToi(b2) - if err != nil { - return 0, err - } - return d1*10 + d2, nil -} - -func parseByteNanoSec(b []byte) (int, error) { - ns, digit := 0, 100000 // max is 6-digits - for i := 0; i < len(b); i++ { - v, err := bToi(b[i]) - if err != nil { - return 0, err - } - ns += v * digit - digit /= 10 - } - // nanoseconds has 10-digits. (needs to scale digits) - // 10 - 6 = 4, so we have to multiple 1000. - return ns * 1000, nil -} - -func bToi(b byte) (int, error) { - if b < '0' || b > '9' { - return 0, errors.New("not [0-9]") - } - return int(b - '0'), nil -} - -func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Value, error) { - switch num { - case 0: - return time.Time{}, nil - case 4: - return time.Date( - int(binary.LittleEndian.Uint16(data[:2])), // year - time.Month(data[2]), // month - int(data[3]), // day - 0, 0, 0, 0, - loc, - ), nil - case 7: - return time.Date( - int(binary.LittleEndian.Uint16(data[:2])), // year - time.Month(data[2]), // month - int(data[3]), // day - int(data[4]), // hour - int(data[5]), // minutes - int(data[6]), // seconds - 0, - loc, - ), nil - case 11: - return time.Date( - int(binary.LittleEndian.Uint16(data[:2])), // year - time.Month(data[2]), // month - int(data[3]), // day - int(data[4]), // hour - int(data[5]), // minutes - int(data[6]), // seconds - int(binary.LittleEndian.Uint32(data[7:11]))*1000, // nanoseconds - loc, - ), nil - } - return nil, fmt.Errorf("invalid DATETIME packet length %d", num) -} - -func appendDateTime(buf []byte, t time.Time) ([]byte, error) { - year, month, day := t.Date() - hour, min, sec := t.Clock() - nsec := t.Nanosecond() - - if year < 1 || year > 9999 { - return buf, errors.New("year is not in the range [1, 9999]: " + strconv.Itoa(year)) // use errors.New instead of fmt.Errorf to avoid year escape to heap - } - year100 := year / 100 - year1 := year % 100 - - var localBuf [len("2006-01-02T15:04:05.999999999")]byte // does not escape - localBuf[0], localBuf[1], localBuf[2], localBuf[3] = digits10[year100], digits01[year100], digits10[year1], digits01[year1] - localBuf[4] = '-' - localBuf[5], localBuf[6] = digits10[month], digits01[month] - localBuf[7] = '-' - localBuf[8], localBuf[9] = digits10[day], digits01[day] - - if hour == 0 && min == 0 && sec == 0 && nsec == 0 { - return append(buf, localBuf[:10]...), nil - } - - localBuf[10] = ' ' - localBuf[11], localBuf[12] = digits10[hour], digits01[hour] - localBuf[13] = ':' - localBuf[14], localBuf[15] = digits10[min], digits01[min] - localBuf[16] = ':' - localBuf[17], localBuf[18] = digits10[sec], digits01[sec] - - if nsec == 0 { - return append(buf, localBuf[:19]...), nil - } - nsec100000000 := nsec / 100000000 - nsec1000000 := (nsec / 1000000) % 100 - nsec10000 := (nsec / 10000) % 100 - nsec100 := (nsec / 100) % 100 - nsec1 := nsec % 100 - localBuf[19] = '.' - - // milli second - localBuf[20], localBuf[21], localBuf[22] = - digits01[nsec100000000], digits10[nsec1000000], digits01[nsec1000000] - // micro second - localBuf[23], localBuf[24], localBuf[25] = - digits10[nsec10000], digits01[nsec10000], digits10[nsec100] - // nano second - localBuf[26], localBuf[27], localBuf[28] = - digits01[nsec100], digits10[nsec1], digits01[nsec1] - - // trim trailing zeros - n := len(localBuf) - for n > 0 && localBuf[n-1] == '0' { - n-- - } - - return append(buf, localBuf[:n]...), nil -} - -// zeroDateTime is used in formatBinaryDateTime to avoid an allocation -// if the DATE or DATETIME has the zero value. -// It must never be changed. -// The current behavior depends on database/sql copying the result. -var zeroDateTime = []byte("0000-00-00 00:00:00.000000") - -const digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" -const digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999" - -func appendMicrosecs(dst, src []byte, decimals int) []byte { - if decimals <= 0 { - return dst - } - if len(src) == 0 { - return append(dst, ".000000"[:decimals+1]...) - } - - microsecs := binary.LittleEndian.Uint32(src[:4]) - p1 := byte(microsecs / 10000) - microsecs -= 10000 * uint32(p1) - p2 := byte(microsecs / 100) - microsecs -= 100 * uint32(p2) - p3 := byte(microsecs) - - switch decimals { - default: - return append(dst, '.', - digits10[p1], digits01[p1], - digits10[p2], digits01[p2], - digits10[p3], digits01[p3], - ) - case 1: - return append(dst, '.', - digits10[p1], - ) - case 2: - return append(dst, '.', - digits10[p1], digits01[p1], - ) - case 3: - return append(dst, '.', - digits10[p1], digits01[p1], - digits10[p2], - ) - case 4: - return append(dst, '.', - digits10[p1], digits01[p1], - digits10[p2], digits01[p2], - ) - case 5: - return append(dst, '.', - digits10[p1], digits01[p1], - digits10[p2], digits01[p2], - digits10[p3], - ) - } -} - -func formatBinaryDateTime(src []byte, length uint8) (driver.Value, error) { - // length expects the deterministic length of the zero value, - // negative time and 100+ hours are automatically added if needed - if len(src) == 0 { - return zeroDateTime[:length], nil - } - var dst []byte // return value - var p1, p2, p3 byte // current digit pair - - switch length { - case 10, 19, 21, 22, 23, 24, 25, 26: - default: - t := "DATE" - if length > 10 { - t += "TIME" - } - return nil, fmt.Errorf("illegal %s length %d", t, length) - } - switch len(src) { - case 4, 7, 11: - default: - t := "DATE" - if length > 10 { - t += "TIME" - } - return nil, fmt.Errorf("illegal %s packet length %d", t, len(src)) - } - dst = make([]byte, 0, length) - // start with the date - year := binary.LittleEndian.Uint16(src[:2]) - pt := year / 100 - p1 = byte(year - 100*uint16(pt)) - p2, p3 = src[2], src[3] - dst = append(dst, - digits10[pt], digits01[pt], - digits10[p1], digits01[p1], '-', - digits10[p2], digits01[p2], '-', - digits10[p3], digits01[p3], - ) - if length == 10 { - return dst, nil - } - if len(src) == 4 { - return append(dst, zeroDateTime[10:length]...), nil - } - dst = append(dst, ' ') - p1 = src[4] // hour - src = src[5:] - - // p1 is 2-digit hour, src is after hour - p2, p3 = src[0], src[1] - dst = append(dst, - digits10[p1], digits01[p1], ':', - digits10[p2], digits01[p2], ':', - digits10[p3], digits01[p3], - ) - return appendMicrosecs(dst, src[2:], int(length)-20), nil -} - -func formatBinaryTime(src []byte, length uint8) (driver.Value, error) { - // length expects the deterministic length of the zero value, - // negative time and 100+ hours are automatically added if needed - if len(src) == 0 { - return zeroDateTime[11 : 11+length], nil - } - var dst []byte // return value - - switch length { - case - 8, // time (can be up to 10 when negative and 100+ hours) - 10, 11, 12, 13, 14, 15: // time with fractional seconds - default: - return nil, fmt.Errorf("illegal TIME length %d", length) - } - switch len(src) { - case 8, 12: - default: - return nil, fmt.Errorf("invalid TIME packet length %d", len(src)) - } - // +2 to enable negative time and 100+ hours - dst = make([]byte, 0, length+2) - if src[0] == 1 { - dst = append(dst, '-') - } - days := binary.LittleEndian.Uint32(src[1:5]) - hours := int64(days)*24 + int64(src[5]) - - if hours >= 100 { - dst = strconv.AppendInt(dst, hours, 10) - } else { - dst = append(dst, digits10[hours], digits01[hours]) - } - - min, sec := src[6], src[7] - dst = append(dst, ':', - digits10[min], digits01[min], ':', - digits10[sec], digits01[sec], - ) - return appendMicrosecs(dst, src[8:], int(length)-9), nil -} - -/****************************************************************************** -* Convert from and to bytes * -******************************************************************************/ - -func uint64ToBytes(n uint64) []byte { - return []byte{ - byte(n), - byte(n >> 8), - byte(n >> 16), - byte(n >> 24), - byte(n >> 32), - byte(n >> 40), - byte(n >> 48), - byte(n >> 56), - } -} - -func uint64ToString(n uint64) []byte { - var a [20]byte - i := 20 - - // U+0030 = 0 - // ... - // U+0039 = 9 - - var q uint64 - for n >= 10 { - i-- - q = n / 10 - a[i] = uint8(n-q*10) + 0x30 - n = q - } - - i-- - a[i] = uint8(n) + 0x30 - - return a[i:] -} - -// treats string value as unsigned integer representation -func stringToInt(b []byte) int { - val := 0 - for i := range b { - val *= 10 - val += int(b[i] - 0x30) - } - return val -} - -// returns the string read as a bytes slice, wheter the value is NULL, -// the number of bytes read and an error, in case the string is longer than -// the input slice -func readLengthEncodedString(b []byte) ([]byte, bool, int, error) { - // Get length - num, isNull, n := readLengthEncodedInteger(b) - if num < 1 { - return b[n:n], isNull, n, nil - } - - n += int(num) - - // Check data length - if len(b) >= n { - return b[n-int(num) : n : n], false, n, nil - } - return nil, false, n, io.EOF -} - -// returns the number of bytes skipped and an error, in case the string is -// longer than the input slice -func skipLengthEncodedString(b []byte) (int, error) { - // Get length - num, _, n := readLengthEncodedInteger(b) - if num < 1 { - return n, nil - } - - n += int(num) - - // Check data length - if len(b) >= n { - return n, nil - } - return n, io.EOF -} - -// returns the number read, whether the value is NULL and the number of bytes read -func readLengthEncodedInteger(b []byte) (uint64, bool, int) { - // See issue #349 - if len(b) == 0 { - return 0, true, 1 - } - - switch b[0] { - // 251: NULL - case 0xfb: - return 0, true, 1 - - // 252: value of following 2 - case 0xfc: - return uint64(b[1]) | uint64(b[2])<<8, false, 3 - - // 253: value of following 3 - case 0xfd: - return uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16, false, 4 - - // 254: value of following 8 - case 0xfe: - return uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16 | - uint64(b[4])<<24 | uint64(b[5])<<32 | uint64(b[6])<<40 | - uint64(b[7])<<48 | uint64(b[8])<<56, - false, 9 - } - - // 0-250: value of first byte - return uint64(b[0]), false, 1 -} - -// encodes a uint64 value and appends it to the given bytes slice -func appendLengthEncodedInteger(b []byte, n uint64) []byte { - switch { - case n <= 250: - return append(b, byte(n)) - - case n <= 0xffff: - return append(b, 0xfc, byte(n), byte(n>>8)) - - case n <= 0xffffff: - return append(b, 0xfd, byte(n), byte(n>>8), byte(n>>16)) - } - return append(b, 0xfe, byte(n), byte(n>>8), byte(n>>16), byte(n>>24), - byte(n>>32), byte(n>>40), byte(n>>48), byte(n>>56)) -} - -// reserveBuffer checks cap(buf) and expand buffer to len(buf) + appendSize. -// If cap(buf) is not enough, reallocate new buffer. -func reserveBuffer(buf []byte, appendSize int) []byte { - newSize := len(buf) + appendSize - if cap(buf) < newSize { - // Grow buffer exponentially - newBuf := make([]byte, len(buf)*2+appendSize) - copy(newBuf, buf) - buf = newBuf - } - return buf[:newSize] -} - -// escapeBytesBackslash escapes []byte with backslashes (\) -// This escapes the contents of a string (provided as []byte) by adding backslashes before special -// characters, and turning others into specific escape sequences, such as -// turning newlines into \n and null bytes into \0. -// https://github.com/mysql/mysql-server/blob/mysql-5.7.5/mysys/charset.c#L823-L932 -func escapeBytesBackslash(buf, v []byte) []byte { - pos := len(buf) - buf = reserveBuffer(buf, len(v)*2) - - for _, c := range v { - switch c { - case '\x00': - buf[pos] = '\\' - buf[pos+1] = '0' - pos += 2 - case '\n': - buf[pos] = '\\' - buf[pos+1] = 'n' - pos += 2 - case '\r': - buf[pos] = '\\' - buf[pos+1] = 'r' - pos += 2 - case '\x1a': - buf[pos] = '\\' - buf[pos+1] = 'Z' - pos += 2 - case '\'': - buf[pos] = '\\' - buf[pos+1] = '\'' - pos += 2 - case '"': - buf[pos] = '\\' - buf[pos+1] = '"' - pos += 2 - case '\\': - buf[pos] = '\\' - buf[pos+1] = '\\' - pos += 2 - default: - buf[pos] = c - pos++ - } - } - - return buf[:pos] -} - -// escapeStringBackslash is similar to escapeBytesBackslash but for string. -func escapeStringBackslash(buf []byte, v string) []byte { - pos := len(buf) - buf = reserveBuffer(buf, len(v)*2) - - for i := 0; i < len(v); i++ { - c := v[i] - switch c { - case '\x00': - buf[pos] = '\\' - buf[pos+1] = '0' - pos += 2 - case '\n': - buf[pos] = '\\' - buf[pos+1] = 'n' - pos += 2 - case '\r': - buf[pos] = '\\' - buf[pos+1] = 'r' - pos += 2 - case '\x1a': - buf[pos] = '\\' - buf[pos+1] = 'Z' - pos += 2 - case '\'': - buf[pos] = '\\' - buf[pos+1] = '\'' - pos += 2 - case '"': - buf[pos] = '\\' - buf[pos+1] = '"' - pos += 2 - case '\\': - buf[pos] = '\\' - buf[pos+1] = '\\' - pos += 2 - default: - buf[pos] = c - pos++ - } - } - - return buf[:pos] -} - -// escapeBytesQuotes escapes apostrophes in []byte by doubling them up. -// This escapes the contents of a string by doubling up any apostrophes that -// it contains. This is used when the NO_BACKSLASH_ESCAPES SQL_MODE is in -// effect on the server. -// https://github.com/mysql/mysql-server/blob/mysql-5.7.5/mysys/charset.c#L963-L1038 -func escapeBytesQuotes(buf, v []byte) []byte { - pos := len(buf) - buf = reserveBuffer(buf, len(v)*2) - - for _, c := range v { - if c == '\'' { - buf[pos] = '\'' - buf[pos+1] = '\'' - pos += 2 - } else { - buf[pos] = c - pos++ - } - } - - return buf[:pos] -} - -// escapeStringQuotes is similar to escapeBytesQuotes but for string. -func escapeStringQuotes(buf []byte, v string) []byte { - pos := len(buf) - buf = reserveBuffer(buf, len(v)*2) - - for i := 0; i < len(v); i++ { - c := v[i] - if c == '\'' { - buf[pos] = '\'' - buf[pos+1] = '\'' - pos += 2 - } else { - buf[pos] = c - pos++ - } - } - - return buf[:pos] -} - -/****************************************************************************** -* Sync utils * -******************************************************************************/ - -// noCopy may be embedded into structs which must not be copied -// after the first use. -// -// See https://github.com/golang/go/issues/8005#issuecomment-190753527 -// for details. -type noCopy struct{} - -// Lock is a no-op used by -copylocks checker from `go vet`. -func (*noCopy) Lock() {} - -// atomicBool is a wrapper around uint32 for usage as a boolean value with -// atomic access. -type atomicBool struct { - _noCopy noCopy - value uint32 -} - -// IsSet returns whether the current boolean value is true -func (ab *atomicBool) IsSet() bool { - return atomic.LoadUint32(&ab.value) > 0 -} - -// Set sets the value of the bool regardless of the previous value -func (ab *atomicBool) Set(value bool) { - if value { - atomic.StoreUint32(&ab.value, 1) - } else { - atomic.StoreUint32(&ab.value, 0) - } -} - -// TrySet sets the value of the bool and returns whether the value changed -func (ab *atomicBool) TrySet(value bool) bool { - if value { - return atomic.SwapUint32(&ab.value, 1) == 0 - } - return atomic.SwapUint32(&ab.value, 0) > 0 -} - -// atomicError is a wrapper for atomically accessed error values -type atomicError struct { - _noCopy noCopy - value atomic.Value -} - -// Set sets the error value regardless of the previous value. -// The value must not be nil -func (ae *atomicError) Set(value error) { - ae.value.Store(value) -} - -// Value returns the current error value -func (ae *atomicError) Value() error { - if v := ae.value.Load(); v != nil { - // this will panic if the value doesn't implement the error interface - return v.(error) - } - return nil -} - -func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) { - dargs := make([]driver.Value, len(named)) - for n, param := range named { - if len(param.Name) > 0 { - // TODO: support the use of Named Parameters #561 - return nil, errors.New("mysql: driver does not support the use of Named Parameters") - } - dargs[n] = param.Value - } - return dargs, nil -} - -func mapIsolationLevel(level driver.IsolationLevel) (string, error) { - switch sql.IsolationLevel(level) { - case sql.LevelRepeatableRead: - return "REPEATABLE READ", nil - case sql.LevelReadCommitted: - return "READ COMMITTED", nil - case sql.LevelReadUncommitted: - return "READ UNCOMMITTED", nil - case sql.LevelSerializable: - return "SERIALIZABLE", nil - default: - return "", fmt.Errorf("mysql: unsupported isolation level: %v", level) - } -} diff --git a/proxy_go/public/mysql@v1.6.0/utils_test.go b/proxy_go/public/mysql@v1.6.0/utils_test.go deleted file mode 100644 index 67b132d..0000000 --- a/proxy_go/public/mysql@v1.6.0/utils_test.go +++ /dev/null @@ -1,508 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package -// -// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. - -package mysql - -import ( - "bytes" - "database/sql" - "database/sql/driver" - "encoding/binary" - "testing" - "time" -) - -func TestLengthEncodedInteger(t *testing.T) { - var integerTests = []struct { - num uint64 - encoded []byte - }{ - {0x0000000000000000, []byte{0x00}}, - {0x0000000000000012, []byte{0x12}}, - {0x00000000000000fa, []byte{0xfa}}, - {0x0000000000000100, []byte{0xfc, 0x00, 0x01}}, - {0x0000000000001234, []byte{0xfc, 0x34, 0x12}}, - {0x000000000000ffff, []byte{0xfc, 0xff, 0xff}}, - {0x0000000000010000, []byte{0xfd, 0x00, 0x00, 0x01}}, - {0x0000000000123456, []byte{0xfd, 0x56, 0x34, 0x12}}, - {0x0000000000ffffff, []byte{0xfd, 0xff, 0xff, 0xff}}, - {0x0000000001000000, []byte{0xfe, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, - {0x123456789abcdef0, []byte{0xfe, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12}}, - {0xffffffffffffffff, []byte{0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, - } - - for _, tst := range integerTests { - num, isNull, numLen := readLengthEncodedInteger(tst.encoded) - if isNull { - t.Errorf("%x: expected %d, got NULL", tst.encoded, tst.num) - } - if num != tst.num { - t.Errorf("%x: expected %d, got %d", tst.encoded, tst.num, num) - } - if numLen != len(tst.encoded) { - t.Errorf("%x: expected size %d, got %d", tst.encoded, len(tst.encoded), numLen) - } - encoded := appendLengthEncodedInteger(nil, num) - if !bytes.Equal(encoded, tst.encoded) { - t.Errorf("%v: expected %x, got %x", num, tst.encoded, encoded) - } - } -} - -func TestFormatBinaryDateTime(t *testing.T) { - rawDate := [11]byte{} - binary.LittleEndian.PutUint16(rawDate[:2], 1978) // years - rawDate[2] = 12 // months - rawDate[3] = 30 // days - rawDate[4] = 15 // hours - rawDate[5] = 46 // minutes - rawDate[6] = 23 // seconds - binary.LittleEndian.PutUint32(rawDate[7:], 987654) // microseconds - expect := func(expected string, inlen, outlen uint8) { - actual, _ := formatBinaryDateTime(rawDate[:inlen], outlen) - bytes, ok := actual.([]byte) - if !ok { - t.Errorf("formatBinaryDateTime must return []byte, was %T", actual) - } - if string(bytes) != expected { - t.Errorf( - "expected %q, got %q for length in %d, out %d", - expected, actual, inlen, outlen, - ) - } - } - expect("0000-00-00", 0, 10) - expect("0000-00-00 00:00:00", 0, 19) - expect("1978-12-30", 4, 10) - expect("1978-12-30 15:46:23", 7, 19) - expect("1978-12-30 15:46:23.987654", 11, 26) -} - -func TestFormatBinaryTime(t *testing.T) { - expect := func(expected string, src []byte, outlen uint8) { - actual, _ := formatBinaryTime(src, outlen) - bytes, ok := actual.([]byte) - if !ok { - t.Errorf("formatBinaryDateTime must return []byte, was %T", actual) - } - if string(bytes) != expected { - t.Errorf( - "expected %q, got %q for src=%q and outlen=%d", - expected, actual, src, outlen) - } - } - - // binary format: - // sign (0: positive, 1: negative), days(4), hours, minutes, seconds, micro(4) - - // Zeros - expect("00:00:00", []byte{}, 8) - expect("00:00:00.0", []byte{}, 10) - expect("00:00:00.000000", []byte{}, 15) - - // Without micro(4) - expect("12:34:56", []byte{0, 0, 0, 0, 0, 12, 34, 56}, 8) - expect("-12:34:56", []byte{1, 0, 0, 0, 0, 12, 34, 56}, 8) - expect("12:34:56.00", []byte{0, 0, 0, 0, 0, 12, 34, 56}, 11) - expect("24:34:56", []byte{0, 1, 0, 0, 0, 0, 34, 56}, 8) - expect("-99:34:56", []byte{1, 4, 0, 0, 0, 3, 34, 56}, 8) - expect("103079215103:34:56", []byte{0, 255, 255, 255, 255, 23, 34, 56}, 8) - - // With micro(4) - expect("12:34:56.00", []byte{0, 0, 0, 0, 0, 12, 34, 56, 99, 0, 0, 0}, 11) - expect("12:34:56.000099", []byte{0, 0, 0, 0, 0, 12, 34, 56, 99, 0, 0, 0}, 15) -} - -func TestEscapeBackslash(t *testing.T) { - expect := func(expected, value string) { - actual := string(escapeBytesBackslash([]byte{}, []byte(value))) - if actual != expected { - t.Errorf( - "expected %s, got %s", - expected, actual, - ) - } - - actual = string(escapeStringBackslash([]byte{}, value)) - if actual != expected { - t.Errorf( - "expected %s, got %s", - expected, actual, - ) - } - } - - expect("foo\\0bar", "foo\x00bar") - expect("foo\\nbar", "foo\nbar") - expect("foo\\rbar", "foo\rbar") - expect("foo\\Zbar", "foo\x1abar") - expect("foo\\\"bar", "foo\"bar") - expect("foo\\\\bar", "foo\\bar") - expect("foo\\'bar", "foo'bar") -} - -func TestEscapeQuotes(t *testing.T) { - expect := func(expected, value string) { - actual := string(escapeBytesQuotes([]byte{}, []byte(value))) - if actual != expected { - t.Errorf( - "expected %s, got %s", - expected, actual, - ) - } - - actual = string(escapeStringQuotes([]byte{}, value)) - if actual != expected { - t.Errorf( - "expected %s, got %s", - expected, actual, - ) - } - } - - expect("foo\x00bar", "foo\x00bar") // not affected - expect("foo\nbar", "foo\nbar") // not affected - expect("foo\rbar", "foo\rbar") // not affected - expect("foo\x1abar", "foo\x1abar") // not affected - expect("foo''bar", "foo'bar") // affected - expect("foo\"bar", "foo\"bar") // not affected -} - -func TestAtomicBool(t *testing.T) { - var ab atomicBool - if ab.IsSet() { - t.Fatal("Expected value to be false") - } - - ab.Set(true) - if ab.value != 1 { - t.Fatal("Set(true) did not set value to 1") - } - if !ab.IsSet() { - t.Fatal("Expected value to be true") - } - - ab.Set(true) - if !ab.IsSet() { - t.Fatal("Expected value to be true") - } - - ab.Set(false) - if ab.value != 0 { - t.Fatal("Set(false) did not set value to 0") - } - if ab.IsSet() { - t.Fatal("Expected value to be false") - } - - ab.Set(false) - if ab.IsSet() { - t.Fatal("Expected value to be false") - } - if ab.TrySet(false) { - t.Fatal("Expected TrySet(false) to fail") - } - if !ab.TrySet(true) { - t.Fatal("Expected TrySet(true) to succeed") - } - if !ab.IsSet() { - t.Fatal("Expected value to be true") - } - - ab.Set(true) - if !ab.IsSet() { - t.Fatal("Expected value to be true") - } - if ab.TrySet(true) { - t.Fatal("Expected TrySet(true) to fail") - } - if !ab.TrySet(false) { - t.Fatal("Expected TrySet(false) to succeed") - } - if ab.IsSet() { - t.Fatal("Expected value to be false") - } - - ab._noCopy.Lock() // we've "tested" it ¯\_(ツ)_/¯ -} - -func TestAtomicError(t *testing.T) { - var ae atomicError - if ae.Value() != nil { - t.Fatal("Expected value to be nil") - } - - ae.Set(ErrMalformPkt) - if v := ae.Value(); v != ErrMalformPkt { - if v == nil { - t.Fatal("Value is still nil") - } - t.Fatal("Error did not match") - } - ae.Set(ErrPktSync) - if ae.Value() == ErrMalformPkt { - t.Fatal("Error still matches old error") - } - if v := ae.Value(); v != ErrPktSync { - t.Fatal("Error did not match") - } -} - -func TestIsolationLevelMapping(t *testing.T) { - data := []struct { - level driver.IsolationLevel - expected string - }{ - { - level: driver.IsolationLevel(sql.LevelReadCommitted), - expected: "READ COMMITTED", - }, - { - level: driver.IsolationLevel(sql.LevelRepeatableRead), - expected: "REPEATABLE READ", - }, - { - level: driver.IsolationLevel(sql.LevelReadUncommitted), - expected: "READ UNCOMMITTED", - }, - { - level: driver.IsolationLevel(sql.LevelSerializable), - expected: "SERIALIZABLE", - }, - } - - for i, td := range data { - if actual, err := mapIsolationLevel(td.level); actual != td.expected || err != nil { - t.Fatal(i, td.expected, actual, err) - } - } - - // check unsupported mapping - expectedErr := "mysql: unsupported isolation level: 7" - actual, err := mapIsolationLevel(driver.IsolationLevel(sql.LevelLinearizable)) - if actual != "" || err == nil { - t.Fatal("Expected error on unsupported isolation level") - } - if err.Error() != expectedErr { - t.Fatalf("Expected error to be %q, got %q", expectedErr, err) - } -} - -func TestAppendDateTime(t *testing.T) { - tests := []struct { - t time.Time - str string - }{ - { - t: time.Date(1234, 5, 6, 0, 0, 0, 0, time.UTC), - str: "1234-05-06", - }, - { - t: time.Date(4567, 12, 31, 12, 0, 0, 0, time.UTC), - str: "4567-12-31 12:00:00", - }, - { - t: time.Date(2020, 5, 30, 12, 34, 0, 0, time.UTC), - str: "2020-05-30 12:34:00", - }, - { - t: time.Date(2020, 5, 30, 12, 34, 56, 0, time.UTC), - str: "2020-05-30 12:34:56", - }, - { - t: time.Date(2020, 5, 30, 22, 33, 44, 123000000, time.UTC), - str: "2020-05-30 22:33:44.123", - }, - { - t: time.Date(2020, 5, 30, 22, 33, 44, 123456000, time.UTC), - str: "2020-05-30 22:33:44.123456", - }, - { - t: time.Date(2020, 5, 30, 22, 33, 44, 123456789, time.UTC), - str: "2020-05-30 22:33:44.123456789", - }, - { - t: time.Date(9999, 12, 31, 23, 59, 59, 999999999, time.UTC), - str: "9999-12-31 23:59:59.999999999", - }, - { - t: time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC), - str: "0001-01-01", - }, - } - for _, v := range tests { - buf := make([]byte, 0, 32) - buf, _ = appendDateTime(buf, v.t) - if str := string(buf); str != v.str { - t.Errorf("appendDateTime(%v), have: %s, want: %s", v.t, str, v.str) - } - } - - // year out of range - { - v := time.Date(0, 1, 1, 0, 0, 0, 0, time.UTC) - buf := make([]byte, 0, 32) - _, err := appendDateTime(buf, v) - if err == nil { - t.Error("want an error") - return - } - } - { - v := time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC) - buf := make([]byte, 0, 32) - _, err := appendDateTime(buf, v) - if err == nil { - t.Error("want an error") - return - } - } -} - -func TestParseDateTime(t *testing.T) { - cases := []struct { - name string - str string - }{ - { - name: "parse date", - str: "2020-05-13", - }, - { - name: "parse null date", - str: sDate0, - }, - { - name: "parse datetime", - str: "2020-05-13 21:30:45", - }, - { - name: "parse null datetime", - str: sDateTime0, - }, - { - name: "parse datetime nanosec 1-digit", - str: "2020-05-25 23:22:01.1", - }, - { - name: "parse datetime nanosec 2-digits", - str: "2020-05-25 23:22:01.15", - }, - { - name: "parse datetime nanosec 3-digits", - str: "2020-05-25 23:22:01.159", - }, - { - name: "parse datetime nanosec 4-digits", - str: "2020-05-25 23:22:01.1594", - }, - { - name: "parse datetime nanosec 5-digits", - str: "2020-05-25 23:22:01.15949", - }, - { - name: "parse datetime nanosec 6-digits", - str: "2020-05-25 23:22:01.159491", - }, - } - - for _, loc := range []*time.Location{ - time.UTC, - time.FixedZone("test", 8*60*60), - } { - for _, cc := range cases { - t.Run(cc.name+"-"+loc.String(), func(t *testing.T) { - var want time.Time - if cc.str != sDate0 && cc.str != sDateTime0 { - var err error - want, err = time.ParseInLocation(timeFormat[:len(cc.str)], cc.str, loc) - if err != nil { - t.Fatal(err) - } - } - got, err := parseDateTime([]byte(cc.str), loc) - if err != nil { - t.Fatal(err) - } - - if !want.Equal(got) { - t.Fatalf("want: %v, but got %v", want, got) - } - }) - } - } -} - -func TestParseDateTimeFail(t *testing.T) { - cases := []struct { - name string - str string - wantErr string - }{ - { - name: "parse invalid time", - str: "hello", - wantErr: "invalid time bytes: hello", - }, - { - name: "parse year", - str: "000!-00-00 00:00:00.000000", - wantErr: "not [0-9]", - }, - { - name: "parse month", - str: "0000-!0-00 00:00:00.000000", - wantErr: "not [0-9]", - }, - { - name: `parse "-" after parsed year`, - str: "0000:00-00 00:00:00.000000", - wantErr: "bad value for field: `:`", - }, - { - name: `parse "-" after parsed month`, - str: "0000-00:00 00:00:00.000000", - wantErr: "bad value for field: `:`", - }, - { - name: `parse " " after parsed date`, - str: "0000-00-00+00:00:00.000000", - wantErr: "bad value for field: `+`", - }, - { - name: `parse ":" after parsed date`, - str: "0000-00-00 00-00:00.000000", - wantErr: "bad value for field: `-`", - }, - { - name: `parse ":" after parsed hour`, - str: "0000-00-00 00:00-00.000000", - wantErr: "bad value for field: `-`", - }, - { - name: `parse "." after parsed sec`, - str: "0000-00-00 00:00:00?000000", - wantErr: "bad value for field: `?`", - }, - } - - for _, cc := range cases { - t.Run(cc.name, func(t *testing.T) { - got, err := parseDateTime([]byte(cc.str), time.UTC) - if err == nil { - t.Fatal("want error") - } - if cc.wantErr != err.Error() { - t.Fatalf("want `%s`, but got `%s`", cc.wantErr, err) - } - if !got.IsZero() { - t.Fatal("want zero time") - } - }) - } -} diff --git a/proxy_go/selfcareproxy b/proxy_go/selfcareproxy deleted file mode 100755 index 7e0dac1..0000000 Binary files a/proxy_go/selfcareproxy and /dev/null differ diff --git a/proxy_go/util/logger_conf/.gitignore b/proxy_go/util/logger_conf/.gitignore deleted file mode 100644 index 275ff8b..0000000 --- a/proxy_go/util/logger_conf/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# Toolchain -# Goland project folder -.idea/ -# Visual Studio Code -.vscode/ -# emacs/vim -GPATH -GRTAGS -GTAGS -TAGS -tags -cscope.* -# mac -.DS_Store diff --git a/proxy_go/util/logger_conf/.golangci.yml b/proxy_go/util/logger_conf/.golangci.yml deleted file mode 100644 index eae90a1..0000000 --- a/proxy_go/util/logger_conf/.golangci.yml +++ /dev/null @@ -1,289 +0,0 @@ -# This file contains all available configuration options -# with their default values. -# options for analysis running -run: - # default concurrency is a available CPU number - concurrency: 4 - # timeout for analysis, e.g. 30s, 5m, default is 1m - timeout: 1m - # exit code when at least one issue was found, default is 1 - issues-exit-code: 1 - # include test files or not, default is true - tests: false - # list of build tags, all linters use it. Default is empty list. - build-tags: - # which dirs to skip: issues from them won't be reported; - # can use regexp here: generated.*, regexp is applied on full path; - # default value is empty list, but default dirs are skipped independently - # from this option's value (see skip-dirs-use-default). - # "/" will be replaced by current OS file path separator to properly work - # on Windows. - skip-dirs: - # default is true. Enables skipping of directories: - # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - skip-dirs-use-default: true - # which files to skip: they will be analyzed, but issues from them - # won't be reported. Default value is empty list, but there is - # no need to include all autogenerated files, we confidently recognize - # autogenerated files. If it's not please let us know. - # "/" will be replaced by current OS file path separator to properly work - # on Windows. - skip-files: - - "api_.*\\.go$" - - "model_.*\\.go$" - - "routers.go" - - "client.go" - - "configuration.go" - - "nas.go" - # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": - # If invoked with -mod=readonly, the go command is disallowed from the implicit - # automatic updating of go.mod described above. Instead, it fails when any changes - # to go.mod are needed. This setting is most useful to check that go.mod does - # not need updates, such as in a continuous integration and testing system. - # If invoked with -mod=vendor, the go command assumes that the vendor - # directory holds the correct copies of dependencies and ignores - # the dependency descriptions in go.mod. - #modules-download-mode: readonly|release|vendor - # Allow multiple parallel golangci-lint instances running. - # If false (default) - golangci-lint acquires file lock on start. - allow-parallel-runners: true -# output configuration options -output: - # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" - format: colored-line-number - # print lines of code with issue, default is true - print-issued-lines: true - # print linter name in the end of issue text, default is true - print-linter-name: true - # make issues output unique by line, default is true - uniq-by-line: true -# all available settings of specific linters -linters-settings: - errcheck: - # report about not checking of errors in type assertions: `a := b.(MyStruct)`; - # default is false: such cases aren't reported by default. - check-type-assertions: false - # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; - # default is false: such cases aren't reported by default. - check-blank: true - # [deprecated] comma-separated list of pairs of the form pkg:regex - # the regex is used to ignore names within pkg. (default "fmt:.*"). - # see https://github.com/kisielk/errcheck#the-deprecated-method for details - #ignore: fmt:.*,io/ioutil:^Read.* - # path to a file containing a list of functions to exclude from checking - # see https://github.com/kisielk/errcheck#excluding-functions for details - #exclude: /path/to/file.txt - funlen: - lines: 60 - statements: 40 - gocognit: - # minimal code complexity to report, 30 by default (but we recommend 10-20) - min-complexity: 10 - nestif: - # minimal complexity of if statements to report, 5 by default - min-complexity: 4 - goconst: - # minimal length of string constant, 3 by default - min-len: 3 - # minimal occurrences count to trigger, 3 by default - min-occurrences: 3 - gocritic: - # Which checks should be enabled; can't be combined with 'disabled-checks'; - # See https://go-critic.github.io/overview#checks-overview - # To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run` - # By default list of stable checks is used. - enabled-checks: - #- rangeValCopy - # Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty - disabled-checks: - - regexpMust - # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks. - # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags". - enabled-tags: - - performance - disabled-tags: - - experimental - settings: # settings passed to gocritic - captLocal: # must be valid enabled check name - paramsOnly: true - rangeValCopy: - sizeThreshold: 32 - gocyclo: - # minimal code complexity to report, 30 by default (but we recommend 10-20) - min-complexity: 10 - godox: - # report any comments starting with keywords, this is useful for TODO or FIXME comments that - # might be left in the code accidentally and should be resolved before merging - keywords: # default keywords are TODO, BUG, and FIXME, these can be overwritten by this setting - #- TODO - - FIXME - - BUG - #- NOTE - #- OPTIMIZE # marks code that should be optimized before merging - #- HACK # marks hack-arounds that should be removed before merging - - XXX # Fatal! Important problem - gofmt: - # simplify code: gofmt with `-s` option, true by default - simplify: true - goimports: - # put imports beginning with prefix after 3rd-party packages; - # it's a comma-separated list of prefixes - local-prefixes: github.com/org/project - golint: - # minimal confidence for issues, default is 0.8 - min-confidence: 0.8 - gomnd: - settings: - mnd: - # the list of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description. - checks: argument,case,condition,operation,return,assign - gomodguard: - allowed: - modules: # List of allowed modules - # - gopkg.in/yaml.v2 - domains: # List of allowed module domains - # - golang.org - blocked: - modules: # List of blocked modules - # - github.com/uudashr/go-module: # Blocked module - # recommendations: # Recommended modules that should be used instead (Optional) - # - golang.org/x/mod - # reason: "`mod` is the official go.mod parser library." # Reason why the recommended module should be used (Optional) - versions: # List of blocked module version constraints - # - github.com/mitchellh/go-homedir: # Blocked module with version constraint - # version: "< 1.1.0" # Version constraint, see https://github.com/Masterminds/semver#basic-comparisons - # reason: "testing if blocked version constraint works." # Reason why the version constraint exists. (Optional) - govet: - # report about shadowed variables - check-shadowing: true - # settings per analyzer - settings: - printf: # analyzer name, run `go tool vet help` to see all analyzers - funcs: # run `go tool vet help printf` to see available settings for `printf` analyzer - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf - # enable or disable analyzers by name - enable: - - atomicalign - enable-all: false - disable: - - shadow - disable-all: false - depguard: - list-type: blacklist - include-go-root: false - packages: - - github.com/sirupsen/logrus - packages-with-error-message: - # specify an error message to output when a blacklisted package is used - - github.com/sirupsen/logrus: "logging is allowed only by logutils.Log" - lll: - # max line length, lines longer will be reported. Default is 120. - # '\t' is counted as 1 character by default, and can be changed with the tab-width option - line-length: 120 - # tab width in spaces. Default to 1. - tab-width: 1 - maligned: - # print struct with more effective memory layout or not, false by default - suggest-new: true - nakedret: - # make an issue if func has more lines of code than this setting and it has naked returns; default is 30 - max-func-lines: 30 - testpackage: - # regexp pattern to skip files - skip-regexp: (export|internal)_test\.go - unused: - # treat code as a program (not a library) and report unused exported identifiers; default is false. - # XXX: if you enable this setting, unused will report a lot of false-positives in text editors: - # if it's called for subdir of a project it can't find funcs usages. All text editor integrations - # with golangci-lint call it on a directory with the changed file. - check-exported: false - whitespace: - multi-if: false # Enforces newlines (or comments) after every multi-line if statement - multi-func: false # Enforces newlines (or comments) after every multi-line function signature - custom: - # Each custom linter should have a unique name. - -linters: - enable: - - gofmt - - govet - - errcheck - - staticcheck - - unused - - gosimple - - structcheck - - varcheck - - ineffassign - - deadcode - - typecheck - # Additional - - lll - - godox - # - gomnd - #- maligned - #- nestif - #- goconst - #- gocognit - - nakedret - #disable-all: false - fast: true -issues: - # List of regexps of issue texts to exclude, empty list by default. - # But independently from this option we use default exclude patterns, - # it can be disabled by `exclude-use-default: false`. To list all - # excluded by default patterns execute `golangci-lint run --help` - exclude: - # Excluding configuration per-path, per-linter, per-text and per-source - exclude-rules: - # Exclude some linters from running on tests files. - # Independently from option `exclude` we use default exclude patterns, - # it can be disabled by this option. To list all - # excluded by default patterns execute `golangci-lint run --help`. - # Default value for this option is true. - exclude-use-default: false - # The default value is false. If set to true exclude and exclude-rules - # regular expressions become case sensitive. - exclude-case-sensitive: false - # The list of ids of default excludes to include or disable. By default it's empty. - include: - #- EXC0002 # disable excluding of issues about comments from golint - # Maximum issues count per one linter. Set to 0 to disable. Default is 50. - #max-issues-per-linter: 0 - # Maximum count of issues with the same text. Set to 0 to disable. Default is 3. - #max-same-issues: 0 - # Show only new issues: if there are unstaged changes or untracked files, - # only those changes are analyzed, else only changes in HEAD~ are analyzed. - # It's a super-useful option for integration of golangci-lint into existing - # large codebase. It's not practical to fix all existing issues at the moment - # of integration: much better don't allow issues in new code. - # Default is false. - new: false - # Show only new issues created after git revision `REV` - new-from-rev: "" - # Show only new issues created in git patch with set file path. - #new-from-patch: path/to/patch/file -severity: - # Default value is empty string. - # Set the default severity for issues. If severity rules are defined and the issues - # do not match or no severity is provided to the rule this will be the default - # severity applied. Severities should match the supported severity names of the - # selected out format. - # - Code climate: https://docs.codeclimate.com/docs/issues#issue-severity - # - Checkstyle: https://checkstyle.sourceforge.io/property_types.html#severity - # - Github: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message - default-severity: error - # The default value is false. - # If set to true severity-rules regular expressions become case sensitive. - case-sensitive: false - # Default value is empty list. - # When a list of severity rules are provided, severity information will be added to lint - # issues. Severity rules have the same filtering capability as exclude rules except you - # are allowed to specify one matcher per severity rule. - # Only affects out formats that support setting severity information. - rules: - - linters: - - gomnd - severity: ignore diff --git a/proxy_go/util/logger_conf/LICENSE.txt b/proxy_go/util/logger_conf/LICENSE.txt deleted file mode 100644 index 4124f39..0000000 --- a/proxy_go/util/logger_conf/LICENSE.txt +++ /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 2019 Communication Service/Software Laboratory, National Chiao Tung University - - 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/proxy_go/util/logger_util/.gitignore b/proxy_go/util/logger_util/.gitignore deleted file mode 100644 index 05fa7d7..0000000 --- a/proxy_go/util/logger_util/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -# Toolchain -# Goland project folder -.idea/ -# Visual Studio Code -.vscode/ -# emacs/vim -GPATH -GRTAGS -GTAGS -TAGS -tags -cscope.* -# mac -.DS_Store - diff --git a/proxy_go/util/logger_util/.golangci.yml b/proxy_go/util/logger_util/.golangci.yml deleted file mode 100644 index eae90a1..0000000 --- a/proxy_go/util/logger_util/.golangci.yml +++ /dev/null @@ -1,289 +0,0 @@ -# This file contains all available configuration options -# with their default values. -# options for analysis running -run: - # default concurrency is a available CPU number - concurrency: 4 - # timeout for analysis, e.g. 30s, 5m, default is 1m - timeout: 1m - # exit code when at least one issue was found, default is 1 - issues-exit-code: 1 - # include test files or not, default is true - tests: false - # list of build tags, all linters use it. Default is empty list. - build-tags: - # which dirs to skip: issues from them won't be reported; - # can use regexp here: generated.*, regexp is applied on full path; - # default value is empty list, but default dirs are skipped independently - # from this option's value (see skip-dirs-use-default). - # "/" will be replaced by current OS file path separator to properly work - # on Windows. - skip-dirs: - # default is true. Enables skipping of directories: - # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - skip-dirs-use-default: true - # which files to skip: they will be analyzed, but issues from them - # won't be reported. Default value is empty list, but there is - # no need to include all autogenerated files, we confidently recognize - # autogenerated files. If it's not please let us know. - # "/" will be replaced by current OS file path separator to properly work - # on Windows. - skip-files: - - "api_.*\\.go$" - - "model_.*\\.go$" - - "routers.go" - - "client.go" - - "configuration.go" - - "nas.go" - # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": - # If invoked with -mod=readonly, the go command is disallowed from the implicit - # automatic updating of go.mod described above. Instead, it fails when any changes - # to go.mod are needed. This setting is most useful to check that go.mod does - # not need updates, such as in a continuous integration and testing system. - # If invoked with -mod=vendor, the go command assumes that the vendor - # directory holds the correct copies of dependencies and ignores - # the dependency descriptions in go.mod. - #modules-download-mode: readonly|release|vendor - # Allow multiple parallel golangci-lint instances running. - # If false (default) - golangci-lint acquires file lock on start. - allow-parallel-runners: true -# output configuration options -output: - # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" - format: colored-line-number - # print lines of code with issue, default is true - print-issued-lines: true - # print linter name in the end of issue text, default is true - print-linter-name: true - # make issues output unique by line, default is true - uniq-by-line: true -# all available settings of specific linters -linters-settings: - errcheck: - # report about not checking of errors in type assertions: `a := b.(MyStruct)`; - # default is false: such cases aren't reported by default. - check-type-assertions: false - # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; - # default is false: such cases aren't reported by default. - check-blank: true - # [deprecated] comma-separated list of pairs of the form pkg:regex - # the regex is used to ignore names within pkg. (default "fmt:.*"). - # see https://github.com/kisielk/errcheck#the-deprecated-method for details - #ignore: fmt:.*,io/ioutil:^Read.* - # path to a file containing a list of functions to exclude from checking - # see https://github.com/kisielk/errcheck#excluding-functions for details - #exclude: /path/to/file.txt - funlen: - lines: 60 - statements: 40 - gocognit: - # minimal code complexity to report, 30 by default (but we recommend 10-20) - min-complexity: 10 - nestif: - # minimal complexity of if statements to report, 5 by default - min-complexity: 4 - goconst: - # minimal length of string constant, 3 by default - min-len: 3 - # minimal occurrences count to trigger, 3 by default - min-occurrences: 3 - gocritic: - # Which checks should be enabled; can't be combined with 'disabled-checks'; - # See https://go-critic.github.io/overview#checks-overview - # To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run` - # By default list of stable checks is used. - enabled-checks: - #- rangeValCopy - # Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty - disabled-checks: - - regexpMust - # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks. - # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags". - enabled-tags: - - performance - disabled-tags: - - experimental - settings: # settings passed to gocritic - captLocal: # must be valid enabled check name - paramsOnly: true - rangeValCopy: - sizeThreshold: 32 - gocyclo: - # minimal code complexity to report, 30 by default (but we recommend 10-20) - min-complexity: 10 - godox: - # report any comments starting with keywords, this is useful for TODO or FIXME comments that - # might be left in the code accidentally and should be resolved before merging - keywords: # default keywords are TODO, BUG, and FIXME, these can be overwritten by this setting - #- TODO - - FIXME - - BUG - #- NOTE - #- OPTIMIZE # marks code that should be optimized before merging - #- HACK # marks hack-arounds that should be removed before merging - - XXX # Fatal! Important problem - gofmt: - # simplify code: gofmt with `-s` option, true by default - simplify: true - goimports: - # put imports beginning with prefix after 3rd-party packages; - # it's a comma-separated list of prefixes - local-prefixes: github.com/org/project - golint: - # minimal confidence for issues, default is 0.8 - min-confidence: 0.8 - gomnd: - settings: - mnd: - # the list of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description. - checks: argument,case,condition,operation,return,assign - gomodguard: - allowed: - modules: # List of allowed modules - # - gopkg.in/yaml.v2 - domains: # List of allowed module domains - # - golang.org - blocked: - modules: # List of blocked modules - # - github.com/uudashr/go-module: # Blocked module - # recommendations: # Recommended modules that should be used instead (Optional) - # - golang.org/x/mod - # reason: "`mod` is the official go.mod parser library." # Reason why the recommended module should be used (Optional) - versions: # List of blocked module version constraints - # - github.com/mitchellh/go-homedir: # Blocked module with version constraint - # version: "< 1.1.0" # Version constraint, see https://github.com/Masterminds/semver#basic-comparisons - # reason: "testing if blocked version constraint works." # Reason why the version constraint exists. (Optional) - govet: - # report about shadowed variables - check-shadowing: true - # settings per analyzer - settings: - printf: # analyzer name, run `go tool vet help` to see all analyzers - funcs: # run `go tool vet help printf` to see available settings for `printf` analyzer - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf - # enable or disable analyzers by name - enable: - - atomicalign - enable-all: false - disable: - - shadow - disable-all: false - depguard: - list-type: blacklist - include-go-root: false - packages: - - github.com/sirupsen/logrus - packages-with-error-message: - # specify an error message to output when a blacklisted package is used - - github.com/sirupsen/logrus: "logging is allowed only by logutils.Log" - lll: - # max line length, lines longer will be reported. Default is 120. - # '\t' is counted as 1 character by default, and can be changed with the tab-width option - line-length: 120 - # tab width in spaces. Default to 1. - tab-width: 1 - maligned: - # print struct with more effective memory layout or not, false by default - suggest-new: true - nakedret: - # make an issue if func has more lines of code than this setting and it has naked returns; default is 30 - max-func-lines: 30 - testpackage: - # regexp pattern to skip files - skip-regexp: (export|internal)_test\.go - unused: - # treat code as a program (not a library) and report unused exported identifiers; default is false. - # XXX: if you enable this setting, unused will report a lot of false-positives in text editors: - # if it's called for subdir of a project it can't find funcs usages. All text editor integrations - # with golangci-lint call it on a directory with the changed file. - check-exported: false - whitespace: - multi-if: false # Enforces newlines (or comments) after every multi-line if statement - multi-func: false # Enforces newlines (or comments) after every multi-line function signature - custom: - # Each custom linter should have a unique name. - -linters: - enable: - - gofmt - - govet - - errcheck - - staticcheck - - unused - - gosimple - - structcheck - - varcheck - - ineffassign - - deadcode - - typecheck - # Additional - - lll - - godox - # - gomnd - #- maligned - #- nestif - #- goconst - #- gocognit - - nakedret - #disable-all: false - fast: true -issues: - # List of regexps of issue texts to exclude, empty list by default. - # But independently from this option we use default exclude patterns, - # it can be disabled by `exclude-use-default: false`. To list all - # excluded by default patterns execute `golangci-lint run --help` - exclude: - # Excluding configuration per-path, per-linter, per-text and per-source - exclude-rules: - # Exclude some linters from running on tests files. - # Independently from option `exclude` we use default exclude patterns, - # it can be disabled by this option. To list all - # excluded by default patterns execute `golangci-lint run --help`. - # Default value for this option is true. - exclude-use-default: false - # The default value is false. If set to true exclude and exclude-rules - # regular expressions become case sensitive. - exclude-case-sensitive: false - # The list of ids of default excludes to include or disable. By default it's empty. - include: - #- EXC0002 # disable excluding of issues about comments from golint - # Maximum issues count per one linter. Set to 0 to disable. Default is 50. - #max-issues-per-linter: 0 - # Maximum count of issues with the same text. Set to 0 to disable. Default is 3. - #max-same-issues: 0 - # Show only new issues: if there are unstaged changes or untracked files, - # only those changes are analyzed, else only changes in HEAD~ are analyzed. - # It's a super-useful option for integration of golangci-lint into existing - # large codebase. It's not practical to fix all existing issues at the moment - # of integration: much better don't allow issues in new code. - # Default is false. - new: false - # Show only new issues created after git revision `REV` - new-from-rev: "" - # Show only new issues created in git patch with set file path. - #new-from-patch: path/to/patch/file -severity: - # Default value is empty string. - # Set the default severity for issues. If severity rules are defined and the issues - # do not match or no severity is provided to the rule this will be the default - # severity applied. Severities should match the supported severity names of the - # selected out format. - # - Code climate: https://docs.codeclimate.com/docs/issues#issue-severity - # - Checkstyle: https://checkstyle.sourceforge.io/property_types.html#severity - # - Github: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message - default-severity: error - # The default value is false. - # If set to true severity-rules regular expressions become case sensitive. - case-sensitive: false - # Default value is empty list. - # When a list of severity rules are provided, severity information will be added to lint - # issues. Severity rules have the same filtering capability as exclude rules except you - # are allowed to specify one matcher per severity rule. - # Only affects out formats that support setting severity information. - rules: - - linters: - - gomnd - severity: ignore diff --git a/proxy_go/util/logger_util/CHANGELOG.md b/proxy_go/util/logger_util/CHANGELOG.md deleted file mode 100644 index f465a20..0000000 --- a/proxy_go/util/logger_util/CHANGELOG.md +++ /dev/null @@ -1,9 +0,0 @@ -# Change Log ---- -2020-03-xx-xx ---- -- Implemented enchacements: - -- Fixed bugs: - -- Closed issues: diff --git a/proxy_go/util/logger_util/LICENSE.txt b/proxy_go/util/logger_util/LICENSE.txt deleted file mode 100644 index 4124f39..0000000 --- a/proxy_go/util/logger_util/LICENSE.txt +++ /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 2019 Communication Service/Software Laboratory, National Chiao Tung University - - 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/proxy_go/util/logger_util/log_level.go b/proxy_go/util/logger_util/log_level.go deleted file mode 100644 index e016ae8..0000000 --- a/proxy_go/util/logger_util/log_level.go +++ /dev/null @@ -1,42 +0,0 @@ -package logger_util - -type Logger struct { - AMF *LogSetting `yaml:"AMF"` - AUSF *LogSetting `yaml:"AUSF"` - N3IWF *LogSetting `yaml:"N3IWF"` - NRF *LogSetting `yaml:"NRF"` - NSSF *LogSetting `yaml:"NSSF"` - PCF *LogSetting `yaml:"PCF"` - SMF *LogSetting `yaml:"SMF"` - UDM *LogSetting `yaml:"UDM"` - UDR *LogSetting `yaml:"UDR"` - NEF *LogSetting `yaml:"NEF"` - WEBUI *LogSetting `yaml:"WEBUI"` - - Aper *LogSetting `yaml:"Aper"` - CommonConsumerTest *LogSetting `yaml:"CommonConsumerTest"` - FSM *LogSetting `yaml:"FSM"` - MongoDBLibrary *LogSetting `yaml:"MongoDBLibrary"` - NAS *LogSetting `yaml:"NAS"` - NGAP *LogSetting `yaml:"NGAP"` - OpenApi *LogSetting `yaml:"OpenApi"` - NamfCommunication *LogSetting `yaml:"NamfCommunication"` - NamfEventExposure *LogSetting `yaml:"NamfEventExposure"` - NnssfNSSAIAvailability *LogSetting `yaml:"NnssfNSSAIAvailability"` - NnssfNSSelection *LogSetting `yaml:"NnssfNSSelection"` - NsmfEventExposure *LogSetting `yaml:"NsmfEventExposure"` - NsmfPDUSession *LogSetting `yaml:"NsmfPDUSession"` - NudmEventExposure *LogSetting `yaml:"NudmEventExposure"` - NudmParameterProvision *LogSetting `yaml:"NudmParameterProvision"` - NudmSubscriberDataManagement *LogSetting `yaml:"NudmSubscriberDataManagement"` - NudmUEAuthentication *LogSetting `yaml:"NudmUEAuthentication"` - NudmUEContextManagement *LogSetting `yaml:"NudmUEContextManagement"` - NudrDataRepository *LogSetting `yaml:"NudrDataRepository"` - PathUtil *LogSetting `yaml:"PathUtil"` - PFCP *LogSetting `yaml:"PFCP"` -} - -type LogSetting struct { - DebugLevel string `yaml:"debugLevel"` - ReportCaller bool `yaml:"ReportCaller"` -} diff --git a/proxy_go/util/logger_util/version/version.go b/proxy_go/util/logger_util/version/version.go deleted file mode 100644 index f89f034..0000000 --- a/proxy_go/util/logger_util/version/version.go +++ /dev/null @@ -1,7 +0,0 @@ -package version - -var VERSION = "2020-03-31-01" - -func GetVersion() (version string) { - return VERSION -}