json.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package json
  14. import (
  15. "encoding/json"
  16. "io"
  17. "strconv"
  18. "unsafe"
  19. jsoniter "github.com/json-iterator/go"
  20. "github.com/modern-go/reflect2"
  21. "sigs.k8s.io/yaml"
  22. "k8s.io/apimachinery/pkg/runtime"
  23. "k8s.io/apimachinery/pkg/runtime/schema"
  24. "k8s.io/apimachinery/pkg/runtime/serializer/recognizer"
  25. "k8s.io/apimachinery/pkg/util/framer"
  26. utilyaml "k8s.io/apimachinery/pkg/util/yaml"
  27. "k8s.io/klog/v2"
  28. )
  29. // NewSerializer creates a JSON serializer that handles encoding versioned objects into the proper JSON form. If typer
  30. // is not nil, the object has the group, version, and kind fields set.
  31. // Deprecated: use NewSerializerWithOptions instead.
  32. func NewSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.ObjectTyper, pretty bool) *Serializer {
  33. return NewSerializerWithOptions(meta, creater, typer, SerializerOptions{false, pretty, false})
  34. }
  35. // NewYAMLSerializer creates a YAML serializer that handles encoding versioned objects into the proper YAML form. If typer
  36. // is not nil, the object has the group, version, and kind fields set. This serializer supports only the subset of YAML that
  37. // matches JSON, and will error if constructs are used that do not serialize to JSON.
  38. // Deprecated: use NewSerializerWithOptions instead.
  39. func NewYAMLSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.ObjectTyper) *Serializer {
  40. return NewSerializerWithOptions(meta, creater, typer, SerializerOptions{true, false, false})
  41. }
  42. // NewSerializerWithOptions creates a JSON/YAML serializer that handles encoding versioned objects into the proper JSON/YAML
  43. // form. If typer is not nil, the object has the group, version, and kind fields set. Options are copied into the Serializer
  44. // and are immutable.
  45. func NewSerializerWithOptions(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.ObjectTyper, options SerializerOptions) *Serializer {
  46. return &Serializer{
  47. meta: meta,
  48. creater: creater,
  49. typer: typer,
  50. options: options,
  51. identifier: identifier(options),
  52. }
  53. }
  54. // identifier computes Identifier of Encoder based on the given options.
  55. func identifier(options SerializerOptions) runtime.Identifier {
  56. result := map[string]string{
  57. "name": "json",
  58. "yaml": strconv.FormatBool(options.Yaml),
  59. "pretty": strconv.FormatBool(options.Pretty),
  60. }
  61. identifier, err := json.Marshal(result)
  62. if err != nil {
  63. klog.Fatalf("Failed marshaling identifier for json Serializer: %v", err)
  64. }
  65. return runtime.Identifier(identifier)
  66. }
  67. // SerializerOptions holds the options which are used to configure a JSON/YAML serializer.
  68. // example:
  69. // (1) To configure a JSON serializer, set `Yaml` to `false`.
  70. // (2) To configure a YAML serializer, set `Yaml` to `true`.
  71. // (3) To configure a strict serializer that can return strictDecodingError, set `Strict` to `true`.
  72. type SerializerOptions struct {
  73. // Yaml: configures the Serializer to work with JSON(false) or YAML(true).
  74. // When `Yaml` is enabled, this serializer only supports the subset of YAML that
  75. // matches JSON, and will error if constructs are used that do not serialize to JSON.
  76. Yaml bool
  77. // Pretty: configures a JSON enabled Serializer(`Yaml: false`) to produce human-readable output.
  78. // This option is silently ignored when `Yaml` is `true`.
  79. Pretty bool
  80. // Strict: configures the Serializer to return strictDecodingError's when duplicate fields are present decoding JSON or YAML.
  81. // Note that enabling this option is not as performant as the non-strict variant, and should not be used in fast paths.
  82. Strict bool
  83. }
  84. // Serializer handles encoding versioned objects into the proper JSON form
  85. type Serializer struct {
  86. meta MetaFactory
  87. options SerializerOptions
  88. creater runtime.ObjectCreater
  89. typer runtime.ObjectTyper
  90. identifier runtime.Identifier
  91. }
  92. // Serializer implements Serializer
  93. var _ runtime.Serializer = &Serializer{}
  94. var _ recognizer.RecognizingDecoder = &Serializer{}
  95. type customNumberExtension struct {
  96. jsoniter.DummyExtension
  97. }
  98. func (cne *customNumberExtension) CreateDecoder(typ reflect2.Type) jsoniter.ValDecoder {
  99. if typ.String() == "interface {}" {
  100. return customNumberDecoder{}
  101. }
  102. return nil
  103. }
  104. type customNumberDecoder struct {
  105. }
  106. func (customNumberDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
  107. switch iter.WhatIsNext() {
  108. case jsoniter.NumberValue:
  109. var number jsoniter.Number
  110. iter.ReadVal(&number)
  111. i64, err := strconv.ParseInt(string(number), 10, 64)
  112. if err == nil {
  113. *(*interface{})(ptr) = i64
  114. return
  115. }
  116. f64, err := strconv.ParseFloat(string(number), 64)
  117. if err == nil {
  118. *(*interface{})(ptr) = f64
  119. return
  120. }
  121. iter.ReportError("DecodeNumber", err.Error())
  122. default:
  123. *(*interface{})(ptr) = iter.Read()
  124. }
  125. }
  126. // CaseSensitiveJSONIterator returns a jsoniterator API that's configured to be
  127. // case-sensitive when unmarshalling, and otherwise compatible with
  128. // the encoding/json standard library.
  129. func CaseSensitiveJSONIterator() jsoniter.API {
  130. config := jsoniter.Config{
  131. EscapeHTML: true,
  132. SortMapKeys: true,
  133. ValidateJsonRawMessage: true,
  134. CaseSensitive: true,
  135. }.Froze()
  136. // Force jsoniter to decode number to interface{} via int64/float64, if possible.
  137. config.RegisterExtension(&customNumberExtension{})
  138. return config
  139. }
  140. // StrictCaseSensitiveJSONIterator returns a jsoniterator API that's configured to be
  141. // case-sensitive, but also disallows unknown fields when unmarshalling. It is compatible with
  142. // the encoding/json standard library.
  143. func StrictCaseSensitiveJSONIterator() jsoniter.API {
  144. config := jsoniter.Config{
  145. EscapeHTML: true,
  146. SortMapKeys: true,
  147. ValidateJsonRawMessage: true,
  148. CaseSensitive: true,
  149. DisallowUnknownFields: true,
  150. }.Froze()
  151. // Force jsoniter to decode number to interface{} via int64/float64, if possible.
  152. config.RegisterExtension(&customNumberExtension{})
  153. return config
  154. }
  155. // Private copies of jsoniter to try to shield against possible mutations
  156. // from outside. Still does not protect from package level jsoniter.Register*() functions - someone calling them
  157. // in some other library will mess with every usage of the jsoniter library in the whole program.
  158. // See https://github.com/json-iterator/go/issues/265
  159. var caseSensitiveJSONIterator = CaseSensitiveJSONIterator()
  160. var strictCaseSensitiveJSONIterator = StrictCaseSensitiveJSONIterator()
  161. // gvkWithDefaults returns group kind and version defaulting from provided default
  162. func gvkWithDefaults(actual, defaultGVK schema.GroupVersionKind) schema.GroupVersionKind {
  163. if len(actual.Kind) == 0 {
  164. actual.Kind = defaultGVK.Kind
  165. }
  166. if len(actual.Version) == 0 && len(actual.Group) == 0 {
  167. actual.Group = defaultGVK.Group
  168. actual.Version = defaultGVK.Version
  169. }
  170. if len(actual.Version) == 0 && actual.Group == defaultGVK.Group {
  171. actual.Version = defaultGVK.Version
  172. }
  173. return actual
  174. }
  175. // Decode attempts to convert the provided data into YAML or JSON, extract the stored schema kind, apply the provided default gvk, and then
  176. // load that data into an object matching the desired schema kind or the provided into.
  177. // If into is *runtime.Unknown, the raw data will be extracted and no decoding will be performed.
  178. // If into is not registered with the typer, then the object will be straight decoded using normal JSON/YAML unmarshalling.
  179. // If into is provided and the original data is not fully qualified with kind/version/group, the type of the into will be used to alter the returned gvk.
  180. // If into is nil or data's gvk different from into's gvk, it will generate a new Object with ObjectCreater.New(gvk)
  181. // On success or most errors, the method will return the calculated schema kind.
  182. // The gvk calculate priority will be originalData > default gvk > into
  183. func (s *Serializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
  184. data := originalData
  185. if s.options.Yaml {
  186. altered, err := yaml.YAMLToJSON(data)
  187. if err != nil {
  188. return nil, nil, err
  189. }
  190. data = altered
  191. }
  192. actual, err := s.meta.Interpret(data)
  193. if err != nil {
  194. return nil, nil, err
  195. }
  196. if gvk != nil {
  197. *actual = gvkWithDefaults(*actual, *gvk)
  198. }
  199. if unk, ok := into.(*runtime.Unknown); ok && unk != nil {
  200. unk.Raw = originalData
  201. unk.ContentType = runtime.ContentTypeJSON
  202. unk.GetObjectKind().SetGroupVersionKind(*actual)
  203. return unk, actual, nil
  204. }
  205. if into != nil {
  206. _, isUnstructured := into.(runtime.Unstructured)
  207. types, _, err := s.typer.ObjectKinds(into)
  208. switch {
  209. case runtime.IsNotRegisteredError(err), isUnstructured:
  210. if err := caseSensitiveJSONIterator.Unmarshal(data, into); err != nil {
  211. return nil, actual, err
  212. }
  213. return into, actual, nil
  214. case err != nil:
  215. return nil, actual, err
  216. default:
  217. *actual = gvkWithDefaults(*actual, types[0])
  218. }
  219. }
  220. if len(actual.Kind) == 0 {
  221. return nil, actual, runtime.NewMissingKindErr(string(originalData))
  222. }
  223. if len(actual.Version) == 0 {
  224. return nil, actual, runtime.NewMissingVersionErr(string(originalData))
  225. }
  226. // use the target if necessary
  227. obj, err := runtime.UseOrCreateObject(s.typer, s.creater, *actual, into)
  228. if err != nil {
  229. return nil, actual, err
  230. }
  231. if err := caseSensitiveJSONIterator.Unmarshal(data, obj); err != nil {
  232. return nil, actual, err
  233. }
  234. // If the deserializer is non-strict, return successfully here.
  235. if !s.options.Strict {
  236. return obj, actual, nil
  237. }
  238. // In strict mode pass the data trough the YAMLToJSONStrict converter.
  239. // This is done to catch duplicate fields regardless of encoding (JSON or YAML). For JSON data,
  240. // the output would equal the input, unless there is a parsing error such as duplicate fields.
  241. // As we know this was successful in the non-strict case, the only error that may be returned here
  242. // is because of the newly-added strictness. hence we know we can return the typed strictDecoderError
  243. // the actual error is that the object contains duplicate fields.
  244. altered, err := yaml.YAMLToJSONStrict(originalData)
  245. if err != nil {
  246. return nil, actual, runtime.NewStrictDecodingError(err.Error(), string(originalData))
  247. }
  248. // As performance is not an issue for now for the strict deserializer (one has regardless to do
  249. // the unmarshal twice), we take the sanitized, altered data that is guaranteed to have no duplicated
  250. // fields, and unmarshal this into a copy of the already-populated obj. Any error that occurs here is
  251. // due to that a matching field doesn't exist in the object. hence we can return a typed strictDecoderError,
  252. // the actual error is that the object contains unknown field.
  253. strictObj := obj.DeepCopyObject()
  254. if err := strictCaseSensitiveJSONIterator.Unmarshal(altered, strictObj); err != nil {
  255. return nil, actual, runtime.NewStrictDecodingError(err.Error(), string(originalData))
  256. }
  257. // Always return the same object as the non-strict serializer to avoid any deviations.
  258. return obj, actual, nil
  259. }
  260. // Encode serializes the provided object to the given writer.
  261. func (s *Serializer) Encode(obj runtime.Object, w io.Writer) error {
  262. if co, ok := obj.(runtime.CacheableObject); ok {
  263. return co.CacheEncode(s.Identifier(), s.doEncode, w)
  264. }
  265. return s.doEncode(obj, w)
  266. }
  267. func (s *Serializer) doEncode(obj runtime.Object, w io.Writer) error {
  268. if s.options.Yaml {
  269. json, err := caseSensitiveJSONIterator.Marshal(obj)
  270. if err != nil {
  271. return err
  272. }
  273. data, err := yaml.JSONToYAML(json)
  274. if err != nil {
  275. return err
  276. }
  277. _, err = w.Write(data)
  278. return err
  279. }
  280. if s.options.Pretty {
  281. data, err := caseSensitiveJSONIterator.MarshalIndent(obj, "", " ")
  282. if err != nil {
  283. return err
  284. }
  285. _, err = w.Write(data)
  286. return err
  287. }
  288. encoder := json.NewEncoder(w)
  289. return encoder.Encode(obj)
  290. }
  291. // Identifier implements runtime.Encoder interface.
  292. func (s *Serializer) Identifier() runtime.Identifier {
  293. return s.identifier
  294. }
  295. // RecognizesData implements the RecognizingDecoder interface.
  296. func (s *Serializer) RecognizesData(data []byte) (ok, unknown bool, err error) {
  297. if s.options.Yaml {
  298. // we could potentially look for '---'
  299. return false, true, nil
  300. }
  301. return utilyaml.IsJSONBuffer(data), false, nil
  302. }
  303. // Framer is the default JSON framing behavior, with newlines delimiting individual objects.
  304. var Framer = jsonFramer{}
  305. type jsonFramer struct{}
  306. // NewFrameWriter implements stream framing for this serializer
  307. func (jsonFramer) NewFrameWriter(w io.Writer) io.Writer {
  308. // we can write JSON objects directly to the writer, because they are self-framing
  309. return w
  310. }
  311. // NewFrameReader implements stream framing for this serializer
  312. func (jsonFramer) NewFrameReader(r io.ReadCloser) io.ReadCloser {
  313. // we need to extract the JSON chunks of data to pass to Decode()
  314. return framer.NewJSONFramedReader(r)
  315. }
  316. // YAMLFramer is the default JSON framing behavior, with newlines delimiting individual objects.
  317. var YAMLFramer = yamlFramer{}
  318. type yamlFramer struct{}
  319. // NewFrameWriter implements stream framing for this serializer
  320. func (yamlFramer) NewFrameWriter(w io.Writer) io.Writer {
  321. return yamlFrameWriter{w}
  322. }
  323. // NewFrameReader implements stream framing for this serializer
  324. func (yamlFramer) NewFrameReader(r io.ReadCloser) io.ReadCloser {
  325. // extract the YAML document chunks directly
  326. return utilyaml.NewDocumentDecoder(r)
  327. }
  328. type yamlFrameWriter struct {
  329. w io.Writer
  330. }
  331. // Write separates each document with the YAML document separator (`---` followed by line
  332. // break). Writers must write well formed YAML documents (include a final line break).
  333. func (w yamlFrameWriter) Write(data []byte) (n int, err error) {
  334. if _, err := w.w.Write([]byte("---\n")); err != nil {
  335. return 0, err
  336. }
  337. return w.w.Write(data)
  338. }