Skip to content

Commit 248265d

Browse files
skoefReinier Schoof
authored and
Reinier Schoof
committed
support client connection attributes on the client side
1 parent d166653 commit 248265d

File tree

3 files changed

+74
-0
lines changed

3 files changed

+74
-0
lines changed

client/auth.go

+26
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,20 @@ func (c *Conn) genAuthResponse(authData []byte) ([]byte, bool, error) {
139139
}
140140
}
141141

142+
// generate connection attributes data
143+
func (c *Conn) genAttributes() []byte {
144+
if len(c.attributes) == 0 {
145+
return nil
146+
}
147+
148+
attrData := make([]byte, 0)
149+
for k, v := range c.attributes {
150+
attrData = append(attrData, PutLengthEncodedString([]byte(k))...)
151+
attrData = append(attrData, PutLengthEncodedString([]byte(v))...)
152+
}
153+
return append(PutLengthEncodedInt(uint64(len(attrData))), attrData...)
154+
}
155+
142156
// See: http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse
143157
func (c *Conn) writeAuthHandshake() error {
144158
if !authPluginAllowed(c.authPluginName) {
@@ -195,6 +209,12 @@ func (c *Conn) writeAuthHandshake() error {
195209
capability |= CLIENT_CONNECT_WITH_DB
196210
length += len(c.db) + 1
197211
}
212+
// connection attributes
213+
attrData := c.genAttributes()
214+
if len(attrData) > 0 {
215+
capability |= CLIENT_CONNECT_ATTRS
216+
length += len(attrData)
217+
}
198218

199219
data := make([]byte, length+4)
200220

@@ -264,6 +284,12 @@ func (c *Conn) writeAuthHandshake() error {
264284
// Assume native client during response
265285
pos += copy(data[pos:], c.authPluginName)
266286
data[pos] = 0x00
287+
pos++
288+
289+
// connection attributes
290+
if len(attrData) > 0 {
291+
copy(data[pos:], attrData)
292+
}
267293

268294
return c.WritePacket(data)
269295
}

client/auth_test.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package client
2+
3+
import (
4+
"bytes"
5+
"testing"
6+
7+
"github.com/go-mysql-org/go-mysql/mysql"
8+
)
9+
10+
func TestConnGenAttributes(t *testing.T) {
11+
c := &Conn{
12+
// example data from
13+
// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse41
14+
attributes: map[string]string{
15+
"_os": "debian6.0",
16+
"_client_name": "libmysql",
17+
"_pid": "22344",
18+
"_client_version": "5.6.6-m9",
19+
"_platform": "x86_64",
20+
"foo": "bar",
21+
},
22+
}
23+
24+
data := c.genAttributes()
25+
26+
// the order of the attributes map cannot be guaranteed so to test the content
27+
// of the attribute data we need to check its partial contents
28+
29+
if len(data) != 98 {
30+
t.Fatalf("unexpected data length, got %d", len(data))
31+
}
32+
if data[0] != 0x61 {
33+
t.Fatalf("unexpected length-encoded int, got %#x", data[0])
34+
}
35+
36+
for k, v := range c.attributes {
37+
fixt := append(mysql.PutLengthEncodedString([]byte(k)), mysql.PutLengthEncodedString([]byte(v))...)
38+
if !bytes.Contains(data, fixt) {
39+
t.Fatalf("%s attribute not found", k)
40+
}
41+
}
42+
}

client/conn.go

+6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ type Conn struct {
2828
// client-set capabilities only
2929
ccaps uint32
3030

31+
attributes map[string]string
32+
3133
status uint16
3234

3335
charset string
@@ -302,6 +304,10 @@ func (c *Conn) Rollback() error {
302304
return errors.Trace(err)
303305
}
304306

307+
func (c *Conn) SetAttributes(attributes map[string]string) {
308+
c.attributes = attributes
309+
}
310+
305311
func (c *Conn) SetCharset(charset string) error {
306312
if c.charset == charset {
307313
return nil

0 commit comments

Comments
 (0)