write.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // Copyright 2014 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // See https://code.google.com/p/go/source/browse/CONTRIBUTORS
  5. // Licensed under the same terms as Go itself:
  6. // https://code.google.com/p/go/source/browse/LICENSE
  7. package http2
  8. import (
  9. "bytes"
  10. "time"
  11. "github.com/bradfitz/http2/hpack"
  12. )
  13. // writeContext is the interface needed by the various frame writing
  14. // functions below. All the functions below are scheduled via the
  15. // frame writing scheduler (see writeScheduler in writesched.go).
  16. //
  17. // This interface is implemented by *serverConn.
  18. // TODO: use it from the client code, once it exists.
  19. type writeContext interface {
  20. Framer() *Framer
  21. Flush() error
  22. CloseConn() error
  23. // HeaderEncoder returns an HPACK encoder that writes to the
  24. // returned buffer.
  25. HeaderEncoder() (*hpack.Encoder, *bytes.Buffer)
  26. }
  27. func flushFrameWriter(ctx writeContext, _ interface{}) error {
  28. return ctx.Flush()
  29. }
  30. func writeSettings(ctx writeContext, v interface{}) error {
  31. settings := v.([]Setting)
  32. return ctx.Framer().WriteSettings(settings...)
  33. }
  34. type goAwayParams struct {
  35. maxStreamID uint32
  36. code ErrCode
  37. }
  38. func writeGoAwayFrame(ctx writeContext, v interface{}) error {
  39. p := v.(*goAwayParams)
  40. err := ctx.Framer().WriteGoAway(p.maxStreamID, p.code, nil)
  41. if p.code != 0 {
  42. ctx.Flush() // ignore error: we're hanging up on them anyway
  43. time.Sleep(50 * time.Millisecond)
  44. ctx.CloseConn()
  45. }
  46. return err
  47. }
  48. type dataWriteParams struct {
  49. streamID uint32
  50. p []byte
  51. end bool
  52. }
  53. func writeRSTStreamFrame(ctx writeContext, v interface{}) error {
  54. se := v.(*StreamError)
  55. return ctx.Framer().WriteRSTStream(se.StreamID, se.Code)
  56. }
  57. func writePingAck(ctx writeContext, v interface{}) error {
  58. pf := v.(*PingFrame) // contains the data we need to write back
  59. return ctx.Framer().WritePing(true, pf.Data)
  60. }
  61. func writeSettingsAck(ctx writeContext, _ interface{}) error {
  62. return ctx.Framer().WriteSettingsAck()
  63. }
  64. func writeHeadersFrame(ctx writeContext, v interface{}) error {
  65. req := v.(headerWriteReq)
  66. enc, buf := ctx.HeaderEncoder()
  67. buf.Reset()
  68. enc.WriteField(hpack.HeaderField{Name: ":status", Value: httpCodeString(req.httpResCode)})
  69. for k, vv := range req.h {
  70. k = lowerHeader(k)
  71. for _, v := range vv {
  72. // TODO: more of "8.1.2.2 Connection-Specific Header Fields"
  73. if k == "transfer-encoding" && v != "trailers" {
  74. continue
  75. }
  76. enc.WriteField(hpack.HeaderField{Name: k, Value: v})
  77. }
  78. }
  79. if req.contentType != "" {
  80. enc.WriteField(hpack.HeaderField{Name: "content-type", Value: req.contentType})
  81. }
  82. if req.contentLength != "" {
  83. enc.WriteField(hpack.HeaderField{Name: "content-length", Value: req.contentLength})
  84. }
  85. headerBlock := buf.Bytes()
  86. if len(headerBlock) == 0 {
  87. panic("unexpected empty hpack")
  88. }
  89. // For now we're lazy and just pick the minimum MAX_FRAME_SIZE
  90. // that all peers must support (16KB). Later we could care
  91. // more and send larger frames if the peer advertised it, but
  92. // there's little point. Most headers are small anyway (so we
  93. // generally won't have CONTINUATION frames), and extra frames
  94. // only waste 9 bytes anyway.
  95. const maxFrameSize = 16384
  96. first := true
  97. for len(headerBlock) > 0 {
  98. frag := headerBlock
  99. if len(frag) > maxFrameSize {
  100. frag = frag[:maxFrameSize]
  101. }
  102. headerBlock = headerBlock[len(frag):]
  103. endHeaders := len(headerBlock) == 0
  104. var err error
  105. if first {
  106. first = false
  107. err = ctx.Framer().WriteHeaders(HeadersFrameParam{
  108. StreamID: req.stream.id,
  109. BlockFragment: frag,
  110. EndStream: req.endStream,
  111. EndHeaders: endHeaders,
  112. })
  113. } else {
  114. err = ctx.Framer().WriteContinuation(req.stream.id, endHeaders, frag)
  115. }
  116. if err != nil {
  117. return err
  118. }
  119. }
  120. return nil
  121. }
  122. func write100ContinueHeadersFrame(ctx writeContext, v interface{}) error {
  123. st := v.(*stream)
  124. enc, buf := ctx.HeaderEncoder()
  125. buf.Reset()
  126. enc.WriteField(hpack.HeaderField{Name: ":status", Value: "100"})
  127. return ctx.Framer().WriteHeaders(HeadersFrameParam{
  128. StreamID: st.id,
  129. BlockFragment: buf.Bytes(),
  130. EndStream: false,
  131. EndHeaders: true,
  132. })
  133. }
  134. func writeDataFrame(ctx writeContext, v interface{}) error {
  135. req := v.(*dataWriteParams)
  136. return ctx.Framer().WriteData(req.streamID, req.end, req.p)
  137. }
  138. type windowUpdateReq struct {
  139. streamID uint32
  140. n uint32
  141. }
  142. func writeWindowUpdate(ctx writeContext, v interface{}) error {
  143. wu := v.(windowUpdateReq)
  144. fr := ctx.Framer()
  145. if err := fr.WriteWindowUpdate(0, wu.n); err != nil {
  146. return err
  147. }
  148. if err := fr.WriteWindowUpdate(wu.streamID, wu.n); err != nil {
  149. return err
  150. }
  151. return nil
  152. }