framer.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. /*
  2. Copyright 2024 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 cbor
  14. import (
  15. "io"
  16. "k8s.io/apimachinery/pkg/runtime"
  17. "github.com/fxamacker/cbor/v2"
  18. )
  19. // NewFramer returns a runtime.Framer based on RFC 8742 CBOR Sequences. Each frame contains exactly
  20. // one encoded CBOR data item.
  21. func NewFramer() runtime.Framer {
  22. return framer{}
  23. }
  24. var _ runtime.Framer = framer{}
  25. type framer struct{}
  26. func (framer) NewFrameReader(rc io.ReadCloser) io.ReadCloser {
  27. return &frameReader{
  28. decoder: cbor.NewDecoder(rc),
  29. closer: rc,
  30. }
  31. }
  32. func (framer) NewFrameWriter(w io.Writer) io.Writer {
  33. // Each data item in a CBOR sequence is self-delimiting (like JSON objects).
  34. return w
  35. }
  36. type frameReader struct {
  37. decoder *cbor.Decoder
  38. closer io.Closer
  39. overflow []byte
  40. }
  41. func (fr *frameReader) Read(dst []byte) (int, error) {
  42. if len(fr.overflow) > 0 {
  43. // We read a frame that was too large for the destination slice in a previous call
  44. // to Read and have bytes left over.
  45. n := copy(dst, fr.overflow)
  46. if n < len(fr.overflow) {
  47. fr.overflow = fr.overflow[n:]
  48. return n, io.ErrShortBuffer
  49. }
  50. fr.overflow = nil
  51. return n, nil
  52. }
  53. // The Reader contract allows implementations to use all of dst[0:len(dst)] as scratch
  54. // space, even if n < len(dst), but it does not allow implementations to use
  55. // dst[len(dst):cap(dst)]. Slicing it up-front allows us to append to it without worrying
  56. // about overwriting dst[len(dst):cap(dst)].
  57. m := cbor.RawMessage(dst[0:0:len(dst)])
  58. if err := fr.decoder.Decode(&m); err != nil {
  59. return 0, err
  60. }
  61. if len(m) > len(dst) {
  62. // The frame was too big, m has a newly-allocated underlying array to accommodate
  63. // it.
  64. fr.overflow = m[len(dst):]
  65. return copy(dst, m), io.ErrShortBuffer
  66. }
  67. return len(m), nil
  68. }
  69. func (fr *frameReader) Close() error {
  70. return fr.closer.Close()
  71. }