• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

go-sql-driver / mysql / 14665995848

25 Apr 2025 01:39PM UTC coverage: 82.772% (-0.2%) from 82.961%
14665995848

Pull #1696

github

rusher
use named constants for caching_sha2_password
Pull Request #1696: Authentication

321 of 387 new or added lines in 9 files covered. (82.95%)

7 existing lines in 3 files now uncovered.

3315 of 4005 relevant lines covered (82.77%)

2440698.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.44
/connector.go
1
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
2
//
3
// Copyright 2018 The Go-MySQL-Driver Authors. All rights reserved.
4
//
5
// This Source Code Form is subject to the terms of the Mozilla Public
6
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
7
// You can obtain one at http://mozilla.org/MPL/2.0/.
8

9
package mysql
10

11
import (
12
        "context"
13
        "database/sql/driver"
14
        "fmt"
15
        "net"
16
        "os"
17
        "strconv"
18
        "strings"
19
)
20

21
const (
22
        authMaximumSwitch = 5
23
)
24

25
type connector struct {
26
        cfg               *Config // immutable private copy.
27
        encodedAttributes string  // Encoded connection attributes.
28
}
29

30
func encodeConnectionAttributes(cfg *Config) string {
6,722✔
31
        connAttrsBuf := make([]byte, 0)
6,722✔
32

6,722✔
33
        // default connection attributes
6,722✔
34
        connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrClientName)
6,722✔
35
        connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrClientNameValue)
6,722✔
36
        connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrOS)
6,722✔
37
        connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrOSValue)
6,722✔
38
        connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrPlatform)
6,722✔
39
        connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrPlatformValue)
6,722✔
40
        connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrPid)
6,722✔
41
        connAttrsBuf = appendLengthEncodedString(connAttrsBuf, strconv.Itoa(os.Getpid()))
6,722✔
42
        serverHost, _, _ := net.SplitHostPort(cfg.Addr)
6,722✔
43
        if serverHost != "" {
11,970✔
44
                connAttrsBuf = appendLengthEncodedString(connAttrsBuf, connAttrServerHost)
5,248✔
45
                connAttrsBuf = appendLengthEncodedString(connAttrsBuf, serverHost)
5,248✔
46
        }
5,248✔
47

48
        // user-defined connection attributes
49
        for _, connAttr := range strings.Split(cfg.ConnectionAttributes, ",") {
13,700✔
50
                k, v, found := strings.Cut(connAttr, ":")
6,978✔
51
                if !found {
13,444✔
52
                        continue
6,466✔
53
                }
54
                connAttrsBuf = appendLengthEncodedString(connAttrsBuf, k)
512✔
55
                connAttrsBuf = appendLengthEncodedString(connAttrsBuf, v)
512✔
56
        }
57

58
        return string(connAttrsBuf)
6,722✔
59
}
60

61
func newConnector(cfg *Config) *connector {
6,722✔
62
        encodedAttributes := encodeConnectionAttributes(cfg)
6,722✔
63
        return &connector{
6,722✔
64
                cfg:               cfg,
6,722✔
65
                encodedAttributes: encodedAttributes,
6,722✔
66
        }
6,722✔
67
}
6,722✔
68

69
// Connect implements driver.Connector interface.
70
// Connect returns a connection to the database.
71
func (c *connector) Connect(ctx context.Context) (driver.Conn, error) {
17,437✔
72
        var err error
17,437✔
73

17,437✔
74
        // Invoke beforeConnect if present, with a copy of the configuration
17,437✔
75
        cfg := c.cfg
17,437✔
76
        if c.cfg.beforeConnect != nil {
17,469✔
77
                cfg = c.cfg.Clone()
32✔
78
                err = c.cfg.beforeConnect(ctx, cfg)
32✔
79
                if err != nil {
32✔
80
                        return nil, err
×
81
                }
×
82
        }
83

84
        // New mysqlConn
85
        mc := &mysqlConn{
17,437✔
86
                maxAllowedPacket: maxPacketSize,
17,437✔
87
                maxWriteSize:     maxPacketSize - 1,
17,437✔
88
                closech:          make(chan struct{}),
17,437✔
89
                cfg:              cfg,
17,437✔
90
                connector:        c,
17,437✔
91
        }
17,437✔
92
        mc.parseTime = mc.cfg.ParseTime
17,437✔
93

17,437✔
94
        // Connect to Server
17,437✔
95
        dctx := ctx
17,437✔
96
        if mc.cfg.Timeout > 0 {
34,778✔
97
                var cancel context.CancelFunc
17,341✔
98
                dctx, cancel = context.WithTimeout(ctx, c.cfg.Timeout)
17,341✔
99
                defer cancel()
17,341✔
100
        }
17,341✔
101

102
        if c.cfg.DialFunc != nil {
17,437✔
103
                mc.netConn, err = c.cfg.DialFunc(dctx, mc.cfg.Net, mc.cfg.Addr)
×
104
        } else {
17,437✔
105
                dialsLock.RLock()
17,437✔
106
                dial, ok := dials[mc.cfg.Net]
17,437✔
107
                dialsLock.RUnlock()
17,437✔
108
                if ok {
17,661✔
109
                        mc.netConn, err = dial(dctx, mc.cfg.Addr)
224✔
110
                } else {
17,437✔
111
                        nd := net.Dialer{}
17,213✔
112
                        mc.netConn, err = nd.DialContext(dctx, mc.cfg.Net, mc.cfg.Addr)
17,213✔
113
                }
17,213✔
114
        }
115
        if err != nil {
17,742✔
116
                return nil, err
305✔
117
        }
305✔
118
        mc.rawConn = mc.netConn
17,132✔
119

17,132✔
120
        // Enable TCP Keepalives on TCP connections
17,132✔
121
        if tc, ok := mc.netConn.(*net.TCPConn); ok {
34,134✔
122
                if err := tc.SetKeepAlive(true); err != nil {
17,002✔
123
                        c.cfg.Logger.Print(err)
×
124
                }
×
125
        }
126

127
        // Call startWatcher for context support (From Go 1.8)
128
        mc.startWatcher()
17,132✔
129
        if err := mc.watchCancel(ctx); err != nil {
17,231✔
130
                mc.cleanup()
99✔
131
                return nil, err
99✔
132
        }
99✔
133
        defer mc.finish()
17,033✔
134

17,033✔
135
        mc.buf = newBuffer()
17,033✔
136

17,033✔
137
        // Reading Handshake Initialization Packet
17,033✔
138
        authData, plugin, err := mc.readHandshakePacket()
17,033✔
139
        if err != nil {
17,222✔
140
                mc.cleanup()
189✔
141
                return nil, err
189✔
142
        }
189✔
143

144
        if plugin == "" {
16,844✔
145
                plugin = defaultAuthPlugin
×
146
        }
×
147
        authPlugin, exists := globalPluginRegistry.GetPlugin(plugin)
16,844✔
148
        if !exists {
16,844✔
NEW
149
                return nil, fmt.Errorf("this authentication plugin '%s' is not supported", plugin)
×
NEW
150
        }
×
151

152
        // Send Client Authentication Packet
153
        authResp, err := authPlugin.InitAuth(authData, mc.cfg)
16,844✔
154
        if err != nil {
16,844✔
NEW
155
                mc.cleanup()
×
NEW
156
                return nil, err
×
UNCOV
157
        }
×
158
        if err = mc.writeHandshakeResponsePacket(authResp, plugin); err != nil {
19,192✔
159
                mc.cleanup()
2,348✔
160
                return nil, err
2,348✔
161
        }
2,348✔
162

163
        // Handle response to auth packet, switch methods if possible
164
        if err = mc.handleAuthResult(authMaximumSwitch, authData, authPlugin); err != nil {
16,358✔
165
                // Authentication failed and MySQL has already closed the connection
1,862✔
166
                // (https://dev.mysql.com/doc/internals/en/authentication-fails.html).
1,862✔
167
                // Do not send COM_QUIT, just cleanup and return the error.
1,862✔
168
                mc.cleanup()
1,862✔
169
                return nil, err
1,862✔
170
        }
1,862✔
171

172
        if mc.cfg.compress && mc.flags&clientCompress == clientCompress {
16,134✔
173
                mc.compress = true
3,500✔
174
                mc.compIO = newCompIO(mc)
3,500✔
175
        }
3,500✔
176
        if mc.cfg.MaxAllowedPacket > 0 {
25,172✔
177
                mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket
12,538✔
178
        } else {
12,634✔
179
                // Get max allowed packet size
96✔
180
                maxap, err := mc.getSystemVar("max_allowed_packet")
96✔
181
                if err != nil {
96✔
182
                        mc.Close()
×
183
                        return nil, err
×
184
                }
×
185
                n, err := strconv.Atoi(string(maxap))
96✔
186
                if err != nil {
96✔
187
                        mc.Close()
×
188
                        return nil, fmt.Errorf("invalid max_allowed_packet value (%q): %w", maxap, err)
×
189
                }
×
190
                mc.maxAllowedPacket = n - 1
96✔
191
        }
192
        if mc.maxAllowedPacket < maxPacketSize {
12,634✔
193
                mc.maxWriteSize = mc.maxAllowedPacket
×
194
        }
×
195

196
        // Charset: character_set_connection, character_set_client, character_set_results
197
        if len(mc.cfg.charsets) > 0 {
13,082✔
198
                for _, cs := range mc.cfg.charsets {
992✔
199
                        // ignore errors here - a charset may not exist
544✔
200
                        if mc.cfg.Collation != "" {
544✔
201
                                err = mc.exec("SET NAMES " + cs + " COLLATE " + mc.cfg.Collation)
×
202
                        } else {
544✔
203
                                err = mc.exec("SET NAMES " + cs)
544✔
204
                        }
544✔
205
                        if err == nil {
928✔
206
                                break
384✔
207
                        }
208
                }
209
                if err != nil {
512✔
210
                        mc.Close()
64✔
211
                        return nil, err
64✔
212
                }
64✔
213
        }
214

215
        // Handle DSN Params
216
        err = mc.handleParams()
12,570✔
217
        if err != nil {
12,570✔
218
                mc.Close()
×
219
                return nil, err
×
220
        }
×
221

222
        return mc, nil
12,570✔
223
}
224

225
// Driver implements driver.Connector interface.
226
// Driver returns &MySQLDriver{}.
227
func (c *connector) Driver() driver.Driver {
×
228
        return &MySQLDriver{}
×
229
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc