...
Run Format

Source file src/net/http/fcgi/child.go

     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	
     5	package fcgi
     6	
     7	// This file implements FastCGI from the perspective of a child process.
     8	
     9	import (
    10		"errors"
    11		"fmt"
    12		"io"
    13		"io/ioutil"
    14		"net"
    15		"net/http"
    16		"net/http/cgi"
    17		"os"
    18		"strings"
    19		"sync"
    20		"time"
    21	)
    22	
    23	// request holds the state for an in-progress request. As soon as it's complete,
    24	// it's converted to an http.Request.
    25	type request struct {
    26		pw        *io.PipeWriter
    27		reqId     uint16
    28		params    map[string]string
    29		buf       [1024]byte
    30		rawParams []byte
    31		keepConn  bool
    32	}
    33	
    34	func newRequest(reqId uint16, flags uint8) *request {
    35		r := &request{
    36			reqId:    reqId,
    37			params:   map[string]string{},
    38			keepConn: flags&flagKeepConn != 0,
    39		}
    40		r.rawParams = r.buf[:0]
    41		return r
    42	}
    43	
    44	// parseParams reads an encoded []byte into Params.
    45	func (r *request) parseParams() {
    46		text := r.rawParams
    47		r.rawParams = nil
    48		for len(text) > 0 {
    49			keyLen, n := readSize(text)
    50			if n == 0 {
    51				return
    52			}
    53			text = text[n:]
    54			valLen, n := readSize(text)
    55			if n == 0 {
    56				return
    57			}
    58			text = text[n:]
    59			if int(keyLen)+int(valLen) > len(text) {
    60				return
    61			}
    62			key := readString(text, keyLen)
    63			text = text[keyLen:]
    64			val := readString(text, valLen)
    65			text = text[valLen:]
    66			r.params[key] = val
    67		}
    68	}
    69	
    70	// response implements http.ResponseWriter.
    71	type response struct {
    72		req         *request
    73		header      http.Header
    74		w           *bufWriter
    75		wroteHeader bool
    76	}
    77	
    78	func newResponse(c *child, req *request) *response {
    79		return &response{
    80			req:    req,
    81			header: http.Header{},
    82			w:      newWriter(c.conn, typeStdout, req.reqId),
    83		}
    84	}
    85	
    86	func (r *response) Header() http.Header {
    87		return r.header
    88	}
    89	
    90	func (r *response) Write(data []byte) (int, error) {
    91		if !r.wroteHeader {
    92			r.WriteHeader(http.StatusOK)
    93		}
    94		return r.w.Write(data)
    95	}
    96	
    97	func (r *response) WriteHeader(code int) {
    98		if r.wroteHeader {
    99			return
   100		}
   101		r.wroteHeader = true
   102		if code == http.StatusNotModified {
   103			// Must not have body.
   104			r.header.Del("Content-Type")
   105			r.header.Del("Content-Length")
   106			r.header.Del("Transfer-Encoding")
   107		} else if r.header.Get("Content-Type") == "" {
   108			r.header.Set("Content-Type", "text/html; charset=utf-8")
   109		}
   110	
   111		if r.header.Get("Date") == "" {
   112			r.header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
   113		}
   114	
   115		fmt.Fprintf(r.w, "Status: %d %s\r\n", code, http.StatusText(code))
   116		r.header.Write(r.w)
   117		r.w.WriteString("\r\n")
   118	}
   119	
   120	func (r *response) Flush() {
   121		if !r.wroteHeader {
   122			r.WriteHeader(http.StatusOK)
   123		}
   124		r.w.Flush()
   125	}
   126	
   127	func (r *response) Close() error {
   128		r.Flush()
   129		return r.w.Close()
   130	}
   131	
   132	type child struct {
   133		conn    *conn
   134		handler http.Handler
   135	
   136		mu       sync.Mutex          // protects requests:
   137		requests map[uint16]*request // keyed by request ID
   138	}
   139	
   140	func newChild(rwc io.ReadWriteCloser, handler http.Handler) *child {
   141		return &child{
   142			conn:     newConn(rwc),
   143			handler:  handler,
   144			requests: make(map[uint16]*request),
   145		}
   146	}
   147	
   148	func (c *child) serve() {
   149		defer c.conn.Close()
   150		defer c.cleanUp()
   151		var rec record
   152		for {
   153			if err := rec.read(c.conn.rwc); err != nil {
   154				return
   155			}
   156			if err := c.handleRecord(&rec); err != nil {
   157				return
   158			}
   159		}
   160	}
   161	
   162	var errCloseConn = errors.New("fcgi: connection should be closed")
   163	
   164	var emptyBody = ioutil.NopCloser(strings.NewReader(""))
   165	
   166	// ErrRequestAborted is returned by Read when a handler attempts to read the
   167	// body of a request that has been aborted by the web server.
   168	var ErrRequestAborted = errors.New("fcgi: request aborted by web server")
   169	
   170	// ErrConnClosed is returned by Read when a handler attempts to read the body of
   171	// a request after the connection to the web server has been closed.
   172	var ErrConnClosed = errors.New("fcgi: connection to web server closed")
   173	
   174	func (c *child) handleRecord(rec *record) error {
   175		c.mu.Lock()
   176		req, ok := c.requests[rec.h.Id]
   177		c.mu.Unlock()
   178		if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues {
   179			// The spec says to ignore unknown request IDs.
   180			return nil
   181		}
   182	
   183		switch rec.h.Type {
   184		case typeBeginRequest:
   185			if req != nil {
   186				// The server is trying to begin a request with the same ID
   187				// as an in-progress request. This is an error.
   188				return errors.New("fcgi: received ID that is already in-flight")
   189			}
   190	
   191			var br beginRequest
   192			if err := br.read(rec.content()); err != nil {
   193				return err
   194			}
   195			if br.role != roleResponder {
   196				c.conn.writeEndRequest(rec.h.Id, 0, statusUnknownRole)
   197				return nil
   198			}
   199			req = newRequest(rec.h.Id, br.flags)
   200			c.mu.Lock()
   201			c.requests[rec.h.Id] = req
   202			c.mu.Unlock()
   203			return nil
   204		case typeParams:
   205			// NOTE(eds): Technically a key-value pair can straddle the boundary
   206			// between two packets. We buffer until we've received all parameters.
   207			if len(rec.content()) > 0 {
   208				req.rawParams = append(req.rawParams, rec.content()...)
   209				return nil
   210			}
   211			req.parseParams()
   212			return nil
   213		case typeStdin:
   214			content := rec.content()
   215			if req.pw == nil {
   216				var body io.ReadCloser
   217				if len(content) > 0 {
   218					// body could be an io.LimitReader, but it shouldn't matter
   219					// as long as both sides are behaving.
   220					body, req.pw = io.Pipe()
   221				} else {
   222					body = emptyBody
   223				}
   224				go c.serveRequest(req, body)
   225			}
   226			if len(content) > 0 {
   227				// TODO(eds): This blocks until the handler reads from the pipe.
   228				// If the handler takes a long time, it might be a problem.
   229				req.pw.Write(content)
   230			} else if req.pw != nil {
   231				req.pw.Close()
   232			}
   233			return nil
   234		case typeGetValues:
   235			values := map[string]string{"FCGI_MPXS_CONNS": "1"}
   236			c.conn.writePairs(typeGetValuesResult, 0, values)
   237			return nil
   238		case typeData:
   239			// If the filter role is implemented, read the data stream here.
   240			return nil
   241		case typeAbortRequest:
   242			c.mu.Lock()
   243			delete(c.requests, rec.h.Id)
   244			c.mu.Unlock()
   245			c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete)
   246			if req.pw != nil {
   247				req.pw.CloseWithError(ErrRequestAborted)
   248			}
   249			if !req.keepConn {
   250				// connection will close upon return
   251				return errCloseConn
   252			}
   253			return nil
   254		default:
   255			b := make([]byte, 8)
   256			b[0] = byte(rec.h.Type)
   257			c.conn.writeRecord(typeUnknownType, 0, b)
   258			return nil
   259		}
   260	}
   261	
   262	func (c *child) serveRequest(req *request, body io.ReadCloser) {
   263		r := newResponse(c, req)
   264		httpReq, err := cgi.RequestFromMap(req.params)
   265		if err != nil {
   266			// there was an error reading the request
   267			r.WriteHeader(http.StatusInternalServerError)
   268			c.conn.writeRecord(typeStderr, req.reqId, []byte(err.Error()))
   269		} else {
   270			httpReq.Body = body
   271			c.handler.ServeHTTP(r, httpReq)
   272		}
   273		r.Close()
   274		c.mu.Lock()
   275		delete(c.requests, req.reqId)
   276		c.mu.Unlock()
   277		c.conn.writeEndRequest(req.reqId, 0, statusRequestComplete)
   278	
   279		// Consume the entire body, so the host isn't still writing to
   280		// us when we close the socket below in the !keepConn case,
   281		// otherwise we'd send a RST. (golang.org/issue/4183)
   282		// TODO(bradfitz): also bound this copy in time. Or send
   283		// some sort of abort request to the host, so the host
   284		// can properly cut off the client sending all the data.
   285		// For now just bound it a little and
   286		io.CopyN(ioutil.Discard, body, 100<<20)
   287		body.Close()
   288	
   289		if !req.keepConn {
   290			c.conn.Close()
   291		}
   292	}
   293	
   294	func (c *child) cleanUp() {
   295		c.mu.Lock()
   296		defer c.mu.Unlock()
   297		for _, req := range c.requests {
   298			if req.pw != nil {
   299				// race with call to Close in c.serveRequest doesn't matter because
   300				// Pipe(Reader|Writer).Close are idempotent
   301				req.pw.CloseWithError(ErrConnClosed)
   302			}
   303		}
   304	}
   305	
   306	// Serve accepts incoming FastCGI connections on the listener l, creating a new
   307	// goroutine for each. The goroutine reads requests and then calls handler
   308	// to reply to them.
   309	// If l is nil, Serve accepts connections from os.Stdin.
   310	// If handler is nil, http.DefaultServeMux is used.
   311	func Serve(l net.Listener, handler http.Handler) error {
   312		if l == nil {
   313			var err error
   314			l, err = net.FileListener(os.Stdin)
   315			if err != nil {
   316				return err
   317			}
   318			defer l.Close()
   319		}
   320		if handler == nil {
   321			handler = http.DefaultServeMux
   322		}
   323		for {
   324			rw, err := l.Accept()
   325			if err != nil {
   326				return err
   327			}
   328			c := newChild(rw, handler)
   329			go c.serve()
   330		}
   331	}
   332	

View as plain text