~ericmoritz/+junk/gofastcgi

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package gofastcgi


import (
	"io";
	"os";
	"bytes";
//	"log";
)

type Request struct {
	RequestID uint16;

	// Bodies from the records
	BeginRequestBody;
	UnknownTypeBody;
	EndRequestBody;

	// The good stuff
	Env map[string]string;
	Stdin  *bytes.Buffer;
	Stdout FlushWriter;
	Stderr FlushWriter;
};

func (req *Request) Read(s io.ReadWriter) (err os.Error) {
	remaining := 1;
	inbytes := make([]byte, 8192); // 8192 is what libfcgi uses
	//outbytes := make([]byte, 8192);
    //errbytes := make([]byte, 512); // 512 is what libfcgi uses
	req.RequestID = 0;

	req.Stdin = bytes.NewBuffer(inbytes);

	timer := new(TimeIt);

	for remaining != 0 {
		var r Record;
		err = r.Read(s);

		if err != nil {
			return err;
		}
		
		
		switch {
		// Start the request
		case r.Header.Type == FCGI_BEGIN_REQUEST && req.RequestID == 0:
			req.RequestID = r.Header.RequestID;
			req.BeginRequestBody.Read(bytes.NewBuffer(r.Content));

			switch req.BeginRequestBody.Role {
			case FCGI_AUTHORIZER:
				remaining=1;
			case FCGI_RESPONDER:
				remaining=2;
			case FCGI_FILTER:
				remaining=3;
			}
			
		case r.Header.Type == FCGI_PARAMS:
			req.Env = r.Content.GetParams();
			if len(r.Content) == 0 {
				remaining--;
			}

		case r.Header.Type == FCGI_STDIN:
			if len(r.Content) > 0 {
				req.Stdin.Write(r.Content);
			} else {
				remaining--;
			}
		case r.Header.Type == FCGI_DATA:
			timer.Start();			
			if len(r.Content) == 0 {
				remaining--;
			}
		}
	}

	req.Stdout = NewWriter(req.RequestID, FCGI_STDOUT, s, true); //bytes.NewBuffer(outbytes);
	req.Stderr = NewWriter(req.RequestID, FCGI_STDERR, s, true); //bytes.NewBuffer(outbytes);		
	return nil
}


func (req *Request) Write(w io.ReadWriter, status uint32) (os.Error) {
	var r *Record;

	// Flush out any left over data
	req.Stdout.Flush();
	req.Stderr.Flush();

	// Set the end of stream record
	r = new(Record);
	r.Header.RequestID=req.RequestID;
	r.Header.Type=FCGI_STDOUT;
	r.Content = make([]byte,0);
	r.Header.ContentLength = 0;
	r.Write(w);

	// Set the end of stream record
	r = new(Record);
	r.Header.RequestID=req.RequestID;
	r.Header.Type=FCGI_STDERR;
	r.Content = make([]byte,0);
	r.Header.ContentLength = 0;
	r.Write(w);

	r = new(Record);
	r.Header.Type = FCGI_END_REQUEST;
	r.Header.RequestID = req.RequestID;
	
	body := new(EndRequestBody);
	body.Status = status;
	body.ProtocolStatus = FCGI_REQUEST_COMPLETE;

	r.Content = body.Bytes();
	r.Header.ContentLength = uint16(len(r.Content));

	if err := r.Write(w); err != nil { return err; }

	return nil;
}