Apply patch from RT#57697
[catagits/fcgi2.git] / perl / FCGI.XL
CommitLineData
0833402a 1use Config;
2
3open OUT, ">FCGI.xs";
4
5print "Generating FCGI.xs for Perl version $]\n";
6#unless (exists $Config{apiversion} && $Config{apiversion} >= 5.005)
7unless ($] >= 5.005) {
8 for (qw(sv_undef diehook warnhook in_eval)) {
9 print OUT "#define PL_$_ $_\n"
10 }
11}
12print OUT while <DATA>;
13close OUT;
14__END__
fdee298f 15/* $Id: FCGI.XL,v 1.10 2003/06/22 00:24:11 robs Exp $ */
0833402a 16
17#include "EXTERN.h"
18#include "perl.h"
19#include "XSUB.h"
20
21#include "fcgi_config.h"
22#include "fcgiapp.h"
23#include "fastcgi.h"
24
25#ifndef FALSE
26#define FALSE (0)
27#endif
28
29#ifndef TRUE
30#define TRUE (1)
31#endif
32
33#ifndef dTHX
34#define dTHX
35#endif
36
0c1fdec9 37#ifndef INT2PTR
38#define INT2PTR(a,b) ((a) (b))
39#endif
40
0833402a 41#ifdef USE_SFIO
42typedef struct
43{
44 Sfdisc_t disc;
45 FCGX_Stream *stream;
46} FCGI_Disc;
47
48static ssize_t
49sffcgiread(f, buf, n, disc)
50Sfio_t* f; /* stream involved */
51Void_t* buf; /* buffer to read into */
52size_t n; /* number of bytes to read */
53Sfdisc_t* disc; /* discipline */
54{
55 return FCGX_GetStr(buf, n, ((FCGI_Disc *)disc)->stream);
56}
57
58static ssize_t
59sffcgiwrite(f, buf, n, disc)
60Sfio_t* f; /* stream involved */
61const Void_t* buf; /* buffer to read into */
62size_t n; /* number of bytes to read */
63Sfdisc_t* disc; /* discipline */
64{
65 n = FCGX_PutStr(buf, n, ((FCGI_Disc *)disc)->stream);
66 FCGX_FFlush(((FCGI_Disc *)disc)->stream);
67 return n;
68}
69
70Sfdisc_t *
71sfdcnewfcgi(stream)
72 FCGX_Stream *stream;
73{
74 FCGI_Disc* disc;
75
76 New(1000,disc,1,FCGI_Disc);
77 if (!disc) return (Sfdisc_t *)disc;
78
79 disc->disc.exceptf = (Sfexcept_f)NULL;
80 disc->disc.seekf = (Sfseek_f)NULL;
81 disc->disc.readf = sffcgiread;
82 disc->disc.writef = sffcgiwrite;
83 disc->stream = stream;
84 return (Sfdisc_t *)disc;
85}
86
87Sfdisc_t *
88sfdcdelfcgi(disc)
89 Sfdisc_t* disc;
90{
91 Safefree(disc);
92 return 0;
93}
94#endif
95
96#if defined(USE_LOCKING) && defined(USE_THREADS)
97static perl_mutex accept_mutex;
98#endif
99
100typedef struct FCGP_Request {
101 int accepted;
102 int bound;
103 SV* svin;
104 SV* svout;
105 SV* sverr;
106 GV* gv[3];
107 HV* hvEnv;
108 FCGX_Request* requestPtr;
109#ifdef USE_SFIO
110 int sfcreated[3];
111 IO* io[3];
112#endif
113} FCGP_Request;
114
115static void FCGI_Finish(FCGP_Request* request);
116
9b60732b 117static void
0833402a 118FCGI_Flush(FCGP_Request* request)
119{
120 dTHX;
121
122 if(!request->bound) {
123 return;
9b60732b 124 }
0833402a 125#ifdef USE_SFIO
126 sfsync(IoOFP(GvIOp(request->gv[1])));
127 sfsync(IoOFP(GvIOp(request->gv[2])));
128#else
9c31872c 129 FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->svout))));
130 FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->sverr))));
0833402a 131#endif
132}
133
134static void
135FCGI_UndoBinding(FCGP_Request* request)
136{
137 dTHX;
138
139#ifdef USE_SFIO
140 sfdcdelfcgi(sfdisc(IoIFP(request->io[0]), SF_POPDISC));
141 sfdcdelfcgi(sfdisc(IoOFP(request->io[1]), SF_POPDISC));
142 sfdcdelfcgi(sfdisc(IoOFP(request->io[2]), SF_POPDISC));
143#else
849cab1e 144# ifdef USE_PERLIO
145 sv_unmagic((SV *)GvIOp(request->gv[0]), 'q');
146 sv_unmagic((SV *)GvIOp(request->gv[1]), 'q');
147 sv_unmagic((SV *)GvIOp(request->gv[2]), 'q');
148# else
0833402a 149 sv_unmagic((SV *)request->gv[0], 'q');
150 sv_unmagic((SV *)request->gv[1], 'q');
151 sv_unmagic((SV *)request->gv[2], 'q');
849cab1e 152# endif
0833402a 153#endif
154 request->bound = FALSE;
155}
156
157static void
158FCGI_Bind(FCGP_Request* request)
159{
160 dTHX;
161
162#ifdef USE_SFIO
163 sfdisc(IoIFP(request->io[0]), sfdcnewfcgi(request->requestPtr->in));
164 sfdisc(IoOFP(request->io[1]), sfdcnewfcgi(request->requestPtr->out));
165 sfdisc(IoOFP(request->io[2]), sfdcnewfcgi(request->requestPtr->err));
166#else
6d7e3fb2 167# ifdef USE_PERLIO
168 /* For tied filehandles, we apply tiedscalar magic to the IO
169 slot of the GP rather than the GV itself. */
170
171 if (!GvIOp(request->gv[1]))
172 GvIOp(request->gv[1]) = newIO();
173 if (!GvIOp(request->gv[2]))
174 GvIOp(request->gv[2]) = newIO();
175 if (!GvIOp(request->gv[0]))
176 GvIOp(request->gv[0]) = newIO();
177
178 sv_magic((SV *)GvIOp(request->gv[1]), request->svout, 'q', Nullch, 0);
179 sv_magic((SV *)GvIOp(request->gv[2]), request->sverr, 'q', Nullch, 0);
180 sv_magic((SV *)GvIOp(request->gv[0]), request->svin, 'q', Nullch, 0);
181# else
0833402a 182 sv_magic((SV *)request->gv[1], request->svout, 'q', Nullch, 0);
183 sv_magic((SV *)request->gv[2], request->sverr, 'q', Nullch, 0);
184 sv_magic((SV *)request->gv[0], request->svin, 'q', Nullch, 0);
6d7e3fb2 185# endif
0833402a 186#endif
187 request->bound = TRUE;
188}
189
190static void
191populate_env(envp, hv)
192char **envp;
193HV *hv;
194{
195 int i;
196 char *p, *p1;
197 SV *sv;
198 dTHX;
199
200 hv_clear(hv);
201 for(i = 0; ; i++) {
202 if((p = envp[i]) == NULL) {
203 break;
204 }
205 p1 = strchr(p, '=');
206 assert(p1 != NULL);
207 sv = newSVpv(p1 + 1, 0);
208 /* call magic for this value ourselves */
209 hv_store(hv, p, p1 - p, sv, 0);
210 SvSETMAGIC(sv);
211 }
212}
213
214static int
215FCGI_IsFastCGI(FCGP_Request* request)
216{
217 static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: CGI */
218
219 if (request->requestPtr->listen_sock == FCGI_LISTENSOCK_FILENO) {
220 if (isCGI == -1)
221 isCGI = FCGX_IsCGI();
222 return !isCGI;
223 }
224
225 /* A explicit socket is being used -> assume FastCGI */
226 return 1;
227}
228
229static int
230FCGI_Accept(FCGP_Request* request)
231{
232 dTHX;
233
234 if (!FCGI_IsFastCGI(request)) {
235 static int been_here = 0;
236
237 /*
238 * Not first call to FCGI_Accept and running as CGI means
239 * application is done.
240 */
241 if (been_here)
242 return EOF;
243
244 been_here = 1;
245 } else {
246#ifdef USE_SFIO
247 int i;
248#endif
249 FCGX_Request *fcgx_req = request->requestPtr;
250 int acceptResult;
251
252 FCGI_Finish(request);
253#if defined(USE_LOCKING) && defined(USE_THREADS)
254 MUTEX_LOCK(&accept_mutex);
255#endif
256 acceptResult = FCGX_Accept_r(fcgx_req);
257#if defined(USE_LOCKING) && defined(USE_THREADS)
258 MUTEX_UNLOCK(&accept_mutex);
259#endif
260 if(acceptResult < 0) {
261 return acceptResult;
262 }
263
264 populate_env(fcgx_req->envp, request->hvEnv);
265
266#ifdef USE_SFIO
267 for (i = 0; i < 3; ++i) {
268 request->io[i] = GvIOn(request->gv[i]);
269 if (!(i == 0 ? IoIFP(request->io[i])
270 : IoOFP(request->io[i]))) {
271 IoIFP(request->io[i]) = sftmp(0);
272 /*IoIFP(request->io[i]) = sfnew(NULL, NULL, SF_UNBOUND, 0,
273 SF_STRING | (i ? SF_WRITE : SF_READ));*/
274 if (i != 0)
275 IoOFP(request->io[i]) = IoIFP(request->io[i]);
276 request->sfcreated[i] = TRUE;
277 }
278 }
279#else
280 if (!request->svout) {
281 newSVrv(request->svout = newSV(0), "FCGI::Stream");
282 newSVrv(request->sverr = newSV(0), "FCGI::Stream");
283 newSVrv(request->svin = newSV(0), "FCGI::Stream");
284 }
9c31872c 285 sv_setiv(SvRV(request->svout), INT2PTR(IV, fcgx_req->out));
286 sv_setiv(SvRV(request->sverr), INT2PTR(IV, fcgx_req->err));
287 sv_setiv(SvRV(request->svin), INT2PTR(IV, fcgx_req->in));
0833402a 288#endif
289 FCGI_Bind(request);
290 request->accepted = TRUE;
291 }
292 return 0;
293}
294
295static void
296FCGI_Finish(FCGP_Request* request)
297{
298#ifdef USE_SFIO
299 int i;
300#endif
301 int was_bound;
302 dTHX;
303
304 if(!request->accepted) {
305 return;
306 }
307
308 if (was_bound = request->bound) {
309 FCGI_UndoBinding(request);
310 }
311#ifdef USE_SFIO
312 for (i = 0; i < 3; ++i) {
313 if (request->sfcreated[i]) {
314 sfclose(IoIFP(request->io[i]));
315 IoIFP(request->io[i]) = IoOFP(request->io[i]) = Nullfp;
316 request->sfcreated[i] = FALSE;
317 }
318 }
319#endif
320 if (was_bound)
321 FCGX_Finish_r(request->requestPtr);
322 else
bef7e0fc 323 FCGX_Free(request->requestPtr, 1);
0833402a 324 request->accepted = FALSE;
325}
326
327static int
328FCGI_StartFilterData(FCGP_Request* request)
329{
330 return request->requestPtr->in ?
331 FCGX_StartFilterData(request->requestPtr->in) : -1;
332}
333
334static FCGP_Request *
335FCGI_Request(in, out, err, env, socket, flags)
336 GV* in;
337 GV* out;
338 GV* err;
339 HV* env;
340 int socket;
341 int flags;
342{
343 FCGX_Request* fcgx_req;
344 FCGP_Request* req;
345
346 Newz(551, fcgx_req, 1, FCGX_Request);
347 FCGX_InitRequest(fcgx_req, socket, flags);
348 Newz(551, req, 1, FCGP_Request);
349 req->requestPtr = fcgx_req;
a6b22a6e 350 SvREFCNT_inc(in);
0833402a 351 req->gv[0] = in;
a6b22a6e 352 SvREFCNT_inc(out);
0833402a 353 req->gv[1] = out;
a6b22a6e 354 SvREFCNT_inc(err);
0833402a 355 req->gv[2] = err;
a6b22a6e 356 SvREFCNT_inc(env);
0833402a 357 req->hvEnv = env;
358
359 return req;
360}
361
362static void
363FCGI_Release_Request(FCGP_Request *req)
364{
a6b22a6e 365 SvREFCNT_dec(req->gv[0]);
366 SvREFCNT_dec(req->gv[1]);
367 SvREFCNT_dec(req->gv[2]);
368 SvREFCNT_dec(req->hvEnv);
0833402a 369 FCGI_Finish(req);
370 Safefree(req->requestPtr);
371 Safefree(req);
372}
373
374static void
375FCGI_Init()
376{
377#if defined(USE_LOCKING) && defined(USE_THREADS)
378 dTHX;
379
380 MUTEX_INIT(&accept_mutex);
381#endif
382
383 FCGX_Init();
384}
385
386typedef FCGX_Stream * FCGI__Stream;
387typedef FCGP_Request * FCGI;
388typedef GV* GLOBREF;
389typedef HV* HASHREF;
390
391MODULE = FCGI PACKAGE = FCGI PREFIX = FCGI_
392
393BOOT:
394 FCGI_Init();
395
396SV *
397RequestX(in, out, err, env, socket, flags)
398 GLOBREF in;
399 GLOBREF out;
400 GLOBREF err;
401 HASHREF env;
402 int socket;
403 int flags;
404
405 PROTOTYPE: ***$$$
406 CODE:
407 RETVAL = sv_setref_pv(newSV(0), "FCGI",
408 FCGI_Request(in, out, err, env, socket, flags));
409
410 OUTPUT:
411 RETVAL
412
413int
414OpenSocket(path, backlog)
415 char* path;
416 int backlog;
417
418 PROTOTYPE: $$
419 CODE:
420 RETVAL = FCGX_OpenSocket(path, backlog);
421 OUTPUT:
422 RETVAL
423
424void
425CloseSocket(socket)
426 int socket;
427
428 PROTOTYPE: $
429 CODE:
430 close(socket);
431
432int
433FCGI_Accept(request)
434
435 FCGI request;
436
437 PROTOTYPE: $
438
439void
440FCGI_Finish(request)
441 FCGI request;
442
443 PROTOTYPE: $
444
445void
446FCGI_Flush(request)
447 FCGI request;
448
449 PROTOTYPE: $
450
451HV *
452GetEnvironment(request)
453 FCGI request;
454
455 PROTOTYPE: $
456
457 CODE:
458 RETVAL = request->hvEnv;
459
460 OUTPUT:
461 RETVAL
462
463void
464GetHandles(request)
465 FCGI request;
466
467 PROTOTYPE: $
468
469 PREINIT:
470 int i;
471
472 PPCODE:
473 EXTEND(sp,3);
474 for (i = 0; i < 3; ++i)
475 PUSHs(sv_2mortal(newRV((SV *) request->gv[i])));
476
477int
478FCGI_IsFastCGI(request)
479 FCGI request;
480
481 PROTOTYPE: $
482
483void
484Detach(request)
0833402a 485 FCGI request;
486
487 PROTOTYPE: $
488
489 CODE:
fdee298f 490 if (request->accepted && request->bound) {
491 FCGI_UndoBinding(request);
492 FCGX_Detach(request->requestPtr);
493 }
0833402a 494
495void
496Attach(request)
0833402a 497 FCGI request;
498
499 PROTOTYPE: $
500
501 CODE:
fdee298f 502 if (request->accepted && !request->bound) {
503 FCGI_Bind(request);
504 FCGX_Attach(request->requestPtr);
505 }
0833402a 506
7fa2de73 507void
508LastCall(request)
509 FCGI request;
510
511 PROTOTYPE: $
512
513 CODE:
514 FCGX_ShutdownPending();
0833402a 515
516int
517FCGI_StartFilterData(request)
518
519 FCGI request;
520
521 PROTOTYPE: $
522
523void
524DESTROY(request)
525 FCGI request;
526
527 CODE:
528 FCGI_Release_Request(request);
529
530
531
532MODULE = FCGI PACKAGE = FCGI::Stream
533
534#ifndef USE_SFIO
535
cd90e76f 536SV *
0833402a 537PRINT(stream, ...)
538 FCGI::Stream stream;
539
540 PREINIT:
cd90e76f 541 int n;
2f33e704 542 STRLEN len;
543 register char *str;
cd90e76f 544 bool ok = TRUE;
0833402a 545
546 CODE:
cd90e76f 547 for (n = 1; ok && n < items; ++n) {
c9234f83 548#ifdef DO_UTF8
cd90e76f 549 if (DO_UTF8(ST(n)) && !sv_utf8_downgrade(ST(n), 1))
550 croak("Wide character in FCGI::Stream::PRINT");
c9234f83 551#endif
2f33e704 552 str = (char *)SvPV(ST(n),len);
cd90e76f 553 if (FCGX_PutStr(str, len, stream) < 0)
554 ok = FALSE;
29829dde 555 }
29829dde 556
cd90e76f 557 if (ok && SvTRUEx(perl_get_sv("|", FALSE)) && FCGX_FFlush(stream) < 0)
558 ok = FALSE;
2f33e704 559
cd90e76f 560 RETVAL = ok ? &PL_sv_yes : &PL_sv_undef;
9a03f456 561 OUTPUT:
562 RETVAL
0833402a 563
564int
565WRITE(stream, bufsv, len, ...)
566 FCGI::Stream stream;
567 SV * bufsv;
568 int len;
569
570 PREINIT:
571 int offset;
572 char * buf;
573 STRLEN blen;
574 int n;
575
576 CODE:
577 offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
c9234f83 578#ifdef DO_UTF8
579 if (DO_UTF8(bufsv) && !sv_utf8_downgrade(bufsv, 1))
580 croak("Wide character in FCGI::Stream::WRITE");
581#endif
0833402a 582 buf = SvPV(bufsv, blen);
583 if (offset < 0) offset += blen;
584 if (len > blen - offset)
585 len = blen - offset;
586 if (offset < 0 || offset >= blen ||
587 (n = FCGX_PutStr(buf+offset, len, stream)) < 0)
588 ST(0) = &PL_sv_undef;
589 else {
590 ST(0) = sv_newmortal();
c9234f83 591 sv_setiv(ST(0), n);
0833402a 592 }
593
594int
595READ(stream, bufsv, len, ...)
596 FCGI::Stream stream;
597 SV * bufsv;
598 int len;
599
600 PREINIT:
601 int offset;
602 char * buf;
603
604 CODE:
605 offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
c9234f83 606#ifdef DO_UTF8
607 if (DO_UTF8(bufsv) && !sv_utf8_downgrade(bufsv, 1))
608 croak("Wide character in FCGI::Stream::READ");
609#endif
0833402a 610 if (! SvOK(bufsv))
611 sv_setpvn(bufsv, "", 0);
612 buf = SvGROW(bufsv, len+offset+1);
613 len = FCGX_GetStr(buf+offset, len, stream);
614 SvCUR_set(bufsv, len+offset);
615 *SvEND(bufsv) = '\0';
616 (void)SvPOK_only(bufsv);
617 SvSETMAGIC(bufsv);
618 RETVAL = len;
619
620 OUTPUT:
621 RETVAL
622
623SV *
624GETC(stream)
625 FCGI::Stream stream;
626
627 PREINIT:
628 int retval;
629
630 CODE:
631 if ((retval = FCGX_GetChar(stream)) != -1) {
632 ST(0) = sv_newmortal();
633 sv_setpvf(ST(0), "%c", retval);
634 } else ST(0) = &PL_sv_undef;
635
636bool
637CLOSE(stream)
638 FCGI::Stream stream;
639
640# ALIAS:
641# DESTROY = 1
642
643 CODE:
644 RETVAL = FCGX_FClose(stream) != -1;
645
646 OUTPUT:
647 RETVAL
648
649#endif