Commit 8332112d authored by Adam Langley's avatar Adam Langley

encoding/asn1: only omit optional elements matching default value.

ASN.1 elements can be optional, and can have a default value.
Traditionally, Go has omitted elements that are optional and that have
the zero value. I believe that's a bug (see [1]).

This change causes an optional element with a default value to only be
omitted when it has that default value. The previous behaviour of
omitting optional, zero elements with no default is retained because
it's used quite a lot and will break things if changed.

[1] https://groups.google.com/d/msg/Golang-nuts/9Ss6o9CW-Yo/KL_V7hFlyOAJ

Fixes #7780.

R=bradfitz

LGTM=bradfitz
R=golang-codereviews, bradfitz, rsc
CC=golang-codereviews, r
https://golang.org/cl/86960045
parent 42d0785b
...@@ -822,8 +822,19 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam ...@@ -822,8 +822,19 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
return return
} }
// canHaveDefaultValue reports whether k is a Kind that we will set a default
// value for. (A signed integer, essentially.)
func canHaveDefaultValue(k reflect.Kind) bool {
switch k {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return true
}
return false
}
// setDefaultValue is used to install a default value, from a tag string, into // setDefaultValue is used to install a default value, from a tag string, into
// a Value. It is successful is the field was optional, even if a default value // a Value. It is successful if the field was optional, even if a default value
// wasn't provided or it failed to install it into the Value. // wasn't provided or it failed to install it into the Value.
func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) { func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
if !params.optional { if !params.optional {
...@@ -833,9 +844,8 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) { ...@@ -833,9 +844,8 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
if params.defaultValue == nil { if params.defaultValue == nil {
return return
} }
switch val := v; val.Kind() { if canHaveDefaultValue(v.Kind()) {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: v.SetInt(*params.defaultValue)
val.SetInt(*params.defaultValue)
} }
return return
} }
......
...@@ -513,8 +513,22 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) ...@@ -513,8 +513,22 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
return return
} }
if params.optional && reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) { if params.optional && params.defaultValue != nil && canHaveDefaultValue(v.Kind()) {
return defaultValue := reflect.New(v.Type()).Elem()
defaultValue.SetInt(*params.defaultValue)
if reflect.DeepEqual(v.Interface(), defaultValue.Interface()) {
return
}
}
// If no default value is given then the zero value for the type is
// assumed to be the default value. This isn't obviously the correct
// behaviour, but it's what Go has traditionally done.
if params.optional && params.defaultValue == nil {
if reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) {
return
}
} }
if v.Type() == rawValueType { if v.Type() == rawValueType {
......
...@@ -58,6 +58,10 @@ type omitEmptyTest struct { ...@@ -58,6 +58,10 @@ type omitEmptyTest struct {
A []string `asn1:"omitempty"` A []string `asn1:"omitempty"`
} }
type defaultTest struct {
A int `asn1:"optional,default:1"`
}
type testSET []int type testSET []int
var PST = time.FixedZone("PST", -8*60*60) var PST = time.FixedZone("PST", -8*60*60)
...@@ -133,6 +137,9 @@ var marshalTests = []marshalTest{ ...@@ -133,6 +137,9 @@ var marshalTests = []marshalTest{
{omitEmptyTest{[]string{}}, "3000"}, {omitEmptyTest{[]string{}}, "3000"},
{omitEmptyTest{[]string{"1"}}, "30053003130131"}, {omitEmptyTest{[]string{"1"}}, "30053003130131"},
{"Σ", "0c02cea3"}, {"Σ", "0c02cea3"},
{defaultTest{0}, "3003020100"},
{defaultTest{1}, "3000"},
{defaultTest{2}, "3003020102"},
} }
func TestMarshal(t *testing.T) { func TestMarshal(t *testing.T) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment