forked from sowawa/node_sample
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfcgi.js
142 lines (113 loc) · 3.79 KB
/
fcgi.js
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
var fcgi = require("fastcgi-stream"),
fs = require("fs"),
util = require("util"),
net = require("net"),
http = require("http"),
IOWatcher = process.binding("io_watcher").IOWatcher,
netBindings = process.binding("net"),
_net_accept = netBindings.accept;
var FCGI_LISTENSOCK_FILENO = process.stdin.fd;
var activeRequests = 0;
var shuttingDown = false;
var closeConnection = function(socket) {
socket.destroy();
socket = null;
activeRequests--;
console.error("closedconn.", activeRequests);
if((activeRequests == 0) && shuttingDown) {
console.error("All done!");
process.exit(-1);
}
}
var handleConnection = function(result, server) {
var socket = new net.Socket(result.fd);
socket.setNoDelay(true);
var fastcgiStream = new fcgi.FastCGIStream(socket);
activeRequests++;
var requests = {};
fastcgiStream.on("record", function(requestId, record) {
var request = requests[requestId];
if(record instanceof fcgi.records.BeginRequest) {
if(request) {
closeConnection(socket);
}
requests[requestId] = {
req: new http.IncomingMessage(null)
};
}
else if(record instanceof fcgi.records.Params) {
record.params.forEach(function(paramPair) {
request.req._addHeaderLine(paramPair[0].toLowerCase(), paramPair[1]);
});
if(record.params.length == 0) {
var httpVersionStr = request.req.headers.server_protocol || "HTTP/1.1";
var httpVersionParts = httpVersionStr.replace(/^HTTP\//, "").split(".");
if(httpVersionParts.length != 2) httpVersionParts = [1, 1];
request.req.httpVersionMajor = httpVersionParts[0];
request.req.httpVersionMinor = httpVersionParts[1];
request.req.httpVersion = request.req.httpVersionMajor + "." + request.req.httpVersionMinor;
request.req.url = request.req.headers.request_uri;
request.req.method = request.req.headers.request_method;
request.res = new http.ServerResponse(request.req);
request.res.assignSocket({
writable: true,
write: function(data, encoding) {
var stdOutRecord = new fcgi.records.StdOut(data);
stdOutRecord.encoding = encoding;
fastcgiStream.writeRecord(requestId, stdOutRecord);
}
});
request.res.useChunkedEncodingByDefault = false;
request.res._storeHeader = function(statusLine, headers) {
var matches = statusLine.match(/^HTTP\/[0-9]\.[0-9] (.+)/);
headers["Status"] = matches[1];
http.OutgoingMessage.prototype._storeHeader.apply(this, ["", headers]);
};
request.res.on("finish", function() {
var end = new fcgi.records.EndRequest(0, fcgi.records.EndRequest.protocolStatus.REQUEST_COMPLETE);
fastcgiStream.writeRecord(requestId, end);
closeConnection(socket);
});
try {
server.emit("request", request.req, request.res);
}
catch(e) {
console.error(e);
var end = new fcgi.records.EndRequest(-1, fcgi.records.EndRequest.protocolStatus.REQUEST_COMPLETE);
fastcgiStream.writeRecord(requestId, end);
closeConnection(socket);
}
}
}
else if(record instanceof fcgi.records.StdIn) {
if(record.data.length == 0) {
request.req.emit("end");
}
else {
request.req.emit("data", record.data);
}
}
});
socket.resume();
};
module.exports.handle = function(server) {
var initiateShutdown = function() {
console.error("Initiating shutdown.");
shuttingDown = true;
console.error(activeRequests);
if(activeRequests == 0) {
console.error("Shutting down.");
watcher.stop();
process.exit(0);
}
};
var watcher = new IOWatcher();
watcher.set(FCGI_LISTENSOCK_FILENO, true, false);
watcher.callback = function() {
var result = _net_accept(FCGI_LISTENSOCK_FILENO);
handleConnection(result, server);
};
watcher.start();
process.on("SIGUSR1", initiateShutdown);
process.on("SIGTERM", initiateShutdown);
};