Closed lgrip closed 4 years ago
I am not sure what is now working.
What do you expect? What do you see?
We expect string values to be decoded as strings and []byte values to be decoded as []byte.
Now, it seems like we need to choose to decode intercface{} values either as []byte (normal settings) or everything as string (RawToString == true).
I'm running into something similar; my expectation with RawToString=true is that string types in msgpack (fixstr, str8, str16, str32) are decoded as string
, but binary values (bin8, bin16, bin32) should be decoded as []byte
. We have an app that has to distinguish between strings and bytes, so this is a blocker for us using this package.
In particular this line https://github.com/ugorji/go/blob/master/codec/msgpack.go#L574 looks wrong, it should just pass false
to fauxUnionReadRawBytes
. Moreover, this line https://github.com/ugorji/go/blob/master/codec/msgpack.go#L818 seems wrong as-is, since decoding with RawToString=true decodes the value as string
, not []byte
.
This issue has impact on the Nexus wamp router too, with both strings and []bytes ending up as strings when routed. Causing autobahn|python clients to trow protocol errors.
can we get an update on this issue, there is a PR that fixes it and would help out anyone trying to work with both strings and bytes
In msgpack, there are 2 supported specs.
In the old spec: fixraw was 101xxxxx (for raw bytes). This is now called fixstr in the new spec (for strings).
See
We determine whether to support the new or old spec based on the value of WriteExt (true or false).
If you want fixstr to be decoded as a string, it means that you want to honor the new spec, so you should set WriteExt=true.
If however, WriteExt=false (meaning you want to honor the old msgpack spec), but you want to fixraw to be decoded as string (not []byte), then you should set RawToString=true also.
It is hard for me to parse what you mean when you say:
We expect string values to be decoded as strings and []byte values to be decoded as []byte.
Hopefully, the above makes it clear how things should work.
I tested this on an adaptation of your code and it works fine:
func TestGithub315(t *testing.T) {
type A struct {
S string
Y []byte
}
type B struct {
S interface{}
Y interface{}
}
h := new(codec.MsgpackHandle)
h.WriteExt = true
var b bytes.Buffer
e := codec.NewEncoder(&b, h)
if err := e.Encode(A{"foo", []byte{0xca, 0xfe}}); err != nil {
t.Fatal("encode", err)
}
buf := b.Bytes()
fmt.Printf("buf: %#v\n", buf)
var b2 B
codec.NewDecoderBytes(buf, h).MustDecode(&b2)
if got, want := b2, (B{"foo", []byte{0xca, 0xfe}}); !reflect.DeepEqual(got, want) {
t.Logf("got %#v", got)
t.Logf("want %#v", want)
t.Fail()
}
}
In summary:
You need to set WriteExt=true so that the new spec is honored. When we built this library, most uses were using the old spec and the new spec was in its infancy, so it is an opt-in. Opt into it by setting the flag WriteExt=true.
We have an object with an
interface{}
value which can either be astring
or a[]byte
. On decoding the value is always set to a[]byte
value unless we set theRawToString
option totrue
. Then the value is always astring
. This makes it impossible to tell astring
from a[]byte
value for a given field.We can see in the byte stream that the string is encoded as a
fixstr
with a0xaN
type.Is this the way this should work?
What are we missing?