1 // Written in the D programming language.
2 
3 /**
4 
5   */
6 module fcgi.app;
7 import std.socket;
8 import std.stdio;
9 import std.traits;
10 import std.stdio;
11 
12 
13 Request request;
14 
15 void init()
16 {
17 	auto family = AddressFamily.INET;
18 	version(Posix)
19 	{
20 		import core.sys.posix.sys.socket;
21 		sockaddr_storage ss;
22 		socklen_t nameLen = ss.sizeof;
23 		if(-1 == getsockname(Protocol.listenfd, cast(sockaddr*)&ss, &nameLen)) {
24 			perror("getsockname");
25 		}
26 		if(ss.ss_family == AF_UNIX) {
27 			family = AddressFamily.UNIX;
28 		}
29 		else {
30 		}
31 		request.listenSock = new Socket(cast(socket_t)0, family);
32 
33 	}
34 
35 	version(Windows)
36 	{
37 		import core.sys.windows.windows;
38 		HANDLE stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
39 		request.listenSock = new Socket(cast(socket_t)stdinHandle, AddressFamily.INET);
40 	}
41 }
42 
43 bool accept()
44 {
45 	if (request.ipcSockClosed) {
46 		synchronized {
47 			try {
48 				request.ipcSock = request.listenSock.accept();
49 			}
50 			catch(SocketAcceptException e)
51 			{
52 				return false;
53 			}
54 			request.ipcSockClosed = false;
55 		}
56 	}
57 	else {
58 	}
59 
60 	request.stdin.fillBuffer();
61 	request.stdin.processProtocol;
62 	return true;
63 }
64 
65 void finish()
66 {
67 	request.stdout.flush();
68 	request.stdin.buffer[] = 0;
69 	request.stdin.next = 0;
70 	request.stdin.bufferStop = 0;
71 	request.stdin.contentStop = 0;
72 	//.close(request.ipcfd);
73 	if (request.keepConnection){
74 		return;
75 	}
76 	request.ipcSock.close();
77 	request.ipcSockClosed = true;
78 }
79 
80 
81 struct Request
82 {
83 	InputStream stdin;
84 	auto stdout = OutputStream(bufferMaxLength);
85 	auto stderr = OutputStream(128);
86 	char[][string] params;
87 	int requestId;
88 
89 	private:
90 	ubyte keepConnection;
91 	int role;
92 	Socket ipcSock;
93 	bool ipcSockClosed = true;
94 	static Socket listenSock;
95 
96 }
97 
98 private:
99 
100 enum bufferMaxLength = 8192;
101 
102 struct InputStream
103 {
104 	size_t read(void* ptr, size_t length)
105 	{
106 		if (next == contentStop) {
107 			fillBuffer;
108 			processProtocol;
109 		}
110 
111 		//import std.algorithm.comparison:min;
112 		auto realLen = contentStop - next;
113 		auto len = length < realLen ? length : realLen;
114 		ptr[0 .. len] = buffer[next .. len + next];
115 		return len;
116 	}
117 
118 	size_t read(void[] buf)
119 	{
120 		return read(buf.ptr, buf.length);
121 	}
122 
123 	char read()
124 	{
125 		if (next == contentStop) {
126 			fillBuffer;
127 		}
128 
129 		return cast(char)buffer[next++];
130 	}
131 
132 	private:
133 	ubyte[bufferMaxLength] buffer;
134 
135 	size_t	contentLength;
136 	ubyte	paddingLength;
137 	size_t	next;
138 	size_t	stop;
139 	size_t	contentStop;
140 	size_t	bufferStop;
141 
142 	bool fillBuffer()
143 	{
144 		if (next == bufferStop) {
145 			auto readn= request.ipcSock.receive(buffer[next .. $]);
146 			if (readn == Socket.ERROR) {
147 				return false;
148 			}
149 			if (readn == 0) {
150 				request.ipcSock.close();
151 				request.ipcSockClosed = true;
152 				return false;
153 			}
154 			bufferStop += readn;
155 
156 		}
157 
158 		return true;
159 	}
160 
161 	void processProtocol()
162 	{
163 		do {
164 			// process Header
165 			if (next == contentStop) {
166 				fillBuffer;
167 			}
168 			auto header = cast(Protocol.Header*)(buffer.ptr + next);
169 			next += Protocol.Header.sizeof;
170 
171 			request.requestId =	(header.requestIdB1 << 8)
172 				+ header.requestIdB0;
173 			contentLength =	(header.contentLengthB1 << 8)
174 				+ header.contentLengthB0;
175 
176 			contentStop = next + contentLength;
177 			paddingLength = header.paddingLength;
178 			// process Body
179 			switch (header.type)
180 			{
181 				case Protocol.requestType.begin:
182 					auto body_ = cast(Protocol.BeginRequestBody*)(buffer.ptr + next);
183 					next += Protocol.BeginRequestBody.sizeof;
184 					request.keepConnection = (body_.flags & Protocol.keepConnection);
185 					request.role = (body_.roleB1 << 8) + body_.roleB0;
186 					if (request.role == Protocol.role.responder) {
187 						request.params["FCGI_ROLE"] = "RESPONDER".dup;
188 					}
189 					else if (request.role == Protocol.role.authorizer) {
190 						request.params["FCGI_ROLE"] = "AUTHORIZER".dup;
191 					}
192 					else if (request.role == Protocol.role.filter) {
193 						request.params["FCGI_ROLE"] = "FILTER".dup;
194 					}
195 					else {
196 						request.params["FCGI_ROLE"] = "UNKNOW".dup;
197 					}
198 					break;
199 				case Protocol.requestType.Params:
200 					// TODO: read params
201 					size_t nameLen, valueLen;
202 					auto begin = next;
203 					while(next < contentStop) {
204 						nameLen = ((buffer[next] & 0x80) != 0) ?
205 							((buffer[next++] & 0x7f) << 24) 
206 							+ (buffer[next++] << 16) 
207 							+ (buffer[next++] << 8) 
208 							+ buffer[next++]
209 							: buffer[next++];
210 
211 						valueLen = ((buffer[next] & 0x80) != 0)?
212 							((valueLen & 0x7f) << 24) 
213 							+ (buffer[next++] << 16)
214 							+ (buffer[next++] << 8)
215 							+ buffer[next++]
216 							:buffer[next++];
217 
218 						auto name = cast(string) buffer[next .. next+ nameLen].idup;
219 						auto value = cast(char[])buffer[next + nameLen .. next + nameLen + valueLen];
220 						request.params[name] = value; 
221 						next += nameLen + valueLen;
222 					}
223 					next += header.paddingLength;
224 					stdout.flush;
225 					return;                  
226 				case Protocol.requestType.Stdin:
227 					return;
228 				case Protocol.requestType.End:
229 					return;
230 				default:
231 					return;
232 
233 			}
234 
235 		} while(true);
236 
237 	}
238 }
239 
240 struct OutputStream
241 {
242 
243 
244 	this(size_t bufferLength)
245 	{
246 		buffer = new ubyte[bufferLength];
247 	}
248 
249 	size_t writeBlock(const void* ptr, size_t length)
250 	{
251 		auto p = cast(ubyte*) ptr;
252 		buffer[next .. next + length] = p[0 .. length];
253 		next += length;
254 		return length;
255 	}
256 
257 	size_t write(ubyte[] buff)
258 	{
259 		return this.writeBlock(buff.ptr, buff.length);
260 	}
261 
262 	void write(ubyte b)
263 	{
264 		buffer[next ++] = b;
265 	}
266 
267 	size_t write(in char[] str)
268 	{
269 		return this.writeBlock(str.ptr, str.length);
270 	}
271 
272 	void put(A)(A writeme)
273 		if (is(ElementType!A : const(dchar)) &&
274 				isInputRange!A &&
275 				!isInfinite!A)
276 		{
277 			alias C = ElementEncodingType!A;
278 			writeBlock(cast(ubyte*)A.ptr, A.length * C.sizeof);
279 		}
280 
281 	void put(char c)
282 	{
283 		buffer[next ++] = cast(ubyte)c;
284 	}
285 
286 	size_t align8(size_t n) {
287 		return (n + 7) & (size_t.max - 7);
288 	}
289 
290 	void makeHeader(Protocol.Header* header, ubyte type, size_t contentLength, ubyte paddingLength)
291 	{
292 
293 		header.version_ = Protocol.version1;
294 		header.type             = cast(ubyte) type;
295 		header.requestIdB1      = cast(ubyte) ((request.requestId     >> 8) & 0xff);
296 		header.requestIdB0      = cast(ubyte) ((request.requestId         ) & 0xff);
297 		header.contentLengthB1  = cast(ubyte) ((contentLength >> 8) & 0xff);
298 		header.contentLengthB0  = cast(ubyte) ((contentLength     ) & 0xff);
299 		header.paddingLength    = paddingLength;
300 		header.reserved         =  0;
301 	}
302 
303 	void flush()
304 	{
305 		auto contentLength = (next - 8);
306 
307 		auto alignLength = align8(next);
308 		auto paddingLength = alignLength - next;
309 		next = alignLength;
310 		auto header = cast(Protocol.Header*)buffer.ptr;
311 		makeHeader(
312 				header, 
313 				Protocol.requestType.Stdout, 
314 				contentLength,
315 				cast(ubyte)paddingLength
316 				);
317 
318 		Protocol.Header endHeader;
319 		makeHeader(
320 				&endHeader, 
321 				Protocol.requestType.End, 
322 				Protocol.EndRequestBody.sizeof, 
323 				cast(ubyte)0
324 				);
325 
326 		Protocol.EndRequestBody endBody;
327 
328 		endBody.protocolStatus = 0;
329 		endBody.appStatusB3 = 0;
330 		endBody.appStatusB2 = 0;
331 		endBody.appStatusB1 = 0;
332 		endBody.appStatusB0 = 0;
333 
334 		next = alignLength;
335 		writeBlock(cast(ubyte*)&endHeader, endHeader.sizeof);
336 		writeBlock(cast(ubyte*)&endBody, endBody.sizeof);
337 		//core.sys.posix.unistd.write(request.ipcfd, buffer.ptr, alignLength);
338 		request.ipcSock.send(buffer[0 .. next]);
339 		buffer[] = 0;
340 		next = 8;
341 		begin = 8;
342 	}
343 
344 	void setStdoutHeader();
345 	private:
346 	ubyte[] buffer;
347 
348 	size_t begin = 8;
349 	size_t next = 8;
350 }
351 
352 struct Protocol
353 {
354 	enum listenfd = 0;
355 
356 	enum nullRequestId = 0;
357 
358 	enum version1 = 1;
359 
360 	enum keepConnection = 1;
361 
362 	enum role {
363 		responder	= 1,
364 		authorizer	= 2,
365 		filter 		= 3,
366 	}
367 
368 	enum error {
369 		unsupportedVersion = -2
370 	}
371 
372 	enum requestType {
373 		begin     = 1,
374 		Abort     = 2,
375 		End       = 3,
376 		Params    = 4,
377 		Stdin     = 5,
378 		Stdout    = 6,
379 		Stderr    = 7,
380 		Data      = 8,
381 		GetValues = 9,
382 		GetValuesResult = 10,
383 		UnknownType     = 11
384 	}
385 
386 	struct Header
387 	{
388 		ubyte version_;
389 		ubyte type;
390 		ubyte requestIdB1;
391 		ubyte requestIdB0;
392 		ubyte contentLengthB1;
393 		ubyte contentLengthB0;
394 		ubyte paddingLength;
395 		ubyte reserved;
396 	}
397 
398 	struct BeginRequestBody
399 	{
400 		ubyte roleB1;
401 		ubyte roleB0;
402 		ubyte flags;
403 		ubyte[5] reserved;
404 	}
405 
406 	struct BeginRequestRecord
407 	{
408 		Header header;
409 		BeginRequestBody body_;
410 	}
411 
412 	struct EndRequestBody
413 	{
414 		ubyte appStatusB3;
415 		ubyte appStatusB2;
416 		ubyte appStatusB1;
417 		ubyte appStatusB0;
418 		ubyte protocolStatus;
419 		ubyte[3] reserved;
420 	}
421 
422 	struct EndRequestRecord
423 	{
424 		Header header;
425 		EndRequestBody body_;
426 	}
427 
428 	struct UnknownTypeBody
429 	{
430 		ubyte type;
431 		ubyte[7] reserved;
432 	}
433 
434 	struct UnknownTypeRecord
435 	{
436 		Header header;
437 		UnknownTypeBody body_;
438 	}
439 }
440