Commit | Line | Data |
1b64d24d |
1 | use Config; |
2 | |
3 | open OUT, ">FCGI.xs"; |
4 | |
5 | print "Generating FCGI.xs for Perl version $]\n"; |
6 | #unless (exists $Config{apiversion} && $Config{apiversion} >= 5.005) |
7 | unless ($] >= 5.005) { |
8 | for (qw(sv_undef diehook warnhook in_eval)) { |
9 | print OUT "#define PL_$_ $_\n" |
10 | } |
11 | } |
12 | print OUT while <DATA>; |
13 | close OUT; |
14 | __END__ |
eede4b76 |
15 | /* $Id: FCGI.PL,v 1.5 1999/07/28 19:23:08 skimo Exp $ */ |
1b64d24d |
16 | |
17 | #include "EXTERN.h" |
18 | #include "perl.h" |
19 | #include "XSUB.h" |
20 | |
21 | #include "fcgiapp.h" |
22 | |
23 | #ifndef FALSE |
24 | #define FALSE (0) |
25 | #endif |
26 | |
27 | #ifndef TRUE |
28 | #define TRUE (1) |
29 | #endif |
30 | |
0074e702 |
31 | #ifdef WIN32 |
32 | #define environ _environ |
33 | #endif |
34 | |
1b64d24d |
35 | extern char **environ; |
1b64d24d |
36 | |
37 | #ifdef USE_SFIO |
38 | typedef struct |
39 | { |
40 | Sfdisc_t disc; |
41 | FCGX_Stream *stream; |
42 | } FCGI_Disc; |
43 | |
44 | static ssize_t |
45 | sffcgiread(f, buf, n, disc) |
46 | Sfio_t* f; /* stream involved */ |
47 | Void_t* buf; /* buffer to read into */ |
48 | size_t n; /* number of bytes to read */ |
49 | Sfdisc_t* disc; /* discipline */ |
50 | { |
51 | return FCGX_GetStr(buf, n, ((FCGI_Disc *)disc)->stream); |
52 | } |
53 | |
54 | static ssize_t |
55 | sffcgiwrite(f, buf, n, disc) |
56 | Sfio_t* f; /* stream involved */ |
57 | const Void_t* buf; /* buffer to read into */ |
58 | size_t n; /* number of bytes to read */ |
59 | Sfdisc_t* disc; /* discipline */ |
60 | { |
61 | n = FCGX_PutStr(buf, n, ((FCGI_Disc *)disc)->stream); |
62 | FCGX_FFlush(((FCGI_Disc *)disc)->stream); |
63 | return n; |
64 | } |
65 | |
66 | Sfdisc_t * |
67 | sfdcnewfcgi(stream) |
68 | FCGX_Stream *stream; |
69 | { |
70 | FCGI_Disc* disc; |
71 | |
72 | New(1000,disc,1,FCGI_Disc); |
73 | if (!disc) return (Sfdisc_t *)disc; |
74 | |
75 | disc->disc.exceptf = (Sfexcept_f)NULL; |
76 | disc->disc.seekf = (Sfseek_f)NULL; |
77 | disc->disc.readf = sffcgiread; |
78 | disc->disc.writef = sffcgiwrite; |
79 | disc->stream = stream; |
80 | return (Sfdisc_t *)disc; |
81 | } |
82 | |
83 | Sfdisc_t * |
84 | sfdcdelfcgi(disc) |
85 | Sfdisc_t* disc; |
86 | { |
87 | Safefree(disc); |
88 | return 0; |
89 | } |
90 | #endif |
91 | |
90a18d65 |
92 | static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: FCGI */ |
93 | |
94 | static FCGX_Request global_fcgx_request; |
95 | |
96 | typedef struct FCGP_Request { |
97 | int compat; |
98 | int acceptCalled; |
99 | int finishCalled; |
100 | SV* svin; |
101 | SV* svout; |
102 | SV* sverr; |
eede4b76 |
103 | GV* gv[3]; |
90a18d65 |
104 | FCGX_Stream* in; |
eede4b76 |
105 | FCGX_ParamArray envp; |
90a18d65 |
106 | FCGX_Request* requestPtr; |
107 | } FCGP_Request; |
108 | |
109 | static FCGP_Request global_request; |
110 | static SV* global_sverr; |
1b64d24d |
111 | |
112 | static int |
90a18d65 |
113 | FCGI_Flush(FCGP_Request* request) |
1b64d24d |
114 | { |
eede4b76 |
115 | if(!request->acceptCalled || isCGI) { |
1b64d24d |
116 | return; |
117 | } |
118 | #ifdef USE_SFIO |
eede4b76 |
119 | sfsync(IoIFP(GvIOp(request->gv[1]))); |
120 | sfsync(IoIFP(GvIOp(request->gv[2]))); |
1b64d24d |
121 | #else |
90a18d65 |
122 | FCGX_FFlush((FCGX_Stream *) SvIV((SV*) SvRV(request->svout))); |
123 | FCGX_FFlush((FCGX_Stream *) SvIV((SV*) SvRV(request->sverr))); |
1b64d24d |
124 | #endif |
125 | } |
126 | |
127 | static int |
90a18d65 |
128 | FCGI_Accept(FCGP_Request* request) |
1b64d24d |
129 | { |
90a18d65 |
130 | if(isCGI == -1) { |
1b64d24d |
131 | /* |
132 | * First call to FCGI_Accept. Is application running |
133 | * as FastCGI or as CGI? |
134 | */ |
135 | isCGI = FCGX_IsCGI(); |
136 | } else if(isCGI) { |
137 | /* |
138 | * Not first call to FCGI_Accept and running as CGI means |
139 | * application is done. |
140 | */ |
141 | return(EOF); |
eede4b76 |
142 | } |
143 | if(request->acceptCalled && !request->finishCalled) { |
1b64d24d |
144 | #ifdef USE_SFIO |
eede4b76 |
145 | sfdcdelfcgi(sfdisc(IoIFP(GvIOp(request->gv[0])), SF_POPDISC)); |
146 | sfdcdelfcgi(sfdisc(IoIFP(GvIOp(request->gv[1])), SF_POPDISC)); |
147 | sfdcdelfcgi(sfdisc(IoIFP(GvIOp(request->gv[2])), SF_POPDISC)); |
1b64d24d |
148 | #else |
eede4b76 |
149 | FCGI_Flush(request); |
1b64d24d |
150 | #endif |
1b64d24d |
151 | } |
152 | if(!isCGI) { |
1b64d24d |
153 | FCGX_Stream *out, *error; |
eede4b76 |
154 | int acceptResult = FCGX_Accept_r(&request->in, &out, &error, |
155 | &request->envp, |
90a18d65 |
156 | request->requestPtr); |
1b64d24d |
157 | if(acceptResult < 0) { |
158 | return acceptResult; |
159 | } |
160 | #ifdef USE_SFIO |
eede4b76 |
161 | sfdisc(IoIFP(GvIOp(request->gv[0])), sfdcnewfcgi(request->in)); |
162 | sfdisc(IoIFP(GvIOp(request->gv[1])), sfdcnewfcgi(out)); |
163 | sfdisc(IoIFP(GvIOp(request->gv[2])), sfdcnewfcgi(error)); |
1b64d24d |
164 | #else |
90a18d65 |
165 | if (!request->svout) { |
eede4b76 |
166 | newSVrv(request->svout = newSV(0), "FCGI::Stream"); |
167 | sv_magic((SV *)request->gv[1], request->svout, 'q', Nullch, 0); |
168 | newSVrv(request->sverr = newSV(0), "FCGI::Stream"); |
169 | sv_magic((SV *)request->gv[2], request->sverr, 'q', Nullch, 0); |
170 | newSVrv(request->svin = newSV(0), "FCGI::Stream"); |
171 | sv_magic((SV *)request->gv[0], request->svin, 'q', Nullch, 0); |
1b64d24d |
172 | } |
90a18d65 |
173 | sv_setiv(SvRV(request->svout), (IV) out); |
174 | sv_setiv(SvRV(request->sverr), (IV) error); |
175 | sv_setiv(SvRV(request->svin), (IV) request->in); |
176 | |
177 | if (request->compat) { |
178 | global_sverr = request->sverr; |
6ef7789b |
179 | if (PL_warnhook) SvREFCNT_dec(PL_warnhook); |
180 | PL_warnhook = SvREFCNT_inc(GvCV(gv_fetchmethod(Nullhv, "FCGI::WARN"))); |
6ef7789b |
181 | if (PL_diehook) SvREFCNT_dec(PL_diehook); |
182 | PL_diehook = SvREFCNT_inc(GvCV(gv_fetchmethod(Nullhv, "FCGI::DIE"))); |
183 | } |
1b64d24d |
184 | #endif |
90a18d65 |
185 | request->finishCalled = FALSE; |
1b64d24d |
186 | } |
90a18d65 |
187 | request->acceptCalled = TRUE; |
1b64d24d |
188 | return 0; |
189 | } |
190 | |
191 | static void |
90a18d65 |
192 | FCGI_Finish(FCGP_Request* request) |
1b64d24d |
193 | { |
90a18d65 |
194 | if(!request->acceptCalled || isCGI) { |
1b64d24d |
195 | return; |
196 | } |
90a18d65 |
197 | if (request->compat) { |
1b64d24d |
198 | #ifdef USE_SFIO |
eede4b76 |
199 | sfdcdelfcgi(sfdisc(IoIFP(GvIOp(request->gv[0])), SF_POPDISC)); |
200 | sfdcdelfcgi(sfdisc(IoIFP(GvIOp(request->gv[1])), SF_POPDISC)); |
201 | sfdcdelfcgi(sfdisc(IoIFP(GvIOp(request->gv[2])), SF_POPDISC)); |
1b64d24d |
202 | #else |
90a18d65 |
203 | FCGI_Flush(request); |
1b64d24d |
204 | #endif |
1b64d24d |
205 | } |
90a18d65 |
206 | request->in = NULL; |
207 | FCGX_Finish_r(request->requestPtr); |
208 | request->finishCalled = TRUE; |
209 | #ifndef USE_SFIO |
210 | if (request->compat) { |
211 | if (PL_warnhook == (SV*)GvCV(gv_fetchmethod(Nullhv, "FCGI::WARN"))) { |
212 | SvREFCNT_dec(PL_warnhook); |
213 | PL_warnhook = Nullsv; |
214 | } |
215 | if (PL_diehook == (SV*)GvCV(gv_fetchmethod(Nullhv, "FCGI::DIE"))) { |
216 | SvREFCNT_dec(PL_diehook); |
217 | PL_diehook = Nullsv; |
218 | } |
1b64d24d |
219 | } |
220 | #endif |
221 | } |
222 | |
223 | static int |
90a18d65 |
224 | FCGI_StartFilterData(FCGP_Request* request) |
225 | { |
226 | return request->in ? FCGX_StartFilterData(request->in) : -1; |
227 | } |
228 | |
229 | static void |
230 | FCGI_SetExitStatus(FCGP_Request* request, int status) |
231 | { |
232 | if (request->in) FCGX_SetExitStatus(status, request->in); |
233 | } |
234 | |
235 | static FCGP_Request * |
236 | FCGI_Request() |
1b64d24d |
237 | { |
90a18d65 |
238 | FCGX_Request* fcgx_req; |
239 | FCGP_Request* req; |
240 | |
241 | Newz(551, fcgx_req, 1, FCGX_Request); |
242 | Newz(551, req, 1, FCGP_Request); |
243 | req->requestPtr = fcgx_req; |
244 | |
245 | return req; |
1b64d24d |
246 | } |
247 | |
248 | static void |
90a18d65 |
249 | FCGI_Release_Request(FCGP_Request *req) |
1b64d24d |
250 | { |
90a18d65 |
251 | Safefree(req->requestPtr); |
252 | Safefree(req); |
1b64d24d |
253 | } |
254 | |
255 | /* |
256 | * For each variable in the array envp, either set or unset it |
257 | * in the global hash %ENV. |
258 | */ |
259 | static void |
260 | DoPerlEnv(envp, set) |
261 | char **envp; |
262 | int set; |
263 | { |
264 | int i; |
265 | char *p, *p1; |
266 | HV *hv; |
267 | SV *sv; |
268 | hv = perl_get_hv("ENV", TRUE); |
269 | |
270 | if (!set) |
271 | perl_eval_pv("%ENV = %FCGI::ENV", 0); |
272 | else { |
273 | perl_eval_pv("%FCGI::ENV = %ENV", 0); |
274 | for(i = 0; ; i++) { |
275 | if((p = envp[i]) == NULL) { |
276 | break; |
277 | } |
278 | p1 = strchr(p, '='); |
279 | assert(p1 != NULL); |
1b64d24d |
280 | sv = newSVpv(p1 + 1, 0); |
281 | /* call magic for this value ourselves */ |
282 | hv_store(hv, p, p1 - p, sv, 0); |
283 | SvSETMAGIC(sv); |
1b64d24d |
284 | } |
285 | } |
286 | } |
287 | |
eede4b76 |
288 | #define REQUEST_ARG(arg,request) \ |
289 | if (sv_isa(ST(arg), "FCGI")) { \ |
290 | request = (FCGP_Request*) SvIV((SV*)SvRV(ST(arg))); \ |
291 | } else \ |
292 | croak("request is not of type FCGI") |
1b64d24d |
293 | |
eede4b76 |
294 | typedef FCGX_Stream * FCGI__Stream; |
295 | typedef FCGP_Request * FCGI; |
1b64d24d |
296 | |
297 | MODULE = FCGI PACKAGE = FCGI |
298 | |
90a18d65 |
299 | BOOT: |
300 | FCGX_Init(); |
301 | FCGX_InitRequest(&global_fcgx_request); |
302 | memset(&global_request, 0, sizeof(global_request)); |
303 | global_request.compat = 1; |
304 | global_request.requestPtr = &global_fcgx_request; |
eede4b76 |
305 | global_request.gv[0] = gv_fetchpv("STDIN",TRUE, SVt_PVIO); |
306 | global_request.gv[1] = gv_fetchpv("STDOUT",TRUE, SVt_PVIO); |
307 | global_request.gv[2] = gv_fetchpv("STDERR",TRUE, SVt_PVIO); |
308 | |
309 | |
310 | SV * |
311 | request() |
312 | |
313 | PROTOTYPE: |
314 | CODE: |
315 | RETVAL = Perl_sv_setref_pv(Perl_newSV(0), "FCGI", FCGI_Request()); |
316 | |
317 | OUTPUT: |
318 | RETVAL |
319 | |
320 | |
321 | int |
322 | accept(...) |
323 | |
324 | PROTOTYPE: ;$***$ |
325 | |
326 | PREINIT: |
327 | FCGP_Request* request = &global_request; |
328 | |
329 | CODE: |
330 | if (items != 0 && items != 5) |
331 | croak("Usage: FCGI::accept() or " |
332 | "FCGI::accept(request, IN, OUT, ERR, env)"); |
333 | if (items) { |
334 | static const char* names[] = {"", "IN", "OUT", "ERR"}; |
335 | int i; |
336 | |
337 | REQUEST_ARG(0,request); |
338 | for(i = 1; i <= 3; ++i) { |
339 | if (SvROK(ST(i)) && isGV(SvRV(ST(i)))) { |
340 | request->gv[i-1] = (GV*)SvRV(ST(i)); |
341 | } else |
342 | croak("%s is not a GLOB reference", names[i]); |
343 | } |
344 | } |
345 | { |
346 | char **savedEnviron; |
347 | int acceptStatus; |
348 | /* |
349 | * Unmake Perl variable settings for the request just completed. |
350 | */ |
351 | if(request->envp != NULL) { |
352 | DoPerlEnv(request->envp, FALSE); |
353 | request->envp = NULL; |
354 | } |
355 | /* |
356 | * Call FCGI_Accept but preserve environ. |
357 | */ |
358 | acceptStatus = FCGI_Accept(request); |
359 | /* |
360 | * Make Perl variable settings for the new request. |
361 | */ |
362 | if(request->compat && acceptStatus >= 0 && !isCGI) { |
363 | DoPerlEnv(request->envp, TRUE); |
364 | } else { |
365 | request->envp = NULL; |
366 | } |
367 | RETVAL = acceptStatus; |
368 | } |
369 | OUTPUT: |
370 | RETVAL |
371 | |
372 | |
373 | void |
374 | finish(...) |
375 | |
376 | PROTOTYPE: ;$ |
377 | |
378 | PREINIT: |
379 | FCGP_Request* request = &global_request; |
380 | |
381 | CODE: |
382 | if (items != 0 && items != 1) |
383 | croak("Usage: FCGI::finish() or " |
384 | "FCGI::finish(request)"); |
385 | if (items) { |
386 | REQUEST_ARG(0,request); |
387 | } |
388 | { |
389 | /* |
390 | * Unmake Perl variable settings for the completed request. |
391 | */ |
392 | if(request->envp != NULL) { |
393 | DoPerlEnv(request->envp, FALSE); |
394 | request->envp = NULL; |
395 | } |
396 | /* |
397 | * Finish the request. |
398 | */ |
399 | FCGI_Finish(request); |
400 | } |
401 | |
402 | |
403 | void |
404 | flush(...) |
405 | |
406 | PROTOTYPE: ;$ |
407 | |
408 | PREINIT: |
409 | FCGP_Request* request = &global_request; |
410 | |
411 | CODE: |
412 | if (items != 0 && items != 1) |
413 | croak("Usage: FCGI::flush([request])"); |
414 | if (items) { |
415 | REQUEST_ARG(0,request); |
416 | } |
417 | FCGI_Flush(request); |
418 | |
419 | void |
420 | set_exit_status(status,...) |
421 | |
422 | int status; |
423 | |
424 | PROTOTYPE: $;$ |
425 | |
426 | PREINIT: |
427 | FCGP_Request* request = &global_request; |
428 | |
429 | CODE: |
430 | if (items != 1 && items != 2) |
431 | croak("Usage: FCGI::set_exit_status(status[,request])"); |
432 | if (items == 2) { |
433 | REQUEST_ARG(1,request); |
434 | } |
435 | FCGI_SetExitStatus(request, status); |
436 | |
437 | int |
438 | start_filter_data(...) |
439 | |
440 | PROTOTYPE: ;$ |
441 | |
442 | PREINIT: |
443 | FCGP_Request* request = &global_request; |
444 | |
445 | CODE: |
446 | if (items != 0 && items != 1) |
447 | croak("Usage: FCGI::flush([request])"); |
448 | if (items) { |
449 | REQUEST_ARG(0,request); |
450 | } |
451 | RETVAL = FCGI_StartFilterData(request); |
452 | |
453 | OUTPUT: |
454 | RETVAL |
455 | |
456 | |
457 | void |
458 | DESTROY(request) |
459 | FCGI request; |
460 | |
461 | CODE: |
462 | FCGI_Release_Request(request); |
463 | |
464 | |
465 | |
466 | MODULE = FCGI PACKAGE = FCGI::Stream |
90a18d65 |
467 | |
1b64d24d |
468 | #ifndef USE_SFIO |
469 | void |
470 | DIE(msg) |
471 | char * msg; |
472 | |
473 | CODE: |
474 | if (!PL_in_eval) |
90a18d65 |
475 | FCGX_PutS(msg, (FCGX_Stream *) SvIV((SV*) SvRV(global_sverr))); |
1b64d24d |
476 | |
477 | void |
478 | WARN(msg) |
479 | char * msg; |
480 | |
481 | CODE: |
90a18d65 |
482 | FCGX_PutS(msg, (FCGX_Stream *) SvIV((SV*) SvRV(global_sverr))); |
1b64d24d |
483 | |
484 | void |
485 | PRINT(stream, ...) |
eede4b76 |
486 | FCGI::Stream stream; |
1b64d24d |
487 | |
488 | PREINIT: |
489 | int n; |
490 | |
491 | CODE: |
492 | for (n = 1; n < items; ++n) { |
493 | STRLEN len; |
494 | register char *tmps = (char *)SvPV(ST(n),len); |
495 | FCGX_PutStr(tmps, len, stream); |
496 | } |
497 | if (SvTRUEx(perl_get_sv("|", FALSE))) |
498 | FCGX_FFlush(stream); |
499 | |
500 | int |
501 | WRITE(stream, bufsv, len, ...) |
eede4b76 |
502 | FCGI::Stream stream; |
1b64d24d |
503 | SV * bufsv; |
504 | int len; |
505 | |
506 | PREINIT: |
507 | int offset; |
508 | char * buf; |
509 | STRLEN blen; |
510 | int n; |
511 | |
512 | CODE: |
513 | offset = (items == 4) ? (int)SvIV(ST(3)) : 0; |
514 | buf = SvPV(bufsv, blen); |
515 | if (offset < 0) offset += blen; |
516 | if (len > blen - offset) |
517 | len = blen - offset; |
518 | if (offset < 0 || offset >= blen || |
519 | (n = FCGX_PutStr(buf+offset, len, stream)) < 0) |
520 | ST(0) = &PL_sv_undef; |
521 | else { |
522 | ST(0) = sv_newmortal(); |
523 | sv_setpvf(ST(0), "%c", n); |
524 | } |
525 | |
526 | int |
527 | READ(stream, bufsv, len, ...) |
eede4b76 |
528 | FCGI::Stream stream; |
1b64d24d |
529 | SV * bufsv; |
530 | int len; |
531 | |
532 | PREINIT: |
533 | int offset; |
534 | char * buf; |
535 | |
536 | CODE: |
537 | offset = (items == 4) ? (int)SvIV(ST(3)) : 0; |
538 | if (! SvOK(bufsv)) |
539 | sv_setpvn(bufsv, "", 0); |
540 | buf = SvGROW(bufsv, len+offset+1); |
541 | len = FCGX_GetStr(buf+offset, len, stream); |
542 | SvCUR_set(bufsv, len+offset); |
543 | *SvEND(bufsv) = '\0'; |
544 | (void)SvPOK_only(bufsv); |
545 | SvSETMAGIC(bufsv); |
546 | RETVAL = len; |
547 | |
548 | OUTPUT: |
549 | RETVAL |
550 | |
551 | SV * |
552 | GETC(stream) |
eede4b76 |
553 | FCGI::Stream stream; |
1b64d24d |
554 | |
555 | PREINIT: |
556 | int retval; |
557 | |
558 | CODE: |
559 | if ((retval = FCGX_GetChar(stream)) != -1) { |
560 | ST(0) = sv_newmortal(); |
561 | sv_setpvf(ST(0), "%c", retval); |
562 | } else ST(0) = &PL_sv_undef; |
563 | |
564 | bool |
565 | CLOSE(stream) |
eede4b76 |
566 | FCGI::Stream stream; |
1b64d24d |
567 | |
568 | ALIAS: |
569 | DESTROY = 1 |
570 | |
571 | CODE: |
572 | RETVAL = FCGX_FClose(stream) != -1; |
573 | |
574 | OUTPUT: |
575 | RETVAL |
576 | |
577 | #endif |