// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package fcgi

// This file implements FastCGI from the perspective of a child process.

import (
	"fmt"
	"http"
	"http/cgi"
	"io"
	"net"
	"os"
	"time"
)

// request holds the state for an in-progress request. As soon as it's complete,
// it's converted to an http.Request.
type request struct {
	pw        *io.PipeWriter
	reqId     uint16
	params    map[string]string
	buf       [1024]byte
	rawParams []byte
	keepConn  bool
}

func newRequest(reqId uint16, flags uint8) *request {
	r := &request{
		reqId:    reqId,
		params:   map[string]string{},
		keepConn: flags&flagKeepConn != 0,
	}
	r.rawParams = r.buf[:0]
	return r
}

// parseParams reads an encoded []byte into Params.
func (r *request) parseParams() {
	text := r.rawParams
	r.rawParams = nil
	for len(text) > 0 {
		keyLen, n := readSize(text)
		if n == 0 {
			return
		}
		text = text[n:]
		valLen, n := readSize(text)
		if n == 0 {
			return
		}
		text = text[n:]
		key := readString(text, keyLen)
		text = text[keyLen:]
		val := readString(text, valLen)
		text = text[valLen:]
		r.params[key] = val
	}
}

// response implements http.ResponseWriter.
type response struct {
	req         *request
	header      http.Header
	w           *bufWriter
	wroteHeader bool
}

func newResponse(c *child, req *request) *response {
	return &response{
		req:    req,
		header: http.Header{},
		w:      newWriter(c.conn, typeStdout, req.reqId),
	}
}

func (r *response) Header() http.Header {
	return r.header
}

func (r *response) Write(data []byte) (int, os.Error) {
	if !r.wroteHeader {
		r.WriteHeader(http.StatusOK)
	}
	return r.w.Write(data)
}

func (r *response) WriteHeader(code int) {
	if r.wroteHeader {
		return
	}
	r.wroteHeader = true
	if code == http.StatusNotModified {
		// Must not have body.
		r.header.Del("Content-Type")
		r.header.Del("Content-Length")
		r.header.Del("Transfer-Encoding")
	} else if r.header.Get("Content-Type") == "" {
		r.header.Set("Content-Type", "text/html; charset=utf-8")
	}

	if r.header.Get("Date") == "" {
		r.header.Set("Date", time.UTC().Format(http.TimeFormat))
	}

	fmt.Fprintf(r.w, "Status: %d %s\r\n", code, http.StatusText(code))
	r.header.Write(r.w)
	r.w.WriteString("\r\n")
}

func (r *response) Flush() {
	if !r.wroteHeader {
		r.WriteHeader(http.StatusOK)
	}
	r.w.Flush()
}

func (r *response) Close() os.Error {
	r.Flush()
	return r.w.Close()
}

type child struct {
	conn    *conn
	handler http.Handler
}

func newChild(rwc net.Conn, handler http.Handler) *child {
	return &child{newConn(rwc), handler}
}

func (c *child) serve() {
	requests := map[uint16]*request{}
	defer c.conn.Close()
	var rec record
	var br beginRequest
	for {
		if err := rec.read(c.conn.rwc); err != nil {
			return
		}

		req, ok := requests[rec.h.Id]
		if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues {
			// The spec says to ignore unknown request IDs.
			continue
		}
		if ok && rec.h.Type == typeBeginRequest {
			// The server is trying to begin a request with the same ID
			// as an in-progress request. This is an error.
			return
		}

		switch rec.h.Type {
		case typeBeginRequest:
			if err := br.read(rec.content()); err != nil {
				return
			}
			if br.role != roleResponder {
				c.conn.writeEndRequest(rec.h.Id, 0, statusUnknownRole)
				break
			}
			requests[rec.h.Id] = newRequest(rec.h.Id, br.flags)
		case typeParams:
			// NOTE(eds): Technically a key-value pair can straddle the boundary
			// between two packets. We buffer until we've received all parameters.
			if len(rec.content()) > 0 {
				req.rawParams = append(req.rawParams, rec.content()...)
				break
			}
			req.parseParams()
		case typeStdin:
			content := rec.content()
			if req.pw == nil {
				var body io.ReadCloser
				if len(content) > 0 {
					// body could be an io.LimitReader, but it shouldn't matter
					// as long as both sides are behaving.
					body, req.pw = io.Pipe()
				}
				go c.serveRequest(req, body)
			}
			if len(content) > 0 {
				// TODO(eds): This blocks until the handler reads from the pipe.
				// If the handler takes a long time, it might be a problem.
				req.pw.Write(content)
			} else if req.pw != nil {
				req.pw.Close()
			}
		case typeGetValues:
			values := map[string]string{"FCGI_MPXS_CONNS": "1"}
			c.conn.writePairs(0, typeGetValuesResult, values)
		case typeData:
			// If the filter role is implemented, read the data stream here.
		case typeAbortRequest:
			requests[rec.h.Id] = nil, false
			c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete)
			if !req.keepConn {
				// connection will close upon return
				return
			}
		default:
			b := make([]byte, 8)
			b[0] = rec.h.Type
			c.conn.writeRecord(typeUnknownType, 0, b)
		}
	}
}

func (c *child) serveRequest(req *request, body io.ReadCloser) {
	r := newResponse(c, req)
	httpReq, err := cgi.RequestFromMap(req.params)
	if err != nil {
		// there was an error reading the request
		r.WriteHeader(http.StatusInternalServerError)
		c.conn.writeRecord(typeStderr, req.reqId, []byte(err.String()))
	} else {
		httpReq.Body = body
		c.handler.ServeHTTP(r, httpReq)
	}
	if body != nil {
		body.Close()
	}
	r.Close()
	c.conn.writeEndRequest(req.reqId, 0, statusRequestComplete)
	if !req.keepConn {
		c.conn.Close()
	}
}

// Serve accepts incoming FastCGI connections on the listener l, creating a new
// service thread for each. The service threads read requests and then call handler
// to reply to them.
// If l is nil, Serve accepts connections on stdin.
// If handler is nil, http.DefaultServeMux is used.
func Serve(l net.Listener, handler http.Handler) os.Error {
	if l == nil {
		var err os.Error
		l, err = net.FileListener(os.Stdin)
		if err != nil {
			return err
		}
		defer l.Close()
	}
	if handler == nil {
		handler = http.DefaultServeMux
	}
	for {
		rw, err := l.Accept()
		if err != nil {
			return err
		}
		c := newChild(rw, handler)
		go c.serve()
	}
	panic("unreachable")
}
