5 print "Generating FCGI.xs for Perl version $]\n";
6 #unless (exists $Config{apiversion} && $Config{apiversion} >= 5.005)
8 for (qw(sv_undef diehook warnhook in_eval)) {
9 print OUT "#define PL_$_ $_\n"
12 print OUT while <DATA>;
15 /* $Id: FCGI.XL,v 1.10 2003/06/22 00:24:11 robs Exp $ */
21 #include "fcgi_config.h"
38 #define INT2PTR(a,b) ((a) (b))
41 /* Deprecation added 2010-10-05. The deprecated functionality should not be
42 * removed for at least a year after that. */
43 #define WIDE_CHAR_DEPRECATION_MSG "Use of wide characters in %s is deprecated" \
44 " and will stop wprking in a future version of FCGI"
46 #if defined(USE_LOCKING) && defined(USE_THREADS)
47 static perl_mutex accept_mutex;
50 typedef struct FCGP_Request {
58 FCGX_Request* requestPtr;
61 static void FCGI_Finish(FCGP_Request* request);
64 FCGI_Flush(FCGP_Request* request) {
68 FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->svout))));
69 FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->sverr))));
73 FCGI_UndoBinding(FCGP_Request* request) {
76 sv_unmagic((SV *)GvIOp(request->gv[0]), 'q');
77 sv_unmagic((SV *)GvIOp(request->gv[1]), 'q');
78 sv_unmagic((SV *)GvIOp(request->gv[2]), 'q');
80 sv_unmagic((SV *)request->gv[0], 'q');
81 sv_unmagic((SV *)request->gv[1], 'q');
82 sv_unmagic((SV *)request->gv[2], 'q');
84 request->bound = FALSE;
88 FCGI_Bind(FCGP_Request* request) {
91 /* For tied filehandles, we apply tiedscalar magic to the IO
92 slot of the GP rather than the GV itself. */
94 if (!GvIOp(request->gv[1]))
95 GvIOp(request->gv[1]) = newIO();
96 if (!GvIOp(request->gv[2]))
97 GvIOp(request->gv[2]) = newIO();
98 if (!GvIOp(request->gv[0]))
99 GvIOp(request->gv[0]) = newIO();
101 sv_magic((SV *)GvIOp(request->gv[1]), request->svout, 'q', Nullch, 0);
102 sv_magic((SV *)GvIOp(request->gv[2]), request->sverr, 'q', Nullch, 0);
103 sv_magic((SV *)GvIOp(request->gv[0]), request->svin, 'q', Nullch, 0);
105 sv_magic((SV *)request->gv[1], request->svout, 'q', Nullch, 0);
106 sv_magic((SV *)request->gv[2], request->sverr, 'q', Nullch, 0);
107 sv_magic((SV *)request->gv[0], request->svin, 'q', Nullch, 0);
109 request->bound = TRUE;
113 populate_env(char **envp, HV *hv) {
121 if((p = envp[i]) == NULL)
125 sv = newSVpv(p1 + 1, 0);
126 /* call magic for this value ourselves */
127 hv_store(hv, p, p1 - p, sv, 0);
133 FCGI_IsFastCGI(FCGP_Request* request) {
134 static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: CGI */
136 if (request->requestPtr->listen_sock == FCGI_LISTENSOCK_FILENO) {
138 isCGI = FCGX_IsCGI();
142 /* A explicit socket is being used -> assume FastCGI */
147 FCGI_Accept(FCGP_Request* request) {
150 if (!FCGI_IsFastCGI(request)) {
151 static int been_here = 0;
154 * Not first call to FCGI_Accept and running as CGI means
155 * application is done.
162 FCGX_Request *fcgx_req = request->requestPtr;
165 FCGI_Finish(request);
166 #if defined(USE_LOCKING) && defined(USE_THREADS)
167 MUTEX_LOCK(&accept_mutex);
169 acceptResult = FCGX_Accept_r(fcgx_req);
170 #if defined(USE_LOCKING) && defined(USE_THREADS)
171 MUTEX_UNLOCK(&accept_mutex);
173 if(acceptResult < 0) {
177 populate_env(fcgx_req->envp, request->hvEnv);
179 if (!request->svout) {
180 newSVrv(request->svout = newSV(0), "FCGI::Stream");
181 newSVrv(request->sverr = newSV(0), "FCGI::Stream");
182 newSVrv(request->svin = newSV(0), "FCGI::Stream");
184 sv_setiv(SvRV(request->svout), INT2PTR(IV, fcgx_req->out));
185 sv_setiv(SvRV(request->sverr), INT2PTR(IV, fcgx_req->err));
186 sv_setiv(SvRV(request->svin), INT2PTR(IV, fcgx_req->in));
188 request->accepted = TRUE;
194 FCGI_Finish(FCGP_Request* request) {
198 if(!request->accepted)
201 if (was_bound = request->bound)
202 FCGI_UndoBinding(request);
204 FCGX_Finish_r(request->requestPtr);
206 FCGX_Free(request->requestPtr, 1);
207 request->accepted = FALSE;
211 FCGI_StartFilterData(FCGP_Request* request) {
212 return request->requestPtr->in ?
213 FCGX_StartFilterData(request->requestPtr->in) : -1;
216 static FCGP_Request *
217 FCGI_Request(GV *in, GV *out, GV *err, HV *env, int socket, int flags) {
218 FCGX_Request* fcgx_req;
221 Newz(551, fcgx_req, 1, FCGX_Request);
222 FCGX_InitRequest(fcgx_req, socket, flags);
223 Newz(551, req, 1, FCGP_Request);
224 req->requestPtr = fcgx_req;
238 FCGI_Release_Request(FCGP_Request *req) {
239 SvREFCNT_dec(req->gv[0]);
240 SvREFCNT_dec(req->gv[1]);
241 SvREFCNT_dec(req->gv[2]);
242 SvREFCNT_dec(req->hvEnv);
244 Safefree(req->requestPtr);
250 #if defined(USE_LOCKING) && defined(USE_THREADS)
252 MUTEX_INIT(&accept_mutex);
257 typedef FCGX_Stream* FCGI__Stream;
258 typedef FCGP_Request* FCGI;
262 MODULE = FCGI PACKAGE = FCGI PREFIX = FCGI_
268 RequestX(in, out, err, env, socket, flags)
277 RETVAL = sv_setref_pv(newSV(0), "FCGI",
278 FCGI_Request(in, out, err, env, socket, flags));
283 OpenSocket(path, backlog)
288 RETVAL = FCGX_OpenSocket(path, backlog);
315 GetEnvironment(request)
319 RETVAL = request->hvEnv;
331 for (i = 0; i < 3; ++i)
332 PUSHs(sv_2mortal(newRV((SV *) request->gv[i])));
335 FCGI_IsFastCGI(request)
344 if (request->accepted && request->bound) {
345 FCGI_UndoBinding(request);
346 FCGX_Detach(request->requestPtr);
354 if (request->accepted && !request->bound) {
356 FCGX_Attach(request->requestPtr);
364 FCGX_ShutdownPending();
367 FCGI_StartFilterData(request)
375 FCGI_Release_Request(request);
377 MODULE = FCGI PACKAGE = FCGI::Stream
388 for (n = 1; ok && n < items; ++n) {
390 if (DO_UTF8(ST(n)) && !sv_utf8_downgrade(ST(n), 1) && ckWARN_d(WARN_UTF8))
391 Perl_warner(aTHX_ WARN_UTF8, WIDE_CHAR_DEPRECATION_MSG,
392 "FCGI::Stream::PRINT");
394 str = (char *)SvPV(ST(n),len);
395 if (FCGX_PutStr(str, len, stream) < 0)
398 if (ok && SvTRUEx(perl_get_sv("|", FALSE)) && FCGX_FFlush(stream) < 0)
400 RETVAL = ok ? &PL_sv_yes : &PL_sv_undef;
405 WRITE(stream, bufsv, len, ...)
415 offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
417 if (DO_UTF8(bufsv) && !sv_utf8_downgrade(bufsv, 1) && ckWARN_d(WARN_UTF8))
418 Perl_warner(aTHX_ WARN_UTF8, WIDE_CHAR_DEPRECATION_MSG,
419 "FCGI::Stream::WRITE");
421 buf = SvPV(bufsv, blen);
422 if (offset < 0) offset += blen;
423 if (len > blen - offset)
425 if (offset < 0 || offset >= blen ||
426 (n = FCGX_PutStr(buf+offset, len, stream)) < 0)
427 ST(0) = &PL_sv_undef;
429 ST(0) = sv_newmortal();
434 READ(stream, bufsv, len, ...)
443 if (items < 3 || items > 4)
444 croak("Usage: FCGI::Stream::READ(STREAM, SCALAR, LENGTH [, OFFSET ])");
446 croak("Negative length");
448 sv_setpvn(bufsv, "", 0);
450 if (DO_UTF8(bufsv) && !sv_utf8_downgrade(bufsv, 1) && ckWARN_d(WARN_UTF8))
451 Perl_warner(aTHX_ WARN_UTF8, WIDE_CHAR_DEPRECATION_MSG,
452 "FCGI::Stream::READ");
454 buf = SvPV_force(bufsv, blen);
456 offset = SvIV(ST(3));
458 if (-offset > (int)blen)
459 croak("Offset outside string");
463 buf = SvGROW(bufsv, len + offset + 1);
465 Zero(buf + blen, offset - blen, char);
466 len = FCGX_GetStr(buf + offset, len, stream);
467 SvCUR_set(bufsv, len + offset);
468 *SvEND(bufsv) = '\0';
469 (void)SvPOK_only(bufsv);
479 if ((retval = FCGX_GetChar(stream)) != -1) {
480 ST(0) = sv_newmortal();
481 sv_setpvf(ST(0), "%c", retval);
484 ST(0) = &PL_sv_undef;
490 RETVAL = FCGX_FClose(stream) != -1;