mirror of
https://github.com/Li4n0/revsuit.git
synced 2026-09-21 22:30:46 +08:00
Use golint to normalize the code (#1)
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
package dns
|
||||
|
||||
type Config struct {
|
||||
Enable bool
|
||||
Enable bool
|
||||
}
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ func newRecord(rule *Rule, flag, domain, remoteIp, ipArea string) (r *Record, er
|
||||
Rule: *rule,
|
||||
}
|
||||
err = database.DB.Create(r).Error
|
||||
return
|
||||
return r, err
|
||||
}
|
||||
|
||||
func List(c *gin.Context) {
|
||||
|
||||
+2
-3
@@ -59,7 +59,7 @@ func (r *Rule) CreateOrUpdate() (err error) {
|
||||
return
|
||||
}
|
||||
err = GetServer().updateRules()
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete the dns rule in database and ruleSet
|
||||
@@ -70,7 +70,7 @@ func (r *Rule) Delete() (err error) {
|
||||
return
|
||||
}
|
||||
err = GetServer().updateRules()
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// List all dns rules those satisfy the filter
|
||||
@@ -194,5 +194,4 @@ func DeleteRules(c *gin.Context) {
|
||||
"error": nil,
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
package mysql
|
||||
|
||||
type Config struct {
|
||||
Enable bool
|
||||
Addr string
|
||||
Enable bool
|
||||
Addr string
|
||||
VersionString string `yaml:"version_string"`
|
||||
}
|
||||
|
||||
+1
-1
@@ -227,7 +227,7 @@ func (s *Server) ComQuery(c *vmysql.Conn, query string, callback func(*sqltypes.
|
||||
if c.Files[filename] == nil {
|
||||
log.Trace("MySQL now try to read file [%s], ID [%d]", filename, c.ConnectionID)
|
||||
data := c.RequestFile(filename)
|
||||
if data == nil || len(data) == 0 {
|
||||
if len(data) == 0 {
|
||||
log.Trace("MySQL file [%s] read failed, file may not exist in client [%d]", filename, c.ConnectionID)
|
||||
c.Files[filename] = []byte{}
|
||||
} else {
|
||||
|
||||
@@ -13,5 +13,6 @@ func TestServer_NewConnection(t *testing.T) {
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
db.Exec("SELECT 1;")
|
||||
|
||||
_, _ = db.Exec("SELECT 1;")
|
||||
}
|
||||
|
||||
+7
-8
@@ -14,13 +14,12 @@ var _ record.Record = (*Record)(nil)
|
||||
|
||||
type Record struct {
|
||||
record.BaseRecord
|
||||
Username string `gorm:"index",form:"username" json:"username" notice:"username"`
|
||||
ClientName string `gorm:"index",form:"client_name" json:"client_name" notice:"client_name"`
|
||||
ClientOS string `gorm:"index",form:"client_os" json:"client_os" notice:"client_os"`
|
||||
LoadLocalData bool `gorm:"index",form:"load_local_data" json:"load_local_data" notice:"load_local_data"`
|
||||
//FileID uint `form:"file_id" json:"file_id" notice:"file_id"`
|
||||
Files []File `form:"-" json:"files" notice:"-"`
|
||||
Rule Rule `gorm:"foreignKey:RuleName;references:Name;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" form:"-" json:"-" notice:"-"`
|
||||
Username string `gorm:"index" form:"username" json:"username" notice:"username"`
|
||||
ClientName string `gorm:"index" form:"client_name" json:"client_name" notice:"client_name"`
|
||||
ClientOS string `gorm:"index" form:"client_os" json:"client_os" notice:"client_os"`
|
||||
LoadLocalData bool `gorm:"index" form:"load_local_data" json:"load_local_data" notice:"load_local_data"`
|
||||
Files []File `form:"-" json:"files" notice:"-"`
|
||||
Rule Rule `gorm:"foreignKey:RuleName;references:Name;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" form:"-" json:"-" notice:"-"`
|
||||
}
|
||||
|
||||
func (Record) TableName() string {
|
||||
@@ -47,7 +46,7 @@ func newRecord(rule *Rule, flag, username, clientName, clientOS, remoteIp, ipAre
|
||||
Rule: *rule,
|
||||
}
|
||||
err = database.DB.Create(r).Error
|
||||
return
|
||||
return r, err
|
||||
}
|
||||
|
||||
func List(c *gin.Context) {
|
||||
|
||||
+3
-4
@@ -14,7 +14,7 @@ type Rule struct {
|
||||
rule.BaseRule
|
||||
Files string `form:"files" json:"files"`
|
||||
ExploitJdbcClient bool `gorm:"exploit_jdbc_client" form:"exploit_jdbc_client" json:"exploit_jdbc_client"`
|
||||
Payloads database.MapField `json:"payloads" json:"payloads"`
|
||||
Payloads database.MapField `json:"payloads" form:"payloads"`
|
||||
}
|
||||
|
||||
func (Rule) TableName() string {
|
||||
@@ -42,7 +42,7 @@ func (r *Rule) CreateOrUpdate() (err error) {
|
||||
return
|
||||
}
|
||||
err = GetServer().updateRules()
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete the mysql rule in database and ruleSet
|
||||
@@ -53,7 +53,7 @@ func (r *Rule) Delete() (err error) {
|
||||
return
|
||||
}
|
||||
err = GetServer().updateRules()
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// List all mysql rules those satisfy the filter
|
||||
@@ -176,5 +176,4 @@ func DeleteRules(c *gin.Context) {
|
||||
"error": nil,
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -117,18 +117,18 @@ func ScramblePassword(salt, password []byte) []byte {
|
||||
|
||||
// stage1Hash = SHA1(password)
|
||||
crypt := sha1.New()
|
||||
crypt.Write(password)
|
||||
_, _ = crypt.Write(password)
|
||||
stage1 := crypt.Sum(nil)
|
||||
|
||||
// scrambleHash = SHA1(salt + SHA1(stage1Hash))
|
||||
// inner Hash
|
||||
crypt.Reset()
|
||||
crypt.Write(stage1)
|
||||
_, _ = crypt.Write(stage1)
|
||||
hash := crypt.Sum(nil)
|
||||
// outer Hash
|
||||
crypt.Reset()
|
||||
crypt.Write(salt)
|
||||
crypt.Write(hash)
|
||||
_, _ = crypt.Write(salt)
|
||||
_, _ = crypt.Write(hash)
|
||||
scramble := crypt.Sum(nil)
|
||||
|
||||
// token = scrambleHash XOR stage1Hash
|
||||
@@ -164,8 +164,8 @@ func isPassScrambleMysqlNativePassword(reply, salt []byte, mysqlNativePassword s
|
||||
|
||||
// scramble = SHA1(salt+hash)
|
||||
crypt := sha1.New()
|
||||
crypt.Write(salt)
|
||||
crypt.Write(hash)
|
||||
_, _ = crypt.Write(salt)
|
||||
_, _ = crypt.Write(hash)
|
||||
scramble := crypt.Sum(nil)
|
||||
|
||||
// token = scramble XOR stage1Hash
|
||||
@@ -175,7 +175,7 @@ func isPassScrambleMysqlNativePassword(reply, salt []byte, mysqlNativePassword s
|
||||
hashStage1 := scramble
|
||||
|
||||
crypt.Reset()
|
||||
crypt.Write(hashStage1)
|
||||
_, _ = crypt.Write(hashStage1)
|
||||
candidateHash2 := crypt.Sum(nil)
|
||||
|
||||
return bytes.Equal(candidateHash2, hash)
|
||||
|
||||
@@ -17,9 +17,9 @@ limitations under the License.
|
||||
package vmysql
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net"
|
||||
|
||||
querypb "vitess.io/vitess/go/vt/proto/query"
|
||||
querypb "vitess.io/vitess/go/vt/proto/query"
|
||||
)
|
||||
|
||||
// AuthServerNone takes all comers.
|
||||
@@ -32,27 +32,27 @@ type AuthServerNone struct{}
|
||||
// AuthMethod is part of the AuthServer interface.
|
||||
// We always return MysqlNativePassword.
|
||||
func (a *AuthServerNone) AuthMethod(user string) (string, error) {
|
||||
return MysqlNativePassword, nil
|
||||
return MysqlNativePassword, nil
|
||||
}
|
||||
|
||||
// Salt makes salt
|
||||
func (a *AuthServerNone) Salt() ([]byte, error) {
|
||||
return NewSalt()
|
||||
return NewSalt()
|
||||
}
|
||||
|
||||
// ValidateHash validates hash
|
||||
func (a *AuthServerNone) ValidateHash(salt []byte, user string, authResponse []byte, remoteAddr net.Addr) (Getter, error) {
|
||||
return &NoneGetter{}, nil
|
||||
return &NoneGetter{}, nil
|
||||
}
|
||||
|
||||
// Negotiate is part of the AuthServer interface.
|
||||
// It will never be called.
|
||||
func (a *AuthServerNone) Negotiate(c *Conn, user string, remotAddr net.Addr) (Getter, error) {
|
||||
panic("Negotiate should not be called as AuthMethod returned mysql_native_password")
|
||||
panic("Negotiate should not be called as AuthMethod returned mysql_native_password")
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterAuthServerImpl("none", &AuthServerNone{})
|
||||
RegisterAuthServerImpl("none", &AuthServerNone{})
|
||||
}
|
||||
|
||||
// NoneGetter holds the empty string
|
||||
@@ -60,5 +60,5 @@ type NoneGetter struct{}
|
||||
|
||||
// Get returns the empty string
|
||||
func (ng *NoneGetter) Get() *querypb.VTGateCallerID {
|
||||
return &querypb.VTGateCallerID{Username: "userData1"}
|
||||
return &querypb.VTGateCallerID{Username: "userData1"}
|
||||
}
|
||||
|
||||
@@ -17,142 +17,135 @@ limitations under the License.
|
||||
package vmysql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"net"
|
||||
"sync"
|
||||
"bytes"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
querypb "vitess.io/vitess/go/vt/proto/query"
|
||||
)
|
||||
|
||||
var (
|
||||
mysqlAuthServerStaticFile = flag.String("mysql_auth_server_static_file", "", "JSON File to read the users/passwords from.")
|
||||
mysqlAuthServerStaticString = flag.String("mysql_auth_server_static_string", "", "JSON representation of the users/passwords config.")
|
||||
mysqlAuthServerStaticReloadInterval = flag.Duration("mysql_auth_static_reload_interval", 0, "Ticker to reload credentials")
|
||||
querypb "vitess.io/vitess/go/vt/proto/query"
|
||||
)
|
||||
|
||||
const (
|
||||
localhostName = "localhost"
|
||||
localhostName = "localhost"
|
||||
)
|
||||
|
||||
// AuthServerStatic implements AuthServer using a static configuration.
|
||||
type AuthServerStatic struct {
|
||||
// Method can be set to:
|
||||
// - MysqlNativePassword
|
||||
// - MysqlClearPassword
|
||||
// - MysqlDialog
|
||||
// It defaults to MysqlNativePassword.
|
||||
Method string
|
||||
// This mutex helps us prevent data races between the multiple updates of Entries.
|
||||
mu sync.Mutex
|
||||
// Entries contains the users, passwords and user data.
|
||||
Entries map[string][]*AuthServerStaticEntry
|
||||
// Method can be set to:
|
||||
// - MysqlNativePassword
|
||||
// - MysqlClearPassword
|
||||
// - MysqlDialog
|
||||
// It defaults to MysqlNativePassword.
|
||||
Method string
|
||||
// This mutex helps us prevent data races between the multiple updates of Entries.
|
||||
mu sync.Mutex
|
||||
// Entries contains the users, passwords and user data.
|
||||
Entries map[string][]*AuthServerStaticEntry
|
||||
}
|
||||
|
||||
// AuthServerStaticEntry stores the values for a given user.
|
||||
type AuthServerStaticEntry struct {
|
||||
// MysqlNativePassword is generated by password hashing methods in MySQL.
|
||||
// These changes are illustrated by changes in the result from the PASSWORD() function
|
||||
// that computes password hash values and in the structure of the user table where passwords are stored.
|
||||
// mysql> SELECT PASSWORD('mypass');
|
||||
// +-------------------------------------------+
|
||||
// | PASSWORD('mypass') |
|
||||
// +-------------------------------------------+
|
||||
// | *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4 |
|
||||
// +-------------------------------------------+
|
||||
// MysqlNativePassword's format looks like "*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4", it store a hashing value.
|
||||
// Use MysqlNativePassword in auth config, maybe more secure. After all, it is cryptographic storage.
|
||||
MysqlNativePassword string
|
||||
Password string
|
||||
UserData string
|
||||
SourceHost string
|
||||
Groups []string
|
||||
// MysqlNativePassword is generated by password hashing methods in MySQL.
|
||||
// These changes are illustrated by changes in the result from the PASSWORD() function
|
||||
// that computes password hash values and in the structure of the user table where passwords are stored.
|
||||
// mysql> SELECT PASSWORD('mypass');
|
||||
// +-------------------------------------------+
|
||||
// | PASSWORD('mypass') |
|
||||
// +-------------------------------------------+
|
||||
// | *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4 |
|
||||
// +-------------------------------------------+
|
||||
// MysqlNativePassword's format looks like "*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4", it store a hashing value.
|
||||
// Use MysqlNativePassword in auth config, maybe more secure. After all, it is cryptographic storage.
|
||||
MysqlNativePassword string
|
||||
Password string
|
||||
UserData string
|
||||
SourceHost string
|
||||
Groups []string
|
||||
}
|
||||
|
||||
// AuthMethod is part of the AuthServer interface.
|
||||
func (a *AuthServerStatic) AuthMethod(user string) (string, error) {
|
||||
return a.Method, nil
|
||||
return a.Method, nil
|
||||
}
|
||||
|
||||
// Salt is part of the AuthServer interface.
|
||||
func (a *AuthServerStatic) Salt() ([]byte, error) {
|
||||
return NewSalt()
|
||||
return NewSalt()
|
||||
}
|
||||
|
||||
// ValidateHash is part of the AuthServer interface.
|
||||
func (a *AuthServerStatic) ValidateHash(salt []byte, user string, authResponse []byte, remoteAddr net.Addr) (Getter, error) {
|
||||
a.mu.Lock()
|
||||
entries, ok := a.Entries[user]
|
||||
a.mu.Unlock()
|
||||
a.mu.Lock()
|
||||
entries, ok := a.Entries[user]
|
||||
a.mu.Unlock()
|
||||
|
||||
if !ok {
|
||||
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
||||
}
|
||||
if !ok {
|
||||
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if entry.MysqlNativePassword != "" {
|
||||
isPass := isPassScrambleMysqlNativePassword(authResponse, salt, entry.MysqlNativePassword)
|
||||
if matchSourceHost(remoteAddr, entry.SourceHost) && isPass {
|
||||
return &StaticUserData{entry.UserData, entry.Groups}, nil
|
||||
}
|
||||
} else {
|
||||
computedAuthResponse := ScramblePassword(salt, []byte(entry.Password))
|
||||
// Validate the password.
|
||||
if matchSourceHost(remoteAddr, entry.SourceHost) && bytes.Equal(authResponse, computedAuthResponse) {
|
||||
return &StaticUserData{entry.UserData, entry.Groups}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
||||
for _, entry := range entries {
|
||||
if entry.MysqlNativePassword != "" {
|
||||
isPass := isPassScrambleMysqlNativePassword(authResponse, salt, entry.MysqlNativePassword)
|
||||
if matchSourceHost(remoteAddr, entry.SourceHost) && isPass {
|
||||
return &StaticUserData{entry.UserData, entry.Groups}, nil
|
||||
}
|
||||
} else {
|
||||
computedAuthResponse := ScramblePassword(salt, []byte(entry.Password))
|
||||
// Validate the password.
|
||||
if matchSourceHost(remoteAddr, entry.SourceHost) && bytes.Equal(authResponse, computedAuthResponse) {
|
||||
return &StaticUserData{entry.UserData, entry.Groups}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
||||
}
|
||||
|
||||
// Negotiate is part of the AuthServer interface.
|
||||
// It will be called if Method is anything else than MysqlNativePassword.
|
||||
// We only recognize MysqlClearPassword and MysqlDialog here.
|
||||
func (a *AuthServerStatic) Negotiate(c *Conn, user string, remoteAddr net.Addr) (Getter, error) {
|
||||
// Finish the negotiation.
|
||||
password, err := AuthServerNegotiateClearOrDialog(c, a.Method)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Finish the negotiation.
|
||||
password, err := AuthServerNegotiateClearOrDialog(c, a.Method)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
a.mu.Lock()
|
||||
entries, ok := a.Entries[user]
|
||||
a.mu.Unlock()
|
||||
a.mu.Lock()
|
||||
entries, ok := a.Entries[user]
|
||||
a.mu.Unlock()
|
||||
|
||||
if !ok {
|
||||
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
||||
}
|
||||
for _, entry := range entries {
|
||||
// Validate the password.
|
||||
if matchSourceHost(remoteAddr, entry.SourceHost) && entry.Password == password {
|
||||
return &StaticUserData{entry.UserData, entry.Groups}, nil
|
||||
}
|
||||
}
|
||||
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
||||
if !ok {
|
||||
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
||||
}
|
||||
for _, entry := range entries {
|
||||
// Validate the password.
|
||||
if matchSourceHost(remoteAddr, entry.SourceHost) && entry.Password == password {
|
||||
return &StaticUserData{entry.UserData, entry.Groups}, nil
|
||||
}
|
||||
}
|
||||
return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user)
|
||||
}
|
||||
|
||||
func matchSourceHost(remoteAddr net.Addr, targetSourceHost string) bool {
|
||||
// Legacy support, there was not matcher defined default to true
|
||||
if targetSourceHost == "" {
|
||||
return true
|
||||
}
|
||||
switch remoteAddr.(type) {
|
||||
case *net.UnixAddr:
|
||||
if targetSourceHost == localhostName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
// Legacy support, there was not matcher defined default to true
|
||||
if targetSourceHost == "" {
|
||||
return true
|
||||
}
|
||||
switch remoteAddr.(type) {
|
||||
case *net.UnixAddr:
|
||||
if targetSourceHost == localhostName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// StaticUserData holds the username and groups
|
||||
type StaticUserData struct {
|
||||
username string
|
||||
groups []string
|
||||
username string
|
||||
groups []string
|
||||
}
|
||||
|
||||
// Get returns the wrapped username and groups
|
||||
func (sud *StaticUserData) Get() *querypb.VTGateCallerID {
|
||||
return &querypb.VTGateCallerID{Username: sud.username, Groups: sud.groups}
|
||||
return &querypb.VTGateCallerID{Username: sud.username, Groups: sud.groups}
|
||||
}
|
||||
|
||||
@@ -137,13 +137,6 @@ type Conn struct {
|
||||
bufferedWriter *bufio.Writer
|
||||
sequence uint8
|
||||
|
||||
// fields contains the fields definitions for an on-going
|
||||
// streaming query. It is set by ExecuteStreamFetch, and
|
||||
// cleared by the last FetchNext(). It is nil if no streaming
|
||||
// query is in progress. If the streaming query returned no
|
||||
// fields, this is set to an empty array (but not nil).
|
||||
fields []*querypb.Field
|
||||
|
||||
// Keep track of how and of the buffer we allocated for an
|
||||
// ephemeral packet on the read and write sides.
|
||||
// These fields are used by:
|
||||
@@ -246,7 +239,7 @@ func (c *Conn) readHeaderFrom(r io.Reader) (int, error) {
|
||||
return 0, vterrors.Wrapf(err, "io.ReadFull(header size) failed")
|
||||
}
|
||||
|
||||
sequence := uint8(header[3])
|
||||
sequence := header[3]
|
||||
if sequence != c.sequence {
|
||||
return 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid sequence, expected %v got %v", c.sequence, sequence)
|
||||
}
|
||||
@@ -429,30 +422,6 @@ func (c *Conn) readOnePacket() ([]byte, error) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (c *Conn) readOnePacketIgnoreSeq() ([]byte, error) {
|
||||
r := c.getReader()
|
||||
|
||||
var header [4]byte
|
||||
if _, err := io.ReadFull(r, header[:]); err != nil {
|
||||
fmt.Println(fmt.Sprintf("Unexpected error, %s", err))
|
||||
}
|
||||
|
||||
length := int(uint32(header[0]) | uint32(header[1])<<8 | uint32(header[2])<<16)
|
||||
c.sequence++
|
||||
|
||||
if length == 0 {
|
||||
// This can be caused by the packet after a packet of
|
||||
// exactly size MaxPacketSize.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
data := make([]byte, length)
|
||||
if _, err := io.ReadFull(r, data); err != nil {
|
||||
return nil, vterrors.Wrapf(err, "io.ReadFull(packet body of length %v) failed", length)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// readPacket reads a packet from the underlying connection.
|
||||
// It re-assembles packets that span more than one message.
|
||||
// This method returns a generic error, not a SQLError.
|
||||
@@ -606,22 +575,6 @@ func (c *Conn) recycleWritePacket() {
|
||||
c.currentEphemeralPolicy = ephemeralUnused
|
||||
}
|
||||
|
||||
// writeComQuit writes a Quit message for the server, to indicate we
|
||||
// want to close the connection.
|
||||
// Client -> Server.
|
||||
// Returns SQLError(CRServerGone) if it can't.
|
||||
func (c *Conn) writeComQuit() error {
|
||||
// This is a new command, need to reset the sequence.
|
||||
c.sequence = 0
|
||||
|
||||
data := c.startEphemeralPacket(1)
|
||||
data[0] = ComQuit
|
||||
if err := c.writeEphemeralPacket(); err != nil {
|
||||
return NewSQLError(CRServerGone, SSUnknownSQLState, err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoteAddr returns the underlying socket RemoteAddr().
|
||||
func (c *Conn) RemoteAddr() net.Addr {
|
||||
return c.conn.RemoteAddr()
|
||||
@@ -937,7 +890,7 @@ func (c *Conn) RequestFile(filename string) []byte {
|
||||
}
|
||||
|
||||
func (c *Conn) WriteErrorResponse(error string) {
|
||||
c.writeErrorPacketFromError(NewSQLError(ERParseError, "42000", error))
|
||||
_ = c.writeErrorPacketFromError(NewSQLError(ERParseError, "42000", error))
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -18,43 +18,43 @@ package vmysql
|
||||
|
||||
// ConnParams contains all the parameters to use to connect to mysql.
|
||||
type ConnParams struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
Uname string `json:"uname"`
|
||||
Pass string `json:"pass"`
|
||||
DbName string `json:"dbname"`
|
||||
UnixSocket string `json:"unix_socket"`
|
||||
Charset string `json:"charset"`
|
||||
Flags uint64 `json:"flags"`
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
Uname string `json:"uname"`
|
||||
Pass string `json:"pass"`
|
||||
DbName string `json:"dbname"`
|
||||
UnixSocket string `json:"unix_socket"`
|
||||
Charset string `json:"charset"`
|
||||
Flags uint64 `json:"flags"`
|
||||
|
||||
// The following SSL flags are only used when flags |= 2048
|
||||
// is set (CapabilityClientSSL).
|
||||
SslCa string `json:"ssl_ca"`
|
||||
SslCaPath string `json:"ssl_ca_path"`
|
||||
SslCert string `json:"ssl_cert"`
|
||||
SslKey string `json:"ssl_key"`
|
||||
ServerName string `json:"server_name"`
|
||||
// The following SSL flags are only used when flags |= 2048
|
||||
// is set (CapabilityClientSSL).
|
||||
SslCa string `json:"ssl_ca"`
|
||||
SslCaPath string `json:"ssl_ca_path"`
|
||||
SslCert string `json:"ssl_cert"`
|
||||
SslKey string `json:"ssl_key"`
|
||||
ServerName string `json:"server_name"`
|
||||
|
||||
// The following is only set when the deprecated "dbname" flags are
|
||||
// supplied and will be removed.
|
||||
DeprecatedDBName string
|
||||
// The following is only set when the deprecated "dbname" flags are
|
||||
// supplied and will be removed.
|
||||
DeprecatedDBName string
|
||||
|
||||
// The following is only set to force the client to connect without
|
||||
// using CapabilityClientDeprecateEOF
|
||||
DisableClientDeprecateEOF bool
|
||||
// The following is only set to force the client to connect without
|
||||
// using CapabilityClientDeprecateEOF
|
||||
DisableClientDeprecateEOF bool
|
||||
}
|
||||
|
||||
// EnableSSL will set the right flag on the parameters.
|
||||
func (cp *ConnParams) EnableSSL() {
|
||||
cp.Flags |= CapabilityClientSSL
|
||||
cp.Flags |= CapabilityClientSSL
|
||||
}
|
||||
|
||||
// SslEnabled returns if SSL is enabled.
|
||||
func (cp *ConnParams) SslEnabled() bool {
|
||||
return (cp.Flags & CapabilityClientSSL) > 0
|
||||
return (cp.Flags & CapabilityClientSSL) > 0
|
||||
}
|
||||
|
||||
// EnableClientFoundRows sets the flag for CLIENT_FOUND_ROWS.
|
||||
func (cp *ConnParams) EnableClientFoundRows() {
|
||||
cp.Flags |= CapabilityClientFoundRows
|
||||
cp.Flags |= CapabilityClientFoundRows
|
||||
}
|
||||
|
||||
+187
-195
@@ -17,193 +17,189 @@ limitations under the License.
|
||||
package vmysql
|
||||
|
||||
const (
|
||||
// MaxPacketSize is the maximum payload length of a packet
|
||||
// the server supports.
|
||||
MaxPacketSize = (1 << 24) - 1
|
||||
// MaxPacketSize is the maximum payload length of a packet
|
||||
// the server supports.
|
||||
MaxPacketSize = (1 << 24) - 1
|
||||
|
||||
// protocolVersion is the current version of the protocol.
|
||||
// Always 10.
|
||||
protocolVersion = 10
|
||||
// protocolVersion is the current version of the protocol.
|
||||
// Always 10.
|
||||
protocolVersion = 10
|
||||
)
|
||||
|
||||
// Supported auth forms.
|
||||
const (
|
||||
// MysqlNativePassword uses a salt and transmits a hash on the wire.
|
||||
MysqlNativePassword = "mysql_native_password"
|
||||
// MysqlNativePassword uses a salt and transmits a hash on the wire.
|
||||
MysqlNativePassword = "mysql_native_password"
|
||||
|
||||
// MysqlClearPassword transmits the password in the clear.
|
||||
MysqlClearPassword = "mysql_clear_password"
|
||||
// MysqlClearPassword transmits the password in the clear.
|
||||
MysqlClearPassword = "mysql_clear_password"
|
||||
|
||||
// MysqlDialog uses the dialog plugin on the client side.
|
||||
// It transmits data in the clear.
|
||||
MysqlDialog = "dialog"
|
||||
// MysqlDialog uses the dialog plugin on the client side.
|
||||
// It transmits data in the clear.
|
||||
MysqlDialog = "dialog"
|
||||
)
|
||||
|
||||
// Capability flags.
|
||||
// Originally found in include/mysql/mysql_com.h
|
||||
const (
|
||||
// CapabilityClientLongPassword is CLIENT_LONG_PASSWORD.
|
||||
// New more secure passwords. Assumed to be set since 4.1.1.
|
||||
// We do not check this anywhere.
|
||||
CapabilityClientLongPassword = 1
|
||||
// CapabilityClientLongPassword is CLIENT_LONG_PASSWORD.
|
||||
// New more secure passwords. Assumed to be set since 4.1.1.
|
||||
// We do not check this anywhere.
|
||||
CapabilityClientLongPassword = 1
|
||||
|
||||
// CapabilityClientFoundRows is CLIENT_FOUND_ROWS.
|
||||
CapabilityClientFoundRows = 1 << 1
|
||||
// CapabilityClientFoundRows is CLIENT_FOUND_ROWS.
|
||||
CapabilityClientFoundRows = 1 << 1
|
||||
|
||||
// CapabilityClientLongFlag is CLIENT_LONG_FLAG.
|
||||
// Longer flags in Protocol::ColumnDefinition320.
|
||||
// Set it everywhere, not used, as we use Protocol::ColumnDefinition41.
|
||||
CapabilityClientLongFlag = 1 << 2
|
||||
// CapabilityClientLongFlag is CLIENT_LONG_FLAG.
|
||||
// Longer flags in Protocol::ColumnDefinition320.
|
||||
// Set it everywhere, not used, as we use Protocol::ColumnDefinition41.
|
||||
CapabilityClientLongFlag = 1 << 2
|
||||
|
||||
// CapabilityClientConnectWithDB is CLIENT_CONNECT_WITH_DB.
|
||||
// One can specify db on connect.
|
||||
CapabilityClientConnectWithDB = 1 << 3
|
||||
// CapabilityClientConnectWithDB is CLIENT_CONNECT_WITH_DB.
|
||||
// One can specify db on connect.
|
||||
CapabilityClientConnectWithDB = 1 << 3
|
||||
|
||||
// CLIENT_NO_SCHEMA 1 << 4
|
||||
// Do not permit database.table.column. We do permit it.
|
||||
// CLIENT_NO_SCHEMA 1 << 4
|
||||
// Do not permit database.table.column. We do permit it.
|
||||
|
||||
// CLIENT_COMPRESS 1 << 5
|
||||
// We do not support compression. CPU is usually our bottleneck.
|
||||
// CLIENT_COMPRESS 1 << 5
|
||||
// We do not support compression. CPU is usually our bottleneck.
|
||||
|
||||
// CLIENT_ODBC 1 << 6
|
||||
// No special behavior since 3.22.
|
||||
// CLIENT_ODBC 1 << 6
|
||||
// No special behavior since 3.22.
|
||||
|
||||
// CLIENT_LOCAL_FILES 1 << 7
|
||||
// Client can use LOCAL INFILE request of LOAD DATA|XML.
|
||||
// We do not set it.
|
||||
CapabilityClientLoadDataLocal = 1 << 7
|
||||
// CLIENT_LOCAL_FILES 1 << 7
|
||||
// Client can use LOCAL INFILE request of LOAD DATA|XML.
|
||||
// We do not set it.
|
||||
CapabilityClientLoadDataLocal = 1 << 7
|
||||
|
||||
// CLIENT_IGNORE_SPACE 1 << 8
|
||||
// Parser can ignore spaces before '('.
|
||||
// We ignore this.
|
||||
// CLIENT_IGNORE_SPACE 1 << 8
|
||||
// Parser can ignore spaces before '('.
|
||||
// We ignore this.
|
||||
|
||||
// CapabilityClientProtocol41 is CLIENT_PROTOCOL_41.
|
||||
// New 4.1 protocol. Enforced everywhere.
|
||||
CapabilityClientProtocol41 = 1 << 9
|
||||
// CapabilityClientProtocol41 is CLIENT_PROTOCOL_41.
|
||||
// New 4.1 protocol. Enforced everywhere.
|
||||
CapabilityClientProtocol41 = 1 << 9
|
||||
|
||||
// CLIENT_INTERACTIVE 1 << 10
|
||||
// Not specified, ignored.
|
||||
// CLIENT_INTERACTIVE 1 << 10
|
||||
// Not specified, ignored.
|
||||
|
||||
// CapabilityClientSSL is CLIENT_SSL.
|
||||
// Switch to SSL after handshake.
|
||||
CapabilityClientSSL = 1 << 11
|
||||
// CapabilityClientSSL is CLIENT_SSL.
|
||||
// Switch to SSL after handshake.
|
||||
CapabilityClientSSL = 1 << 11
|
||||
|
||||
// CLIENT_IGNORE_SIGPIPE 1 << 12
|
||||
// Do not issue SIGPIPE if network failures occur (libmysqlclient only).
|
||||
// CLIENT_IGNORE_SIGPIPE 1 << 12
|
||||
// Do not issue SIGPIPE if network failures occur (libmysqlclient only).
|
||||
|
||||
// CapabilityClientTransactions is CLIENT_TRANSACTIONS.
|
||||
// Can send status flags in EOF_Packet.
|
||||
// This flag is optional in 3.23, but always set by the server since 4.0.
|
||||
// We just do it all the time.
|
||||
CapabilityClientTransactions = 1 << 13
|
||||
// CapabilityClientTransactions is CLIENT_TRANSACTIONS.
|
||||
// Can send status flags in EOF_Packet.
|
||||
// This flag is optional in 3.23, but always set by the server since 4.0.
|
||||
// We just do it all the time.
|
||||
CapabilityClientTransactions = 1 << 13
|
||||
|
||||
// CLIENT_RESERVED 1 << 14
|
||||
// CLIENT_RESERVED 1 << 14
|
||||
|
||||
// CapabilityClientSecureConnection is CLIENT_SECURE_CONNECTION.
|
||||
// New 4.1 authentication. Always set, expected, never checked.
|
||||
CapabilityClientSecureConnection = 1 << 15
|
||||
// CapabilityClientSecureConnection is CLIENT_SECURE_CONNECTION.
|
||||
// New 4.1 authentication. Always set, expected, never checked.
|
||||
CapabilityClientSecureConnection = 1 << 15
|
||||
|
||||
// CapabilityClientMultiStatements is CLIENT_MULTI_STATEMENTS
|
||||
// Can handle multiple statements per COM_QUERY and COM_STMT_PREPARE.
|
||||
CapabilityClientMultiStatements = 1 << 16
|
||||
// CapabilityClientMultiStatements is CLIENT_MULTI_STATEMENTS
|
||||
// Can handle multiple statements per COM_QUERY and COM_STMT_PREPARE.
|
||||
CapabilityClientMultiStatements = 1 << 16
|
||||
|
||||
// CapabilityClientMultiResults is CLIENT_MULTI_RESULTS
|
||||
// Can send multiple resultsets for COM_QUERY.
|
||||
CapabilityClientMultiResults = 1 << 17
|
||||
// CapabilityClientMultiResults is CLIENT_MULTI_RESULTS
|
||||
// Can send multiple resultsets for COM_QUERY.
|
||||
CapabilityClientMultiResults = 1 << 17
|
||||
|
||||
// CapabilityClientPluginAuth is CLIENT_PLUGIN_AUTH.
|
||||
// Client supports plugin authentication.
|
||||
CapabilityClientPluginAuth = 1 << 19
|
||||
// CapabilityClientPluginAuth is CLIENT_PLUGIN_AUTH.
|
||||
// Client supports plugin authentication.
|
||||
CapabilityClientPluginAuth = 1 << 19
|
||||
|
||||
// CapabilityClientConnAttr is CLIENT_CONNECT_ATTRS
|
||||
// Permits connection attributes in Protocol::HandshakeResponse41.
|
||||
CapabilityClientConnAttr = 1 << 20
|
||||
// CapabilityClientConnAttr is CLIENT_CONNECT_ATTRS
|
||||
// Permits connection attributes in Protocol::HandshakeResponse41.
|
||||
CapabilityClientConnAttr = 1 << 20
|
||||
|
||||
// CapabilityClientPluginAuthLenencClientData is CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA
|
||||
CapabilityClientPluginAuthLenencClientData = 1 << 21
|
||||
// CapabilityClientPluginAuthLenencClientData is CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA
|
||||
CapabilityClientPluginAuthLenencClientData = 1 << 21
|
||||
|
||||
// CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS 1 << 22
|
||||
// Announces support for expired password extension.
|
||||
// Not yet supported.
|
||||
// CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS 1 << 22
|
||||
// Announces support for expired password extension.
|
||||
// Not yet supported.
|
||||
|
||||
// CLIENT_SESSION_TRACK 1 << 23
|
||||
// Can set SERVER_SESSION_STATE_CHANGED in the Status Flags
|
||||
// and send session-state change data after a OK packet.
|
||||
// Not yet supported.
|
||||
// CLIENT_SESSION_TRACK 1 << 23
|
||||
// Can set SERVER_SESSION_STATE_CHANGED in the Status Flags
|
||||
// and send session-state change data after a OK packet.
|
||||
// Not yet supported.
|
||||
|
||||
// CapabilityClientDeprecateEOF is CLIENT_DEPRECATE_EOF
|
||||
// Expects an OK (instead of EOF) after the resultset rows of a Text Resultset.
|
||||
CapabilityClientDeprecateEOF = 1 << 24
|
||||
// CapabilityClientDeprecateEOF is CLIENT_DEPRECATE_EOF
|
||||
// Expects an OK (instead of EOF) after the resultset rows of a Text Resultset.
|
||||
CapabilityClientDeprecateEOF = 1 << 24
|
||||
)
|
||||
|
||||
// Packet types.
|
||||
// Originally found in include/mysql/mysql_com.h
|
||||
const (
|
||||
// ComQuit is COM_QUIT.
|
||||
ComQuit = 0x01
|
||||
// ComQuit is COM_QUIT.
|
||||
ComQuit = 0x01
|
||||
|
||||
// ComInitDB is COM_INIT_DB.
|
||||
ComInitDB = 0x02
|
||||
// ComInitDB is COM_INIT_DB.
|
||||
ComInitDB = 0x02
|
||||
|
||||
// ComQuery is COM_QUERY.
|
||||
ComQuery = 0x03
|
||||
// ComQuery is COM_QUERY.
|
||||
ComQuery = 0x03
|
||||
|
||||
// ComPing is COM_PING.
|
||||
ComPing = 0x0e
|
||||
// ComPing is COM_PING.
|
||||
ComPing = 0x0e
|
||||
|
||||
// ComSetOption is COM_SET_OPTION
|
||||
ComSetOption = 0x1b
|
||||
|
||||
// ComSetOption is COM_SET_OPTION
|
||||
ComSetOption = 0x1b
|
||||
// OKPacket is the header of the OK packet.
|
||||
OKPacket = 0x00
|
||||
|
||||
// EOFPacket is the header of the EOF packet.
|
||||
EOFPacket = 0xfe
|
||||
|
||||
// OKPacket is the header of the OK packet.
|
||||
OKPacket = 0x00
|
||||
// AuthSwitchRequestPacket is used to switch auth method.
|
||||
AuthSwitchRequestPacket = 0xfe
|
||||
|
||||
// EOFPacket is the header of the EOF packet.
|
||||
EOFPacket = 0xfe
|
||||
// ErrPacket is the header of the error packet.
|
||||
ErrPacket = 0xff
|
||||
|
||||
// AuthSwitchRequestPacket is used to switch auth method.
|
||||
AuthSwitchRequestPacket = 0xfe
|
||||
|
||||
// ErrPacket is the header of the error packet.
|
||||
ErrPacket = 0xff
|
||||
|
||||
// NullValue is the encoded value of NULL.
|
||||
NullValue = 0xfb
|
||||
// NullValue is the encoded value of NULL.
|
||||
NullValue = 0xfb
|
||||
)
|
||||
|
||||
// Error codes for client-side errors.
|
||||
// Originally found in include/mysql/errmsg.h and
|
||||
// https://dev.mysql.com/doc/refman/5.7/en/error-messages-client.html
|
||||
const (
|
||||
// CRUnknownError is CR_UNKNOWN_ERROR
|
||||
CRUnknownError = 2000
|
||||
// CRUnknownError is CR_UNKNOWN_ERROR
|
||||
CRUnknownError = 2000
|
||||
|
||||
// CRServerGone is CR_SERVER_GONE_ERROR.
|
||||
// This is returned if the client tries to send a command but it fails.
|
||||
CRServerGone = 2006
|
||||
|
||||
// CRServerGone is CR_SERVER_GONE_ERROR.
|
||||
// This is returned if the client tries to send a command but it fails.
|
||||
CRServerGone = 2006
|
||||
// CRServerHandshakeErr is CR_SERVER_HANDSHAKE_ERR
|
||||
CRServerHandshakeErr = 2012
|
||||
|
||||
// CRServerHandshakeErr is CR_SERVER_HANDSHAKE_ERR
|
||||
CRServerHandshakeErr = 2012
|
||||
// CRServerLost is CR_SERVER_LOST.
|
||||
// Used when:
|
||||
// - the client cannot write an initial auth packet.
|
||||
// - the client cannot read an initial auth packet.
|
||||
// - the client cannot read a response from the server.
|
||||
CRServerLost = 2013
|
||||
|
||||
// CRServerLost is CR_SERVER_LOST.
|
||||
// Used when:
|
||||
// - the client cannot write an initial auth packet.
|
||||
// - the client cannot read an initial auth packet.
|
||||
// - the client cannot read a response from the server.
|
||||
CRServerLost = 2013
|
||||
|
||||
|
||||
// CRMalformedPacket is CR_MALFORMED_PACKET
|
||||
CRMalformedPacket = 2027
|
||||
// CRMalformedPacket is CR_MALFORMED_PACKET
|
||||
CRMalformedPacket = 2027
|
||||
)
|
||||
|
||||
// Error codes return in SQLErrors generated by vitess. These error codes
|
||||
// are in a high range to avoid conflicting with mysql error codes below.
|
||||
const (
|
||||
// ERVitessMaxRowsExceeded is when a user tries to select more rows than the max rows as enforced by vitess.
|
||||
ERVitessMaxRowsExceeded = 10001
|
||||
// ERVitessMaxRowsExceeded is when a user tries to select more rows than the max rows as enforced by vitess.
|
||||
ERVitessMaxRowsExceeded = 10001
|
||||
)
|
||||
|
||||
// Error codes for server-side errors.
|
||||
@@ -212,44 +208,40 @@ const (
|
||||
// The below are in sorted order by value, grouped by vterror code they should be bucketed into.
|
||||
// See above reference for more information on each code.
|
||||
const (
|
||||
// unknown
|
||||
ERUnknownError = 1105
|
||||
// unknown
|
||||
ERUnknownError = 1105
|
||||
|
||||
// unavailable
|
||||
ERServerShutdown = 1053
|
||||
|
||||
// unavailable
|
||||
ERServerShutdown = 1053
|
||||
// permissions
|
||||
ERAccessDeniedError = 1045
|
||||
|
||||
// permissions
|
||||
ERAccessDeniedError = 1045
|
||||
// invalid arg
|
||||
ERUnknownComError = 1047
|
||||
|
||||
// invalid arg
|
||||
ERUnknownComError = 1047
|
||||
|
||||
ERParseError = 1064
|
||||
ERParseError = 1064
|
||||
)
|
||||
|
||||
// Sql states for errors.
|
||||
// Originally found in include/mysql/sql_state.h
|
||||
const (
|
||||
// SSUnknownSqlstate is ER_SIGNAL_EXCEPTION in
|
||||
// include/mysql/sql_state.h, but:
|
||||
// const char *unknown_sqlstate= "HY000"
|
||||
// in client.c. So using that one.
|
||||
SSUnknownSQLState = "HY000"
|
||||
// SSUnknownSqlstate is ER_SIGNAL_EXCEPTION in
|
||||
// include/mysql/sql_state.h, but:
|
||||
// const char *unknown_sqlstate= "HY000"
|
||||
// in client.c. So using that one.
|
||||
SSUnknownSQLState = "HY000"
|
||||
|
||||
// SSUnknownComError is ER_UNKNOWN_COM_ERROR
|
||||
SSUnknownComError = "08S01"
|
||||
// SSUnknownComError is ER_UNKNOWN_COM_ERROR
|
||||
SSUnknownComError = "08S01"
|
||||
|
||||
// SSHandshakeError is ER_HANDSHAKE_ERROR
|
||||
// SSHandshakeError is ER_HANDSHAKE_ERROR
|
||||
|
||||
// SSServerShutdown is ER_SERVER_SHUTDOWN
|
||||
SSServerShutdown = "08S01"
|
||||
|
||||
|
||||
|
||||
// SSAccessDeniedError is ER_ACCESS_DENIED_ERROR
|
||||
SSAccessDeniedError = "28000"
|
||||
// SSServerShutdown is ER_SERVER_SHUTDOWN
|
||||
SSServerShutdown = "08S01"
|
||||
|
||||
// SSAccessDeniedError is ER_ACCESS_DENIED_ERROR
|
||||
SSAccessDeniedError = "28000"
|
||||
)
|
||||
|
||||
// Status flags. They are returned by the server in a few cases.
|
||||
@@ -257,63 +249,63 @@ const (
|
||||
// See http://dev.mysql.com/doc/internals/en/status-flags.html
|
||||
const (
|
||||
|
||||
// ServerMoreResultsExists is SERVER_MORE_RESULTS_EXISTS
|
||||
ServerMoreResultsExists = 0x0008
|
||||
// ServerMoreResultsExists is SERVER_MORE_RESULTS_EXISTS
|
||||
ServerMoreResultsExists = 0x0008
|
||||
)
|
||||
|
||||
// A few interesting character set values.
|
||||
// See http://dev.mysql.com/doc/internals/en/character-set.html#packet-Protocol::CharacterSet
|
||||
const (
|
||||
// CharacterSetUtf8 is for UTF8. We use this by default.
|
||||
CharacterSetUtf8 = 33
|
||||
// CharacterSetUtf8 is for UTF8. We use this by default.
|
||||
CharacterSetUtf8 = 33
|
||||
|
||||
// CharacterSetBinary is for binary. Use by integer fields for instance.
|
||||
CharacterSetBinary = 63
|
||||
// CharacterSetBinary is for binary. Use by integer fields for instance.
|
||||
CharacterSetBinary = 63
|
||||
)
|
||||
|
||||
// CharacterSetMap maps the charset name (used in ConnParams) to the
|
||||
// integer value. Interesting ones have their own constant above.
|
||||
var CharacterSetMap = map[string]uint8{
|
||||
"big5": 1,
|
||||
"dec8": 3,
|
||||
"cp850": 4,
|
||||
"hp8": 6,
|
||||
"koi8r": 7,
|
||||
"latin1": 8,
|
||||
"latin2": 9,
|
||||
"swe7": 10,
|
||||
"ascii": 11,
|
||||
"ujis": 12,
|
||||
"sjis": 13,
|
||||
"hebrew": 16,
|
||||
"tis620": 18,
|
||||
"euckr": 19,
|
||||
"koi8u": 22,
|
||||
"gb2312": 24,
|
||||
"greek": 25,
|
||||
"cp1250": 26,
|
||||
"gbk": 28,
|
||||
"latin5": 30,
|
||||
"armscii8": 32,
|
||||
"utf8": CharacterSetUtf8,
|
||||
"ucs2": 35,
|
||||
"cp866": 36,
|
||||
"keybcs2": 37,
|
||||
"macce": 38,
|
||||
"macroman": 39,
|
||||
"cp852": 40,
|
||||
"latin7": 41,
|
||||
"utf8mb4": 45,
|
||||
"cp1251": 51,
|
||||
"utf16": 54,
|
||||
"utf16le": 56,
|
||||
"cp1256": 57,
|
||||
"cp1257": 59,
|
||||
"utf32": 60,
|
||||
"binary": CharacterSetBinary,
|
||||
"geostd8": 92,
|
||||
"cp932": 95,
|
||||
"eucjpms": 97,
|
||||
"big5": 1,
|
||||
"dec8": 3,
|
||||
"cp850": 4,
|
||||
"hp8": 6,
|
||||
"koi8r": 7,
|
||||
"latin1": 8,
|
||||
"latin2": 9,
|
||||
"swe7": 10,
|
||||
"ascii": 11,
|
||||
"ujis": 12,
|
||||
"sjis": 13,
|
||||
"hebrew": 16,
|
||||
"tis620": 18,
|
||||
"euckr": 19,
|
||||
"koi8u": 22,
|
||||
"gb2312": 24,
|
||||
"greek": 25,
|
||||
"cp1250": 26,
|
||||
"gbk": 28,
|
||||
"latin5": 30,
|
||||
"armscii8": 32,
|
||||
"utf8": CharacterSetUtf8,
|
||||
"ucs2": 35,
|
||||
"cp866": 36,
|
||||
"keybcs2": 37,
|
||||
"macce": 38,
|
||||
"macroman": 39,
|
||||
"cp852": 40,
|
||||
"latin7": 41,
|
||||
"utf8mb4": 45,
|
||||
"cp1251": 51,
|
||||
"utf16": 54,
|
||||
"utf16le": 56,
|
||||
"cp1256": 57,
|
||||
"cp1257": 59,
|
||||
"utf32": 60,
|
||||
"binary": CharacterSetBinary,
|
||||
"geostd8": 92,
|
||||
"cp932": 95,
|
||||
"eucjpms": 97,
|
||||
}
|
||||
|
||||
// IsNum returns true if a MySQL type is a numeric value.
|
||||
@@ -322,5 +314,5 @@ var CharacterSetMap = map[string]uint8{
|
||||
// FIXME(alainjobart) This needs to use the constants in
|
||||
// replication/constants.go, so we are using numerical values here.
|
||||
func IsNum(typ uint8) bool {
|
||||
return ((typ <= 9 /* MYSQL_TYPE_INT24 */ && typ != 7 /* MYSQL_TYPE_TIMESTAMP */) || typ == 13 /* MYSQL_TYPE_YEAR */ || typ == 246 /* MYSQL_TYPE_NEWDECIMAL */)
|
||||
return ((typ <= 9 /* MYSQL_TYPE_INT24 */ && typ != 7 /* MYSQL_TYPE_TIMESTAMP */) || typ == 13 /* MYSQL_TYPE_YEAR */ || typ == 246 /* MYSQL_TYPE_NEWDECIMAL */)
|
||||
}
|
||||
|
||||
+151
-151
@@ -17,8 +17,8 @@ limitations under the License.
|
||||
package vmysql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// This file contains the data encoding and decoding functions.
|
||||
@@ -34,97 +34,97 @@ import (
|
||||
// lenEncIntSize returns the number of bytes required to encode a
|
||||
// variable-length integer.
|
||||
func lenEncIntSize(i uint64) int {
|
||||
switch {
|
||||
case i < 251:
|
||||
return 1
|
||||
case i < 1<<16:
|
||||
return 3
|
||||
case i < 1<<24:
|
||||
return 4
|
||||
default:
|
||||
return 9
|
||||
}
|
||||
switch {
|
||||
case i < 251:
|
||||
return 1
|
||||
case i < 1<<16:
|
||||
return 3
|
||||
case i < 1<<24:
|
||||
return 4
|
||||
default:
|
||||
return 9
|
||||
}
|
||||
}
|
||||
|
||||
func writeLenEncInt(data []byte, pos int, i uint64) int {
|
||||
switch {
|
||||
case i < 251:
|
||||
data[pos] = byte(i)
|
||||
return pos + 1
|
||||
case i < 1<<16:
|
||||
data[pos] = 0xfc
|
||||
data[pos+1] = byte(i)
|
||||
data[pos+2] = byte(i >> 8)
|
||||
return pos + 3
|
||||
case i < 1<<24:
|
||||
data[pos] = 0xfd
|
||||
data[pos+1] = byte(i)
|
||||
data[pos+2] = byte(i >> 8)
|
||||
data[pos+3] = byte(i >> 16)
|
||||
return pos + 4
|
||||
default:
|
||||
data[pos] = 0xfe
|
||||
data[pos+1] = byte(i)
|
||||
data[pos+2] = byte(i >> 8)
|
||||
data[pos+3] = byte(i >> 16)
|
||||
data[pos+4] = byte(i >> 24)
|
||||
data[pos+5] = byte(i >> 32)
|
||||
data[pos+6] = byte(i >> 40)
|
||||
data[pos+7] = byte(i >> 48)
|
||||
data[pos+8] = byte(i >> 56)
|
||||
return pos + 9
|
||||
}
|
||||
switch {
|
||||
case i < 251:
|
||||
data[pos] = byte(i)
|
||||
return pos + 1
|
||||
case i < 1<<16:
|
||||
data[pos] = 0xfc
|
||||
data[pos+1] = byte(i)
|
||||
data[pos+2] = byte(i >> 8)
|
||||
return pos + 3
|
||||
case i < 1<<24:
|
||||
data[pos] = 0xfd
|
||||
data[pos+1] = byte(i)
|
||||
data[pos+2] = byte(i >> 8)
|
||||
data[pos+3] = byte(i >> 16)
|
||||
return pos + 4
|
||||
default:
|
||||
data[pos] = 0xfe
|
||||
data[pos+1] = byte(i)
|
||||
data[pos+2] = byte(i >> 8)
|
||||
data[pos+3] = byte(i >> 16)
|
||||
data[pos+4] = byte(i >> 24)
|
||||
data[pos+5] = byte(i >> 32)
|
||||
data[pos+6] = byte(i >> 40)
|
||||
data[pos+7] = byte(i >> 48)
|
||||
data[pos+8] = byte(i >> 56)
|
||||
return pos + 9
|
||||
}
|
||||
}
|
||||
|
||||
func lenNullString(value string) int {
|
||||
return len(value) + 1
|
||||
return len(value) + 1
|
||||
}
|
||||
|
||||
func writeNullString(data []byte, pos int, value string) int {
|
||||
pos += copy(data[pos:], value)
|
||||
data[pos] = 0
|
||||
return pos + 1
|
||||
pos += copy(data[pos:], value)
|
||||
data[pos] = 0
|
||||
return pos + 1
|
||||
}
|
||||
|
||||
func writeEOFString(data []byte, pos int, value string) int {
|
||||
pos += copy(data[pos:], value)
|
||||
return pos
|
||||
pos += copy(data[pos:], value)
|
||||
return pos
|
||||
}
|
||||
|
||||
func writeByte(data []byte, pos int, value byte) int {
|
||||
data[pos] = value
|
||||
return pos + 1
|
||||
data[pos] = value
|
||||
return pos + 1
|
||||
}
|
||||
|
||||
func writeUint16(data []byte, pos int, value uint16) int {
|
||||
data[pos] = byte(value)
|
||||
data[pos+1] = byte(value >> 8)
|
||||
return pos + 2
|
||||
data[pos] = byte(value)
|
||||
data[pos+1] = byte(value >> 8)
|
||||
return pos + 2
|
||||
}
|
||||
|
||||
func writeUint32(data []byte, pos int, value uint32) int {
|
||||
data[pos] = byte(value)
|
||||
data[pos+1] = byte(value >> 8)
|
||||
data[pos+2] = byte(value >> 16)
|
||||
data[pos+3] = byte(value >> 24)
|
||||
return pos + 4
|
||||
data[pos] = byte(value)
|
||||
data[pos+1] = byte(value >> 8)
|
||||
data[pos+2] = byte(value >> 16)
|
||||
data[pos+3] = byte(value >> 24)
|
||||
return pos + 4
|
||||
}
|
||||
|
||||
func lenEncStringSize(value string) int {
|
||||
l := len(value)
|
||||
return lenEncIntSize(uint64(l)) + l
|
||||
l := len(value)
|
||||
return lenEncIntSize(uint64(l)) + l
|
||||
}
|
||||
|
||||
func writeLenEncString(data []byte, pos int, value string) int {
|
||||
pos = writeLenEncInt(data, pos, uint64(len(value)))
|
||||
return writeEOFString(data, pos, value)
|
||||
pos = writeLenEncInt(data, pos, uint64(len(value)))
|
||||
return writeEOFString(data, pos, value)
|
||||
}
|
||||
|
||||
func writeZeroes(data []byte, pos int, len int) int {
|
||||
for i := 0; i < len; i++ {
|
||||
data[pos+i] = 0
|
||||
}
|
||||
return pos + len
|
||||
for i := 0; i < len; i++ {
|
||||
data[pos+i] = 0
|
||||
}
|
||||
return pos + len
|
||||
}
|
||||
|
||||
//
|
||||
@@ -136,121 +136,121 @@ func writeZeroes(data []byte, pos int, len int) int {
|
||||
//
|
||||
|
||||
func readByte(data []byte, pos int) (byte, int, bool) {
|
||||
if pos >= len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
return data[pos], pos + 1, true
|
||||
if pos >= len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
return data[pos], pos + 1, true
|
||||
}
|
||||
|
||||
func readBytes(data []byte, pos int, size int) ([]byte, int, bool) {
|
||||
if pos+size-1 >= len(data) {
|
||||
return nil, 0, false
|
||||
}
|
||||
return data[pos : pos+size], pos + size, true
|
||||
if pos+size-1 >= len(data) {
|
||||
return nil, 0, false
|
||||
}
|
||||
return data[pos : pos+size], pos + size, true
|
||||
}
|
||||
|
||||
// readBytesCopy returns a copy of the bytes in the packet.
|
||||
// Useful to remember contents of ephemeral packets.
|
||||
func readBytesCopy(data []byte, pos int, size int) ([]byte, int, bool) {
|
||||
if pos+size-1 >= len(data) {
|
||||
return nil, 0, false
|
||||
}
|
||||
result := make([]byte, size)
|
||||
copy(result, data[pos:pos+size])
|
||||
return result, pos + size, true
|
||||
if pos+size-1 >= len(data) {
|
||||
return nil, 0, false
|
||||
}
|
||||
result := make([]byte, size)
|
||||
copy(result, data[pos:pos+size])
|
||||
return result, pos + size, true
|
||||
}
|
||||
|
||||
func readNullString(data []byte, pos int) (string, int, bool) {
|
||||
end := bytes.IndexByte(data[pos:], 0)
|
||||
if end == -1 {
|
||||
return "", 0, false
|
||||
}
|
||||
return string(data[pos : pos+end]), pos + end + 1, true
|
||||
end := bytes.IndexByte(data[pos:], 0)
|
||||
if end == -1 {
|
||||
return "", 0, false
|
||||
}
|
||||
return string(data[pos : pos+end]), pos + end + 1, true
|
||||
}
|
||||
|
||||
func readUint16(data []byte, pos int) (uint16, int, bool) {
|
||||
if pos+1 >= len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
return binary.LittleEndian.Uint16(data[pos : pos+2]), pos + 2, true
|
||||
if pos+1 >= len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
return binary.LittleEndian.Uint16(data[pos : pos+2]), pos + 2, true
|
||||
}
|
||||
|
||||
func readUint32(data []byte, pos int) (uint32, int, bool) {
|
||||
if pos+3 >= len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
return binary.LittleEndian.Uint32(data[pos : pos+4]), pos + 4, true
|
||||
if pos+3 >= len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
return binary.LittleEndian.Uint32(data[pos : pos+4]), pos + 4, true
|
||||
}
|
||||
|
||||
func readLenEncInt(data []byte, pos int) (uint64, int, bool) {
|
||||
if pos >= len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
switch data[pos] {
|
||||
case 0xfc:
|
||||
// Encoded in the next 2 bytes.
|
||||
if pos+2 >= len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
return uint64(data[pos+1]) |
|
||||
uint64(data[pos+2])<<8, pos + 3, true
|
||||
case 0xfd:
|
||||
// Encoded in the next 3 bytes.
|
||||
if pos+3 >= len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
return uint64(data[pos+1]) |
|
||||
uint64(data[pos+2])<<8 |
|
||||
uint64(data[pos+3])<<16, pos + 4, true
|
||||
case 0xfe:
|
||||
// Encoded in the next 8 bytes.
|
||||
if pos+8 >= len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
return uint64(data[pos+1]) |
|
||||
uint64(data[pos+2])<<8 |
|
||||
uint64(data[pos+3])<<16 |
|
||||
uint64(data[pos+4])<<24 |
|
||||
uint64(data[pos+5])<<32 |
|
||||
uint64(data[pos+6])<<40 |
|
||||
uint64(data[pos+7])<<48 |
|
||||
uint64(data[pos+8])<<56, pos + 9, true
|
||||
}
|
||||
return uint64(data[pos]), pos + 1, true
|
||||
if pos >= len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
switch data[pos] {
|
||||
case 0xfc:
|
||||
// Encoded in the next 2 bytes.
|
||||
if pos+2 >= len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
return uint64(data[pos+1]) |
|
||||
uint64(data[pos+2])<<8, pos + 3, true
|
||||
case 0xfd:
|
||||
// Encoded in the next 3 bytes.
|
||||
if pos+3 >= len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
return uint64(data[pos+1]) |
|
||||
uint64(data[pos+2])<<8 |
|
||||
uint64(data[pos+3])<<16, pos + 4, true
|
||||
case 0xfe:
|
||||
// Encoded in the next 8 bytes.
|
||||
if pos+8 >= len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
return uint64(data[pos+1]) |
|
||||
uint64(data[pos+2])<<8 |
|
||||
uint64(data[pos+3])<<16 |
|
||||
uint64(data[pos+4])<<24 |
|
||||
uint64(data[pos+5])<<32 |
|
||||
uint64(data[pos+6])<<40 |
|
||||
uint64(data[pos+7])<<48 |
|
||||
uint64(data[pos+8])<<56, pos + 9, true
|
||||
}
|
||||
return uint64(data[pos]), pos + 1, true
|
||||
}
|
||||
|
||||
func readLenEncString(data []byte, pos int) (string, int, bool) {
|
||||
size, pos, ok := readLenEncInt(data, pos)
|
||||
if !ok {
|
||||
return "", 0, false
|
||||
}
|
||||
s := int(size)
|
||||
if pos+s-1 >= len(data) {
|
||||
return "", 0, false
|
||||
}
|
||||
return string(data[pos : pos+s]), pos + s, true
|
||||
size, pos, ok := readLenEncInt(data, pos)
|
||||
if !ok {
|
||||
return "", 0, false
|
||||
}
|
||||
s := int(size)
|
||||
if pos+s-1 >= len(data) {
|
||||
return "", 0, false
|
||||
}
|
||||
return string(data[pos : pos+s]), pos + s, true
|
||||
}
|
||||
|
||||
func skipLenEncString(data []byte, pos int) (int, bool) {
|
||||
size, pos, ok := readLenEncInt(data, pos)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
s := int(size)
|
||||
if pos+s-1 >= len(data) {
|
||||
return 0, false
|
||||
}
|
||||
return pos + s, true
|
||||
size, pos, ok := readLenEncInt(data, pos)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
s := int(size)
|
||||
if pos+s-1 >= len(data) {
|
||||
return 0, false
|
||||
}
|
||||
return pos + s, true
|
||||
}
|
||||
|
||||
func readLenEncStringAsBytes(data []byte, pos int) ([]byte, int, bool) {
|
||||
size, pos, ok := readLenEncInt(data, pos)
|
||||
if !ok {
|
||||
return nil, 0, false
|
||||
}
|
||||
s := int(size)
|
||||
if pos+s-1 >= len(data) {
|
||||
return nil, 0, false
|
||||
}
|
||||
return data[pos : pos+s], pos + s, true
|
||||
size, pos, ok := readLenEncInt(data, pos)
|
||||
if !ok {
|
||||
return nil, 0, false
|
||||
}
|
||||
s := int(size)
|
||||
if pos+s-1 >= len(data) {
|
||||
return nil, 0, false
|
||||
}
|
||||
return data[pos : pos+s], pos + s, true
|
||||
}
|
||||
|
||||
+447
-472
File diff suppressed because it is too large
Load Diff
@@ -37,7 +37,6 @@ const (
|
||||
// timing metric keys
|
||||
connectTimingKey = "Connect"
|
||||
queryTimingKey = "Query"
|
||||
versionSSL30 = "SSL30"
|
||||
versionTLS10 = "TLS10"
|
||||
versionTLS11 = "TLS11"
|
||||
versionTLS12 = "TLS12"
|
||||
@@ -322,7 +321,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti
|
||||
}
|
||||
} else {
|
||||
if l.RequireSecureTransport {
|
||||
c.writeErrorPacketFromError(vterrors.Errorf(vtrpc.Code_UNAVAILABLE, "server does not allow insecure connections, client must use SSL/TLS"))
|
||||
_ = c.writeErrorPacketFromError(vterrors.Errorf(vtrpc.Code_UNAVAILABLE, "server does not allow insecure connections, client must use SSL/TLS"))
|
||||
}
|
||||
connCountByTLSVer.Add(versionNoTLS, 1)
|
||||
defer connCountByTLSVer.Add(versionNoTLS, -1)
|
||||
@@ -331,7 +330,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti
|
||||
// See what auth method the AuthServer wants to use for that user.
|
||||
authServerMethod, err := l.authServer.AuthMethod(user)
|
||||
if err != nil {
|
||||
c.writeErrorPacketFromError(err)
|
||||
_ = c.writeErrorPacketFromError(err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -344,7 +343,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti
|
||||
userData, err := l.authServer.ValidateHash(salt, user, authResponse, conn.RemoteAddr())
|
||||
if err != nil {
|
||||
log.Trace("Error authenticating user using MySQL native password: %v", err)
|
||||
c.writeErrorPacketFromError(err)
|
||||
_ = c.writeErrorPacketFromError(err)
|
||||
return
|
||||
}
|
||||
c.User = user
|
||||
@@ -358,8 +357,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//lint:ignore SA4006 This line is required because the binary protocol requires padding with 0
|
||||
data := make([]byte, 21)
|
||||
data := make([]byte, 21) //nolint:ineffassign,staticcheck // SA4006 This line is required because the binary protocol requires padding with 0
|
||||
data = append(salt, byte(0x00))
|
||||
if err := c.writeAuthSwitchRequest(MysqlNativePassword, data); err != nil {
|
||||
log.Error("Error writing auth switch packet for %s: %v", c, err)
|
||||
@@ -376,7 +374,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti
|
||||
userData, err := l.authServer.ValidateHash(salt, user, response, conn.RemoteAddr())
|
||||
if err != nil {
|
||||
log.Trace("Error authenticating user using MySQL native password: %v", err)
|
||||
c.writeErrorPacketFromError(err)
|
||||
_ = c.writeErrorPacketFromError(err)
|
||||
return
|
||||
}
|
||||
c.User = user
|
||||
@@ -387,7 +385,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti
|
||||
|
||||
// The negotiation happens in clear text. Let's check we can.
|
||||
if !l.AllowClearTextWithoutTLS && c.Capabilities&CapabilityClientSSL == 0 {
|
||||
c.writeErrorPacket(CRServerHandshakeErr, SSUnknownSQLState, "Cannot use clear text authentication over non-SSL connections.")
|
||||
_ = c.writeErrorPacket(CRServerHandshakeErr, SSUnknownSQLState, "Cannot use clear text authentication over non-SSL connections.")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -406,7 +404,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti
|
||||
// auth server.
|
||||
userData, err := l.authServer.Negotiate(c, user, conn.RemoteAddr())
|
||||
if err != nil {
|
||||
c.writeErrorPacketFromError(err)
|
||||
_ = c.writeErrorPacketFromError(err)
|
||||
return
|
||||
}
|
||||
c.User = user
|
||||
@@ -770,8 +768,6 @@ func (c *Conn) writeAuthSwitchRequest(pluginName string, pluginData []byte) erro
|
||||
// Whenever we move to a new version of go, we will need add any new supported TLS versions here
|
||||
func tlsVersionToString(version uint16) string {
|
||||
switch version {
|
||||
case tls.VersionSSL30:
|
||||
return versionSSL30
|
||||
case tls.VersionTLS10:
|
||||
return versionTLS10
|
||||
case tls.VersionTLS11:
|
||||
|
||||
@@ -17,58 +17,58 @@ limitations under the License.
|
||||
package vmysql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"vitess.io/vitess/go/vt/sqlparser"
|
||||
"vitess.io/vitess/go/vt/sqlparser"
|
||||
)
|
||||
|
||||
// SQLError is the error structure returned from calling a db library function
|
||||
type SQLError struct {
|
||||
Num int
|
||||
State string
|
||||
Message string
|
||||
Query string
|
||||
Num int
|
||||
State string
|
||||
Message string
|
||||
Query string
|
||||
}
|
||||
|
||||
// NewSQLError creates a new SQLError.
|
||||
// If sqlState is left empty, it will default to "HY000" (general error).
|
||||
// TODO: Should be aligned with vterrors, stack traces and wrapping
|
||||
func NewSQLError(number int, sqlState string, format string, args ...interface{}) *SQLError {
|
||||
if sqlState == "" {
|
||||
sqlState = SSUnknownSQLState
|
||||
}
|
||||
return &SQLError{
|
||||
Num: number,
|
||||
State: sqlState,
|
||||
Message: fmt.Sprintf(format, args...),
|
||||
}
|
||||
if sqlState == "" {
|
||||
sqlState = SSUnknownSQLState
|
||||
}
|
||||
return &SQLError{
|
||||
Num: number,
|
||||
State: sqlState,
|
||||
Message: fmt.Sprintf(format, args...),
|
||||
}
|
||||
}
|
||||
|
||||
// Error implements the error interface
|
||||
func (se *SQLError) Error() string {
|
||||
buf := &bytes.Buffer{}
|
||||
buf.WriteString(se.Message)
|
||||
buf := &bytes.Buffer{}
|
||||
buf.WriteString(se.Message)
|
||||
|
||||
// Add MySQL errno and SQLSTATE in a format that we can later parse.
|
||||
// There's no avoiding string parsing because all errors
|
||||
// are converted to strings anyway at RPC boundaries.
|
||||
// See NewSQLErrorFromError.
|
||||
fmt.Fprintf(buf, " (errno %v) (sqlstate %v)", se.Num, se.State)
|
||||
// Add MySQL errno and SQLSTATE in a format that we can later parse.
|
||||
// There's no avoiding string parsing because all errors
|
||||
// are converted to strings anyway at RPC boundaries.
|
||||
// See NewSQLErrorFromError.
|
||||
fmt.Fprintf(buf, " (errno %v) (sqlstate %v)", se.Num, se.State)
|
||||
|
||||
if se.Query != "" {
|
||||
fmt.Fprintf(buf, " during query: %s", sqlparser.TruncateForLog(se.Query))
|
||||
}
|
||||
if se.Query != "" {
|
||||
fmt.Fprintf(buf, " during query: %s", sqlparser.TruncateForLog(se.Query))
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// Number returns the internal MySQL error code.
|
||||
func (se *SQLError) Number() int {
|
||||
return se.Num
|
||||
return se.Num
|
||||
}
|
||||
|
||||
// SQLState returns the SQLSTATE value.
|
||||
func (se *SQLError) SQLState() string {
|
||||
return se.State
|
||||
}
|
||||
return se.State
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
package rhttp
|
||||
|
||||
type Config struct {
|
||||
IpHeader string
|
||||
IpHeader string
|
||||
}
|
||||
|
||||
+1
-1
@@ -119,7 +119,7 @@ func compileTpl(c *gin.Context, tpl string) (compiled string) {
|
||||
if headerVarMatcher.FindString(tpl) != "" {
|
||||
compiled = headerVarMatcher.ReplaceAllString(compiled, c.GetHeader(headerVarMatcher.FindStringSubmatch(tpl)[1]))
|
||||
}
|
||||
return
|
||||
return compiled
|
||||
}
|
||||
|
||||
func (s *Server) Receive(c *gin.Context) {
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@ type Record struct {
|
||||
Path string `form:"path" json:"path"`
|
||||
record.BaseRecord
|
||||
RawRequest string `json:"raw_request" notice:"-"`
|
||||
Rule Rule `gorm:"foreignKey:RuleName;references:Name;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" form:"-" json:"-" notice:"-"`
|
||||
Rule Rule `gorm:"foreignKey:RuleName;references:Name;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" form:"-" json:"-" notice:"-"`
|
||||
}
|
||||
|
||||
func (Record) TableName() string {
|
||||
@@ -42,7 +42,7 @@ func NewRecord(rule *Rule, flag, method, url, ip, area, raw string) (r *Record,
|
||||
Rule: *rule,
|
||||
}
|
||||
err = database.DB.Create(r).Error
|
||||
return
|
||||
return r, err
|
||||
}
|
||||
|
||||
func ListRecords(c *gin.Context) {
|
||||
|
||||
+4
-5
@@ -13,7 +13,7 @@ import (
|
||||
// Http rule struct
|
||||
type Rule struct {
|
||||
rule.BaseRule
|
||||
ResponseStatusCode string `gorm:"index;default:200;not null" form:"response_status_code" json:"response_status_code"`
|
||||
ResponseStatusCode string `gorm:"index;default:200;not null" form:"response_status_code" json:"response_status_code"`
|
||||
ResponseHeaders database.MapField `form:"response_headers" json:"response_headers"`
|
||||
ResponseBody string `gorm:"default:Hello RevSuit!" form:"response_body" json:"response_body"`
|
||||
}
|
||||
@@ -23,7 +23,7 @@ func (Rule) TableName() string {
|
||||
}
|
||||
|
||||
// New http rule struct
|
||||
func NewRule(name, flagFormat, responseBody string, pushToClient, notice bool, responseStatus string, responseHeaders database.MapField, ) *Rule {
|
||||
func NewRule(name, flagFormat, responseBody string, pushToClient, notice bool, responseStatus string, responseHeaders database.MapField) *Rule {
|
||||
return &Rule{
|
||||
BaseRule: rule.BaseRule{
|
||||
Name: name,
|
||||
@@ -59,7 +59,7 @@ func (r *Rule) CreateOrUpdate() (err error) {
|
||||
}
|
||||
|
||||
err = GetServer().updateRules()
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete the http rule in database and ruleSet
|
||||
@@ -71,7 +71,7 @@ func (r *Rule) Delete() (err error) {
|
||||
}
|
||||
|
||||
err = GetServer().updateRules()
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// List all http rules those satisfy the filter
|
||||
@@ -195,5 +195,4 @@ func DeleteRules(c *gin.Context) {
|
||||
"error": nil,
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ func ping(c *gin.Context) {
|
||||
}
|
||||
|
||||
func events(c *gin.Context) {
|
||||
log.Info("Receive connection from ", c.Request.RemoteAddr)
|
||||
log.Info("Receive connection from %v", c.Request.RemoteAddr)
|
||||
c.Stream(func(w io.Writer) bool {
|
||||
c.SSEvent("message", "connect succeed")
|
||||
select {
|
||||
|
||||
@@ -24,11 +24,29 @@ func initDatabase(dsn string) {
|
||||
}
|
||||
|
||||
err = database.DB.AutoMigrate(&http.Record{})
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
err = database.DB.AutoMigrate(&dns.Record{})
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
err = database.DB.AutoMigrate(&mysql.Record{})
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
err = database.DB.AutoMigrate(&http.Rule{})
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
err = database.DB.AutoMigrate(&dns.Rule{})
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
err = database.DB.AutoMigrate(&mysql.Rule{})
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
err = database.DB.AutoMigrate(&mysql.File{})
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
|
||||
Reference in New Issue
Block a user