mirror of
https://github.com/ProtonMail/go-proton-api.git
synced 2025-12-23 15:47:52 -05:00
110 lines
1.9 KiB
Go
110 lines
1.9 KiB
Go
package proton
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"gitlab.com/c0b/go-ordered-json"
|
|
)
|
|
|
|
var ErrBadHeader = errors.New("bad header")
|
|
|
|
type Headers struct {
|
|
Values map[string][]string
|
|
Order []string
|
|
}
|
|
|
|
func (h *Headers) UnmarshalJSON(b []byte) error {
|
|
type rawHeaders map[string]any
|
|
|
|
raw := make(rawHeaders)
|
|
|
|
// Need to use a different type to deserialize, because there still is no official way for json to decode an object
|
|
// with the fields in order https://github.com/golang/go/issues/27179.
|
|
orderedMap := ordered.NewOrderedMap()
|
|
if err := orderedMap.UnmarshalJSON(b); err != nil {
|
|
return err
|
|
}
|
|
|
|
header := Headers{
|
|
Values: make(map[string][]string, len(raw)),
|
|
Order: make([]string, 0, len(raw)),
|
|
}
|
|
|
|
iter := orderedMap.EntriesIter()
|
|
|
|
for {
|
|
entry, ok := iter()
|
|
if !ok {
|
|
break
|
|
}
|
|
|
|
switch val := entry.Value.(type) {
|
|
case string:
|
|
header.Values[entry.Key] = []string{val}
|
|
|
|
case []any:
|
|
for _, val := range val {
|
|
switch val := val.(type) {
|
|
case string:
|
|
header.Values[entry.Key] = append(header.Values[entry.Key], val)
|
|
|
|
default:
|
|
return ErrBadHeader
|
|
}
|
|
}
|
|
|
|
default:
|
|
return ErrBadHeader
|
|
}
|
|
|
|
header.Order = append(header.Order, entry.Key)
|
|
}
|
|
|
|
*h = header
|
|
|
|
return nil
|
|
}
|
|
|
|
func (h Headers) MarshalJSON() ([]byte, error) {
|
|
// Manually Serialize to preserve oder
|
|
if len(h.Values) == 0 {
|
|
return []byte{'{', '}'}, nil
|
|
}
|
|
|
|
out := make([]byte, 0, 64)
|
|
|
|
out = append(out, '{')
|
|
|
|
for _, k := range h.Order {
|
|
v := h.Values[k]
|
|
|
|
if len(v) == 0 {
|
|
continue
|
|
}
|
|
|
|
key, err := json.Marshal(k)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var val []byte
|
|
if len(v) == 1 {
|
|
val, err = json.Marshal(v[0])
|
|
} else {
|
|
val, err = json.Marshal(v)
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out = append(out, key...)
|
|
out = append(out, ':')
|
|
out = append(out, val...)
|
|
out = append(out, ',')
|
|
}
|
|
|
|
out[len(out)-1] = '}'
|
|
|
|
return out, nil
|
|
}
|