src/pkg/net/http/fcgi/child.go - The Go Programming Language

Golang

Source file src/pkg/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		"net"
    14		"net/http"
    15		"net/http/cgi"
    16		"os"
    17		"time"
    18	)
    19	
    20	// request holds the state for an in-progress request. As soon as it's complete,
    21	// it's converted to an http.Request.
    22	type request struct {
    23		pw        *io.PipeWriter
    24		reqId     uint16
    25		params    map[string]string
    26		buf       [1024]byte
    27		rawParams []byte
    28		keepConn  bool
    29	}
    30	
    31	func newRequest(reqId uint16, flags uint8) *request {
    32		r := &request{
    33			reqId:    reqId,
    34			params:   map[string]string{},
    35			keepConn: flags&flagKeepConn != 0,
    36		}
    37		r.rawParams = r.buf[:0]
    38		return r
    39	}
    40	
    41	// parseParams reads an encoded []byte into Params.
    42	func (r *request) parseParams() {
    43		text := r.rawParams
    44		r.rawParams = nil
    45		for len(text) > 0 {
    46			keyLen, n := readSize(text)
    47			if n == 0 {
    48				return
    49			}
    50			text = text[n:]
    51			valLen, n := readSize(text)
    52			if n == 0 {
    53				return
    54			}
    55			text = text[n:]
    56			key := readString(text, keyLen)
    57			text = text[keyLen:]
    58			val := readString(text, valLen)
    59			text = text[valLen:]
    60			r.params[key] = val
    61		}
    62	}
    63	
    64	// response implements http.ResponseWriter.
    65	type response struct {
    66		req         *request
    67		header      http.Header
    68		w           *bufWriter
    69		wroteHeader bool
    70	}
    71	
    72	func newResponse(c *child, req *request) *response {
    73		return &response{
    74			req:    req,
    75			header: http.Header{},
    76			w:      newWriter(c.conn, typeStdout, req.reqId),
    77		}
    78	}
    79	
    80	func (r *response) Header() http.Header {
    81		return r.header
    82	}
    83	
    84	func (r *response) Write(data []byte) (int, error) {
    85		if !r.wroteHeader {
    86			r.WriteHeader(http.StatusOK)
    87		}
    88		return r.w.Write(data)
    89	}
    90	
    91	func (r *response) WriteHeader(code int) {
    92		if r.wroteHeader {
    93			return
    94		}
    95		r.wroteHeader = true
    96		if code == http.StatusNotModified {
    97			// Must not have body.
    98			r.header.Del("Content-Type")
    99			r.header.Del("Content-Length")
   100			r.header.Del("Transfer-Encoding")
   101		} else if r.header.Get("Content-Type") == "" {
   102			r.header.Set("Content-Type", "text/html; charset=utf-8")
   103		}
   104	
   105		if r.header.Get("Date") == "" {
   106			r.header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
   107		}
   108	
   109		fmt.Fprintf(r.w, "Status: %d %s\r\n", code, http.StatusText(code))
   110		r.header.Write(r.w)
   111		r.w.WriteString("\r\n")
   112	}
   113	
   114	func (r *response) Flush() {
   115		if !r.wroteHeader {
   116			r.WriteHeader(http.StatusOK)
   117		}
   118		r.w.Flush()
   119	}
   120	
   121	func (r *response) Close() error {
   122		r.Flush()
   123		return r.w.Close()
   124	}
   125	
   126	type child struct {
   127		conn     *conn
   128		handler  http.Handler
   129		requests map[uint16]*request // keyed by request ID
   130	}
   131	
   132	func newChild(rwc io.ReadWriteCloser, handler http.Handler) *child {
   133		return &child{
   134			conn:     newConn(rwc),
   135			handler:  handler,
   136			requests: make(map[uint16]*request),
   137		}
   138	}
   139	
   140	func (c *child) serve() {
   141		defer c.conn.Close()
   142		var rec record
   143		for {
   144			if err := rec.read(c.conn.rwc); err != nil {
   145				return
   146			}
   147			if err := c.handleRecord(&rec); err != nil {
   148				return
   149			}
   150		}
   151	}
   152	
   153	var errCloseConn = errors.New("fcgi: connection should be closed")
   154	
   155	func (c *child) handleRecord(rec *record) error {
   156		req, ok := c.requests[rec.h.Id]
   157		if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues {
   158			// The spec says to ignore unknown request IDs.
   159			return nil
   160		}
   161		if ok && rec.h.Type == typeBeginRequest {
   162			// The server is trying to begin a request with the same ID
   163			// as an in-progress request. This is an error.
   164			return errors.New("fcgi: received ID that is already in-flight")
   165		}
   166	
   167		switch rec.h.Type {
   168		case typeBeginRequest:
   169			var br beginRequest
   170			if err := br.read(rec.content()); err != nil {
   171				return err
   172			}
   173			if br.role != roleResponder {
   174				c.conn.writeEndRequest(rec.h.Id, 0, statusUnknownRole)
   175				return nil
   176			}
   177			c.requests[rec.h.Id] = newRequest(rec.h.Id, br.flags)
   178		case typeParams:
   179			// NOTE(eds): Technically a key-value pair can straddle the boundary
   180			// between two packets. We buffer until we've received all parameters.
   181			if len(rec.content()) > 0 {
   182				req.rawParams = append(req.rawParams, rec.content()...)
   183				return nil
   184			}
   185			req.parseParams()
   186		case typeStdin:
   187			content := rec.content()
   188			if req.pw == nil {
   189				var body io.ReadCloser
   190				if len(content) > 0 {
   191					// body could be an io.LimitReader, but it shouldn't matter
   192					// as long as both sides are behaving.
   193					body, req.pw = io.Pipe()
   194				}
   195				go c.serveRequest(req, body)
   196			}
   197			if len(content) > 0 {
   198				// TODO(eds): This blocks until the handler reads from the pipe.
   199				// If the handler takes a long time, it might be a problem.
   200				req.pw.Write(content)
   201			} else if req.pw != nil {
   202				req.pw.Close()
   203			}
   204		case typeGetValues:
   205			values := map[string]string{"FCGI_MPXS_CONNS": "1"}
   206			c.conn.writePairs(typeGetValuesResult, 0, values)
   207		case typeData:
   208			// If the filter role is implemented, read the data stream here.
   209		case typeAbortRequest:
   210			delete(c.requests, rec.h.Id)
   211			c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete)
   212			if !req.keepConn {
   213				// connection will close upon return
   214				return errCloseConn
   215			}
   216		default:
   217			b := make([]byte, 8)
   218			b[0] = byte(rec.h.Type)
   219			c.conn.writeRecord(typeUnknownType, 0, b)
   220		}
   221		return nil
   222	}
   223	
   224	func (c *child) serveRequest(req *request, body io.ReadCloser) {
   225		r := newResponse(c, req)
   226		httpReq, err := cgi.RequestFromMap(req.params)
   227		if err != nil {
   228			// there was an error reading the request
   229			r.WriteHeader(http.StatusInternalServerError)
   230			c.conn.writeRecord(typeStderr, req.reqId, []byte(err.Error()))
   231		} else {
   232			httpReq.Body = body
   233			c.handler.ServeHTTP(r, httpReq)
   234		}
   235		if body != nil {
   236			body.Close()
   237		}
   238		r.Close()
   239		c.conn.writeEndRequest(req.reqId, 0, statusRequestComplete)
   240		if !req.keepConn {
   241			c.conn.Close()
   242		}
   243	}
   244	
   245	// Serve accepts incoming FastCGI connections on the listener l, creating a new
   246	// goroutine for each. The goroutine reads requests and then calls handler
   247	// to reply to them.
   248	// If l is nil, Serve accepts connections from os.Stdin.
   249	// If handler is nil, http.DefaultServeMux is used.
   250	func Serve(l net.Listener, handler http.Handler) error {
   251		if l == nil {
   252			var err error
   253			l, err = net.FileListener(os.Stdin)
   254			if err != nil {
   255				return err
   256			}
   257			defer l.Close()
   258		}
   259		if handler == nil {
   260			handler = http.DefaultServeMux
   261		}
   262		for {
   263			rw, err := l.Accept()
   264			if err != nil {
   265				return err
   266			}
   267			c := newChild(rw, handler)
   268			go c.serve()
   269		}
   270		panic("unreachable")
   271	}