Writer.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /*
  2. * Copyright (c) 2014 by Farsight Security, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package framestream
  17. import (
  18. "bufio"
  19. "encoding/binary"
  20. "io"
  21. "time"
  22. )
  23. type WriterOptions struct {
  24. // The ContentTypes available to be written to the Writer. May be
  25. // left unset for no content negotiation. If the Reader requests a
  26. // disjoint set of content types, NewEncoder() will return
  27. // ErrContentTypeMismatch.
  28. ContentTypes [][]byte
  29. // If Bidirectional is true, the underlying io.Writer must be an
  30. // io.ReadWriter, and the Writer will engage in a bidirectional
  31. // handshake with its peer to establish content type and communicate
  32. // shutdown.
  33. Bidirectional bool
  34. // Timeout gives the timeout for writing both control and data frames,
  35. // and for reading responses to control frames sent. It is only
  36. // effective for underlying Writers satisfying net.Conn.
  37. Timeout time.Duration
  38. }
  39. // A Writer writes data frames to a Frame Streams file or connection.
  40. type Writer struct {
  41. contentType []byte
  42. w *bufio.Writer
  43. r *bufio.Reader
  44. opt WriterOptions
  45. buf []byte
  46. }
  47. // NewWriter returns a Frame Streams Writer using the given io.Writer and options.
  48. func NewWriter(w io.Writer, opt *WriterOptions) (writer *Writer, err error) {
  49. if opt == nil {
  50. opt = &WriterOptions{}
  51. }
  52. w = timeoutWriter(w, opt)
  53. writer = &Writer{
  54. w: bufio.NewWriter(w),
  55. opt: *opt,
  56. }
  57. if len(opt.ContentTypes) > 0 {
  58. writer.contentType = opt.ContentTypes[0]
  59. }
  60. if opt.Bidirectional {
  61. r, ok := w.(io.Reader)
  62. if !ok {
  63. return nil, ErrType
  64. }
  65. writer.r = bufio.NewReader(r)
  66. ready := ControlReady
  67. ready.SetContentTypes(opt.ContentTypes)
  68. if err = ready.EncodeFlush(writer.w); err != nil {
  69. return
  70. }
  71. var accept ControlFrame
  72. if err = accept.DecodeTypeEscape(writer.r, CONTROL_ACCEPT); err != nil {
  73. return
  74. }
  75. if t, ok := accept.ChooseContentType(opt.ContentTypes); ok {
  76. writer.contentType = t
  77. } else {
  78. return nil, ErrContentTypeMismatch
  79. }
  80. }
  81. // Write the start control frame.
  82. start := ControlStart
  83. start.SetContentType(writer.contentType)
  84. err = start.EncodeFlush(writer.w)
  85. if err != nil {
  86. return
  87. }
  88. return
  89. }
  90. // ContentType returns the content type negotiated with Reader.
  91. func (w *Writer) ContentType() []byte {
  92. return w.contentType
  93. }
  94. // Close shuts down the Frame Streams stream by writing a CONTROL_STOP message.
  95. // If the Writer is Bidirectional, Close will wait for an acknowledgement
  96. // (CONTROL_FINISH) from its peer.
  97. func (w *Writer) Close() (err error) {
  98. err = ControlStop.EncodeFlush(w.w)
  99. if err != nil || !w.opt.Bidirectional {
  100. return
  101. }
  102. var finish ControlFrame
  103. return finish.DecodeTypeEscape(w.r, CONTROL_FINISH)
  104. }
  105. // WriteFrame writes the given frame to the underlying io.Writer with Frame Streams
  106. // framing.
  107. func (w *Writer) WriteFrame(frame []byte) (n int, err error) {
  108. err = binary.Write(w.w, binary.BigEndian, uint32(len(frame)))
  109. if err != nil {
  110. return
  111. }
  112. return w.w.Write(frame)
  113. }
  114. // Flush ensures that any buffered data frames are written to the underlying
  115. // io.Writer.
  116. func (w *Writer) Flush() error {
  117. return w.w.Flush()
  118. }