fcgi.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. // Copyright 2011 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. // Package fcgi implements the FastCGI protocol.
  5. //
  6. // See https://fast-cgi.github.io/ for an unofficial mirror of the
  7. // original documentation.
  8. //
  9. // Currently only the responder role is supported.
  10. package fcgi
  11. // This file defines the raw protocol and some utilities used by the child and
  12. // the host.
  13. import (
  14. "bufio"
  15. "bytes"
  16. "encoding/binary"
  17. "errors"
  18. "io"
  19. "sync"
  20. )
  21. // recType is a record type, as defined by
  22. // https://web.archive.org/web/20150420080736/http://www.fastcgi.com/drupal/node/6?q=node/22#S8
  23. type recType uint8
  24. const (
  25. typeBeginRequest recType = 1
  26. typeAbortRequest recType = 2
  27. typeEndRequest recType = 3
  28. typeParams recType = 4
  29. typeStdin recType = 5
  30. typeStdout recType = 6
  31. typeStderr recType = 7
  32. typeData recType = 8
  33. typeGetValues recType = 9
  34. typeGetValuesResult recType = 10
  35. typeUnknownType recType = 11
  36. )
  37. // keep the connection between web-server and responder open after request
  38. const flagKeepConn = 1
  39. const (
  40. maxWrite = 65535 // maximum record body
  41. maxPad = 255
  42. )
  43. const (
  44. roleResponder = iota + 1 // only Responders are implemented.
  45. roleAuthorizer
  46. roleFilter
  47. )
  48. const (
  49. statusRequestComplete = iota
  50. statusCantMultiplex
  51. statusOverloaded
  52. statusUnknownRole
  53. )
  54. type header struct {
  55. Version uint8
  56. Type recType
  57. Id uint16
  58. ContentLength uint16
  59. PaddingLength uint8
  60. Reserved uint8
  61. }
  62. type beginRequest struct {
  63. role uint16
  64. flags uint8
  65. reserved [5]uint8
  66. }
  67. func (br *beginRequest) read(content []byte) error {
  68. if len(content) != 8 {
  69. return errors.New("fcgi: invalid begin request record")
  70. }
  71. br.role = binary.BigEndian.Uint16(content)
  72. br.flags = content[2]
  73. return nil
  74. }
  75. // for padding so we don't have to allocate all the time
  76. // not synchronized because we don't care what the contents are
  77. var pad [maxPad]byte
  78. func (h *header) init(recType recType, reqId uint16, contentLength int) {
  79. h.Version = 1
  80. h.Type = recType
  81. h.Id = reqId
  82. h.ContentLength = uint16(contentLength)
  83. h.PaddingLength = uint8(-contentLength & 7)
  84. }
  85. // conn sends records over rwc
  86. type conn struct {
  87. mutex sync.Mutex
  88. rwc io.ReadWriteCloser
  89. // to avoid allocations
  90. buf bytes.Buffer
  91. h header
  92. }
  93. func newConn(rwc io.ReadWriteCloser) *conn {
  94. return &conn{rwc: rwc}
  95. }
  96. func (c *conn) Close() error {
  97. c.mutex.Lock()
  98. defer c.mutex.Unlock()
  99. return c.rwc.Close()
  100. }
  101. type record struct {
  102. h header
  103. buf [maxWrite + maxPad]byte
  104. }
  105. func (rec *record) read(r io.Reader) (err error) {
  106. if err = binary.Read(r, binary.BigEndian, &rec.h); err != nil {
  107. return err
  108. }
  109. if rec.h.Version != 1 {
  110. return errors.New("fcgi: invalid header version")
  111. }
  112. n := int(rec.h.ContentLength) + int(rec.h.PaddingLength)
  113. if _, err = io.ReadFull(r, rec.buf[:n]); err != nil {
  114. return err
  115. }
  116. return nil
  117. }
  118. func (r *record) content() []byte {
  119. return r.buf[:r.h.ContentLength]
  120. }
  121. // writeRecord writes and sends a single record.
  122. func (c *conn) writeRecord(recType recType, reqId uint16, b []byte) error {
  123. c.mutex.Lock()
  124. defer c.mutex.Unlock()
  125. c.buf.Reset()
  126. c.h.init(recType, reqId, len(b))
  127. if err := binary.Write(&c.buf, binary.BigEndian, c.h); err != nil {
  128. return err
  129. }
  130. if _, err := c.buf.Write(b); err != nil {
  131. return err
  132. }
  133. if _, err := c.buf.Write(pad[:c.h.PaddingLength]); err != nil {
  134. return err
  135. }
  136. _, err := c.rwc.Write(c.buf.Bytes())
  137. return err
  138. }
  139. func (c *conn) writeEndRequest(reqId uint16, appStatus int, protocolStatus uint8) error {
  140. b := make([]byte, 8)
  141. binary.BigEndian.PutUint32(b, uint32(appStatus))
  142. b[4] = protocolStatus
  143. return c.writeRecord(typeEndRequest, reqId, b)
  144. }
  145. func (c *conn) writePairs(recType recType, reqId uint16, pairs map[string]string) error {
  146. w := newWriter(c, recType, reqId)
  147. b := make([]byte, 8)
  148. for k, v := range pairs {
  149. n := encodeSize(b, uint32(len(k)))
  150. n += encodeSize(b[n:], uint32(len(v)))
  151. if _, err := w.Write(b[:n]); err != nil {
  152. return err
  153. }
  154. if _, err := w.WriteString(k); err != nil {
  155. return err
  156. }
  157. if _, err := w.WriteString(v); err != nil {
  158. return err
  159. }
  160. }
  161. w.Close()
  162. return nil
  163. }
  164. func readSize(s []byte) (uint32, int) {
  165. if len(s) == 0 {
  166. return 0, 0
  167. }
  168. size, n := uint32(s[0]), 1
  169. if size&(1<<7) != 0 {
  170. if len(s) < 4 {
  171. return 0, 0
  172. }
  173. n = 4
  174. size = binary.BigEndian.Uint32(s)
  175. size &^= 1 << 31
  176. }
  177. return size, n
  178. }
  179. func readString(s []byte, size uint32) string {
  180. if size > uint32(len(s)) {
  181. return ""
  182. }
  183. return string(s[:size])
  184. }
  185. func encodeSize(b []byte, size uint32) int {
  186. if size > 127 {
  187. size |= 1 << 31
  188. binary.BigEndian.PutUint32(b, size)
  189. return 4
  190. }
  191. b[0] = byte(size)
  192. return 1
  193. }
  194. // bufWriter encapsulates bufio.Writer but also closes the underlying stream when
  195. // Closed.
  196. type bufWriter struct {
  197. closer io.Closer
  198. *bufio.Writer
  199. }
  200. func (w *bufWriter) Close() error {
  201. if err := w.Writer.Flush(); err != nil {
  202. w.closer.Close()
  203. return err
  204. }
  205. return w.closer.Close()
  206. }
  207. func newWriter(c *conn, recType recType, reqId uint16) *bufWriter {
  208. s := &streamWriter{c: c, recType: recType, reqId: reqId}
  209. w := bufio.NewWriterSize(s, maxWrite)
  210. return &bufWriter{s, w}
  211. }
  212. // streamWriter abstracts out the separation of a stream into discrete records.
  213. // It only writes maxWrite bytes at a time.
  214. type streamWriter struct {
  215. c *conn
  216. recType recType
  217. reqId uint16
  218. }
  219. func (w *streamWriter) Write(p []byte) (int, error) {
  220. nn := 0
  221. for len(p) > 0 {
  222. n := len(p)
  223. if n > maxWrite {
  224. n = maxWrite
  225. }
  226. if err := w.c.writeRecord(w.recType, w.reqId, p[:n]); err != nil {
  227. return nn, err
  228. }
  229. nn += n
  230. p = p[n:]
  231. }
  232. return nn, nil
  233. }
  234. func (w *streamWriter) Close() error {
  235. // send empty record to close the stream
  236. return w.c.writeRecord(w.recType, w.reqId, nil)
  237. }