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