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