2
0

Fix json marshal/unmarshal implementations

Fix marshal/unmarshal for:
- authentication_{cleartext_password, md5_password, ok, sasl, sasl_continue, sasl_final}
- error_response
This commit is contained in:
Yuli Khodorkovskiy
2021-05-27 14:47:56 -04:00
committed by Jack Christensen
parent 9c2c389e06
commit 28c20e93c0
8 changed files with 264 additions and 8 deletions
+10
View File
@@ -2,6 +2,7 @@ package pgproto3
import ( import (
"encoding/binary" "encoding/binary"
"encoding/json"
"errors" "errors"
"github.com/jackc/pgio" "github.com/jackc/pgio"
@@ -37,3 +38,12 @@ func (src *AuthenticationCleartextPassword) Encode(dst []byte) []byte {
dst = pgio.AppendUint32(dst, AuthTypeCleartextPassword) dst = pgio.AppendUint32(dst, AuthTypeCleartextPassword)
return dst return dst
} }
// MarshalJSON implements encoding/json.Marshaler.
func (src AuthenticationCleartextPassword) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Type string
}{
Type: "AuthenticationCleartextPassword",
})
}
+31
View File
@@ -2,6 +2,7 @@ package pgproto3
import ( import (
"encoding/binary" "encoding/binary"
"encoding/json"
"errors" "errors"
"github.com/jackc/pgio" "github.com/jackc/pgio"
@@ -41,3 +42,33 @@ func (src *AuthenticationMD5Password) Encode(dst []byte) []byte {
dst = append(dst, src.Salt[:]...) dst = append(dst, src.Salt[:]...)
return dst return dst
} }
// MarshalJSON implements encoding/json.Marshaler.
func (src AuthenticationMD5Password) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Type string
Salt [4]byte
}{
Type: "AuthenticationMD5Password",
Salt: src.Salt,
})
}
// UnmarshalJSON implements encoding/json.Unmarshaler.
func (dst *AuthenticationMD5Password) UnmarshalJSON(data []byte) error {
// Ignore null, like in the main JSON package.
if string(data) == "null" {
return nil
}
var msg struct {
Type string
Salt [4]byte
}
if err := json.Unmarshal(data, &msg); err != nil {
return err
}
dst.Salt = msg.Salt
return nil
}
+10
View File
@@ -2,6 +2,7 @@ package pgproto3
import ( import (
"encoding/binary" "encoding/binary"
"encoding/json"
"errors" "errors"
"github.com/jackc/pgio" "github.com/jackc/pgio"
@@ -37,3 +38,12 @@ func (src *AuthenticationOk) Encode(dst []byte) []byte {
dst = pgio.AppendUint32(dst, AuthTypeOk) dst = pgio.AppendUint32(dst, AuthTypeOk)
return dst return dst
} }
// MarshalJSON implements encoding/json.Marshaler.
func (src AuthenticationOk) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Type string
}{
Type: "AuthenticationOK",
})
}
+12
View File
@@ -3,6 +3,7 @@ package pgproto3
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"encoding/json"
"errors" "errors"
"github.com/jackc/pgio" "github.com/jackc/pgio"
@@ -58,3 +59,14 @@ func (src *AuthenticationSASL) Encode(dst []byte) []byte {
return dst return dst
} }
// MarshalJSON implements encoding/json.Marshaler.
func (src AuthenticationSASL) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Type string
AuthMechanisms []string
}{
Type: "AuthenticationSASL",
AuthMechanisms: src.AuthMechanisms,
})
}
+11
View File
@@ -48,6 +48,17 @@ func (src *AuthenticationSASLContinue) Encode(dst []byte) []byte {
return dst return dst
} }
// MarshalJSON implements encoding/json.Marshaler.
func (src AuthenticationSASLContinue) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Type string
Data string
}{
Type: "AuthenticationSASLContinue",
Data: string(src.Data),
})
}
// UnmarshalJSON implements encoding/json.Unmarshaler. // UnmarshalJSON implements encoding/json.Unmarshaler.
func (dst *AuthenticationSASLContinue) UnmarshalJSON(data []byte) error { func (dst *AuthenticationSASLContinue) UnmarshalJSON(data []byte) error {
// Ignore null, like in the main JSON package. // Ignore null, like in the main JSON package.
+11
View File
@@ -48,6 +48,17 @@ func (src *AuthenticationSASLFinal) Encode(dst []byte) []byte {
return dst return dst
} }
// MarshalJSON implements encoding/json.Unmarshaler.
func (src AuthenticationSASLFinal) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Type string
Data string
}{
Type: "AuthenticationSASLFinal",
Data: string(src.Data),
})
}
// UnmarshalJSON implements encoding/json.Unmarshaler. // UnmarshalJSON implements encoding/json.Unmarshaler.
func (dst *AuthenticationSASLFinal) UnmarshalJSON(data []byte) error { func (dst *AuthenticationSASLFinal) UnmarshalJSON(data []byte) error {
// Ignore null, like in the main JSON package. // Ignore null, like in the main JSON package.
+107
View File
@@ -3,6 +3,7 @@ package pgproto3
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"encoding/json"
"strconv" "strconv"
) )
@@ -225,3 +226,109 @@ func (src *ErrorResponse) marshalBinary(typeByte byte) []byte {
return buf.Bytes() return buf.Bytes()
} }
// MarshalJSON implements encoding/json.Marshaler.
func (src ErrorResponse) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Type string
Severity string
SeverityUnlocalized string // only in 9.6 and greater
Code string
Message string
Detail string
Hint string
Position int32
InternalPosition int32
InternalQuery string
Where string
SchemaName string
TableName string
ColumnName string
DataTypeName string
ConstraintName string
File string
Line int32
Routine string
UnknownFields map[byte]string
}{
Type: "ErrorResponse",
Severity: src.Severity,
SeverityUnlocalized: src.SeverityUnlocalized,
Code: src.Code,
Message: src.Message,
Detail: src.Detail,
Hint: src.Hint,
Position: src.Position,
InternalPosition: src.InternalPosition,
InternalQuery: src.InternalQuery,
Where: src.Where,
SchemaName: src.SchemaName,
TableName: src.TableName,
ColumnName: src.ColumnName,
DataTypeName: src.DataTypeName,
ConstraintName: src.ConstraintName,
File: src.File,
Line: src.Line,
Routine: src.Routine,
UnknownFields: src.UnknownFields,
})
}
// UnmarshalJSON implements encoding/json.Unmarshaler.
func (dst *ErrorResponse) UnmarshalJSON(data []byte) error {
// Ignore null, like in the main JSON package.
if string(data) == "null" {
return nil
}
var msg struct {
Type string
Severity string
SeverityUnlocalized string // only in 9.6 and greater
Code string
Message string
Detail string
Hint string
Position int32
InternalPosition int32
InternalQuery string
Where string
SchemaName string
TableName string
ColumnName string
DataTypeName string
ConstraintName string
File string
Line int32
Routine string
UnknownFields map[byte]string
}
if err := json.Unmarshal(data, &msg); err != nil {
return err
}
dst.Severity = msg.Severity
dst.SeverityUnlocalized = msg.SeverityUnlocalized
dst.Code = msg.Code
dst.Message = msg.Message
dst.Detail = msg.Detail
dst.Hint = msg.Hint
dst.Position = msg.Position
dst.InternalPosition = msg.InternalPosition
dst.InternalQuery = msg.InternalQuery
dst.Where = msg.Where
dst.SchemaName = msg.SchemaName
dst.TableName = msg.TableName
dst.ColumnName = msg.ColumnName
dst.DataTypeName = msg.DataTypeName
dst.ConstraintName = msg.ConstraintName
dst.File = msg.File
dst.Line = msg.Line
dst.Routine = msg.Routine
dst.UnknownFields = msg.UnknownFields
return nil
}
+72 -8
View File
@@ -23,9 +23,9 @@ func TestJSONUnmarshalAuthenticationMD5Password(t *testing.T) {
} }
func TestJSONUnmarshalAuthenticationSASL(t *testing.T) { func TestJSONUnmarshalAuthenticationSASL(t *testing.T) {
data := []byte(`{"Type":"AuthenticationSASL", "AuthMechanisms":[]}`) data := []byte(`{"Type":"AuthenticationSASL","AuthMechanisms":["SCRAM-SHA-256"]}`)
want := AuthenticationSASL{ want := AuthenticationSASL{
AuthMechanisms: []string{}, []string{"SCRAM-SHA-256"},
} }
var got AuthenticationSASL var got AuthenticationSASL
@@ -38,9 +38,9 @@ func TestJSONUnmarshalAuthenticationSASL(t *testing.T) {
} }
func TestJSONUnmarshalAuthenticationSASLContinue(t *testing.T) { func TestJSONUnmarshalAuthenticationSASLContinue(t *testing.T) {
data := []byte(`{"Type":"AuthenticationSASLContinue"}`) data := []byte(`{"Type":"AuthenticationSASLContinue", "Data":"1"}`)
want := AuthenticationSASLContinue{ want := AuthenticationSASLContinue{
Data: []byte{}, Data: []byte{'1'},
} }
var got AuthenticationSASLContinue var got AuthenticationSASLContinue
@@ -53,9 +53,9 @@ func TestJSONUnmarshalAuthenticationSASLContinue(t *testing.T) {
} }
func TestJSONUnmarshalAuthenticationSASLFinal(t *testing.T) { func TestJSONUnmarshalAuthenticationSASLFinal(t *testing.T) {
data := []byte(`{"Type":"AuthenticationSASLFinal"}`) data := []byte(`{"Type":"AuthenticationSASLFinal", "Data":"1"}`)
want := AuthenticationSASLFinal{ want := AuthenticationSASLFinal{
Data: []byte{}, Data: []byte{'1'},
} }
var got AuthenticationSASLFinal var got AuthenticationSASLFinal
@@ -463,8 +463,11 @@ func TestJSONUnmarshalQuery(t *testing.T) {
} }
func TestJSONUnmarshalSASLInitialResponse(t *testing.T) { func TestJSONUnmarshalSASLInitialResponse(t *testing.T) {
data := []byte(`{"Type":"SASLInitialResponse"}`) data := []byte(`{"Type":"SASLInitialResponse", "AuthMechanism":"SCRAM-SHA-256", "Data": "6D"}`)
want := SASLInitialResponse{} want := SASLInitialResponse{
AuthMechanism: "SCRAM-SHA-256",
Data: []byte{109},
}
var got SASLInitialResponse var got SASLInitialResponse
if err := json.Unmarshal(data, &got); err != nil { if err := json.Unmarshal(data, &got); err != nil {
@@ -506,3 +509,64 @@ func TestJSONUnmarshalStartupMessage(t *testing.T) {
t.Error("unmarshaled StartupMessage struct doesn't match expected value") t.Error("unmarshaled StartupMessage struct doesn't match expected value")
} }
} }
func TestAuthenticationOK(t *testing.T) {
data := []byte(`{"Type":"AuthenticationOK"}`)
want := AuthenticationOk{}
var got AuthenticationOk
if err := json.Unmarshal(data, &got); err != nil {
t.Errorf("cannot JSON unmarshal %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Error("unmarshaled AuthenticationOK struct doesn't match expected value")
}
}
func TestAuthenticationCleartextPassword(t *testing.T) {
data := []byte(`{"Type":"AuthenticationCleartextPassword"}`)
want := AuthenticationCleartextPassword{}
var got AuthenticationCleartextPassword
if err := json.Unmarshal(data, &got); err != nil {
t.Errorf("cannot JSON unmarshal %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Error("unmarshaled AuthenticationCleartextPassword struct doesn't match expected value")
}
}
func TestAuthenticationMD5Password(t *testing.T) {
data := []byte(`{"Type":"AuthenticationMD5Password","Salt":[1,2,3,4]}`)
want := AuthenticationMD5Password{
Salt: [4]byte{1, 2, 3, 4},
}
var got AuthenticationMD5Password
if err := json.Unmarshal(data, &got); err != nil {
t.Errorf("cannot JSON unmarshal %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Error("unmarshaled AuthenticationMD5Password struct doesn't match expected value")
}
}
func TestErrorResponse(t *testing.T) {
data := []byte(`{"Type":"ErrorResponse","UnknownFields":{"112":"foo"},"Code": "Fail","Position":1,"Message":"this is an error"}`)
want := ErrorResponse{
UnknownFields: map[byte]string{
'p': "foo",
},
Code: "Fail",
Position: 1,
Message: "this is an error",
}
var got ErrorResponse
if err := json.Unmarshal(data, &got); err != nil {
t.Errorf("cannot JSON unmarshal %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Error("unmarshaled ErrorResponse struct doesn't match expected value")
}
}