1 /* $Id: FCGI.XL,v 1.10 2003/06/22 00:24:11 robs Exp $ */
7 #include "fcgi_config.h"
24 #define INT2PTR(a,b) ((a) (b))
27 /* Deprecation added 2010-10-05. The deprecated functionality should not be
28 * removed for at least a year after that. */
29 #define WIDE_CHAR_DEPRECATION_MSG "Use of wide characters in %s is deprecated" \
30 " and will stop wprking in a future version of FCGI"
32 #if defined(USE_ITHREADS)
33 static perl_mutex accept_mutex;
36 typedef struct FCGP_Request {
44 FCGX_Request* requestPtr;
47 static void FCGI_Finish(FCGP_Request* request);
50 FCGI_Flush(FCGP_Request* request) {
54 FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->svout))));
55 FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->sverr))));
59 FCGI_UndoBinding(FCGP_Request* request) {
62 sv_unmagic((SV *)GvIOp(request->gv[0]), 'q');
63 sv_unmagic((SV *)GvIOp(request->gv[1]), 'q');
64 sv_unmagic((SV *)GvIOp(request->gv[2]), 'q');
66 sv_unmagic((SV *)request->gv[0], 'q');
67 sv_unmagic((SV *)request->gv[1], 'q');
68 sv_unmagic((SV *)request->gv[2], 'q');
70 request->bound = FALSE;
74 FCGI_Bind(FCGP_Request* request) {
77 /* For tied filehandles, we apply tiedscalar magic to the IO
78 slot of the GP rather than the GV itself. */
80 if (!GvIOp(request->gv[1]))
81 GvIOp(request->gv[1]) = newIO();
82 if (!GvIOp(request->gv[2]))
83 GvIOp(request->gv[2]) = newIO();
84 if (!GvIOp(request->gv[0]))
85 GvIOp(request->gv[0]) = newIO();
87 sv_magic((SV *)GvIOp(request->gv[1]), request->svout, 'q', Nullch, 0);
88 sv_magic((SV *)GvIOp(request->gv[2]), request->sverr, 'q', Nullch, 0);
89 sv_magic((SV *)GvIOp(request->gv[0]), request->svin, 'q', Nullch, 0);
91 sv_magic((SV *)request->gv[1], request->svout, 'q', Nullch, 0);
92 sv_magic((SV *)request->gv[2], request->sverr, 'q', Nullch, 0);
93 sv_magic((SV *)request->gv[0], request->svin, 'q', Nullch, 0);
95 request->bound = TRUE;
99 populate_env(char **envp, HV *hv) {
107 if((p = envp[i]) == NULL)
111 sv = newSVpv(p1 + 1, 0);
112 /* call magic for this value ourselves */
113 hv_store(hv, p, p1 - p, sv, 0);
119 FCGI_IsFastCGI(FCGP_Request* request) {
120 static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: CGI */
122 if (request->requestPtr->listen_sock == FCGI_LISTENSOCK_FILENO) {
124 isCGI = FCGX_IsCGI();
128 /* A explicit socket is being used -> assume FastCGI */
133 FCGI_Accept(FCGP_Request* request) {
136 if (!FCGI_IsFastCGI(request)) {
137 static int been_here = 0;
140 * Not first call to FCGI_Accept and running as CGI means
141 * application is done.
148 FCGX_Request *fcgx_req = request->requestPtr;
151 FCGI_Finish(request);
152 #if defined(USE_ITHREADS)
153 MUTEX_LOCK(&accept_mutex);
155 acceptResult = FCGX_Accept_r(fcgx_req);
156 #if defined(USE_ITHREADS)
157 MUTEX_UNLOCK(&accept_mutex);
159 if(acceptResult < 0) {
163 populate_env(fcgx_req->envp, request->hvEnv);
165 if (!request->svout) {
166 newSVrv(request->svout = newSV(0), "FCGI::Stream");
167 newSVrv(request->sverr = newSV(0), "FCGI::Stream");
168 newSVrv(request->svin = newSV(0), "FCGI::Stream");
170 sv_setiv(SvRV(request->svout), INT2PTR(IV, fcgx_req->out));
171 sv_setiv(SvRV(request->sverr), INT2PTR(IV, fcgx_req->err));
172 sv_setiv(SvRV(request->svin), INT2PTR(IV, fcgx_req->in));
174 request->accepted = TRUE;
180 FCGI_Finish(FCGP_Request* request) {
184 if(!request->accepted)
187 if (was_bound = request->bound)
188 FCGI_UndoBinding(request);
190 FCGX_Finish_r(request->requestPtr);
192 FCGX_Free(request->requestPtr, 1);
193 request->accepted = FALSE;
197 FCGI_StartFilterData(FCGP_Request* request) {
198 return request->requestPtr->in ?
199 FCGX_StartFilterData(request->requestPtr->in) : -1;
202 static FCGP_Request *
203 FCGI_Request(GV *in, GV *out, GV *err, HV *env, int socket, int flags) {
204 FCGX_Request* fcgx_req;
207 Newz(551, fcgx_req, 1, FCGX_Request);
208 FCGX_InitRequest(fcgx_req, socket, flags);
209 Newz(551, req, 1, FCGP_Request);
210 req->requestPtr = fcgx_req;
224 FCGI_Release_Request(FCGP_Request *req) {
225 SvREFCNT_dec(req->gv[0]);
226 SvREFCNT_dec(req->gv[1]);
227 SvREFCNT_dec(req->gv[2]);
228 SvREFCNT_dec(req->hvEnv);
230 Safefree(req->requestPtr);
236 #if defined(USE_ITHREADS)
238 MUTEX_INIT(&accept_mutex);
243 typedef FCGX_Stream* FCGI__Stream;
244 typedef FCGP_Request* FCGI;
248 MODULE = FCGI PACKAGE = FCGI PREFIX = FCGI_
254 RequestX(in, out, err, env, socket, flags)
263 RETVAL = sv_setref_pv(newSV(0), "FCGI",
264 FCGI_Request(in, out, err, env, socket, flags));
269 OpenSocket(path, backlog)
274 RETVAL = FCGX_OpenSocket(path, backlog);
301 GetEnvironment(request)
305 RETVAL = request->hvEnv;
317 for (i = 0; i < 3; ++i)
318 PUSHs(sv_2mortal(newRV((SV *) request->gv[i])));
321 FCGI_IsFastCGI(request)
330 if (request->accepted && request->bound) {
331 FCGI_UndoBinding(request);
332 FCGX_Detach(request->requestPtr);
340 if (request->accepted && !request->bound) {
342 FCGX_Attach(request->requestPtr);
350 FCGX_ShutdownPending();
353 FCGI_StartFilterData(request)
361 FCGI_Release_Request(request);
363 MODULE = FCGI PACKAGE = FCGI::Stream
374 for (n = 1; ok && n < items; ++n) {
376 if (DO_UTF8(ST(n)) && !sv_utf8_downgrade(ST(n), 1) && ckWARN_d(WARN_UTF8))
377 Perl_warner(aTHX_ WARN_UTF8, WIDE_CHAR_DEPRECATION_MSG,
378 "FCGI::Stream::PRINT");
380 str = (char *)SvPV(ST(n),len);
381 if (FCGX_PutStr(str, len, stream) < 0)
384 if (ok && SvTRUEx(perl_get_sv("|", FALSE)) && FCGX_FFlush(stream) < 0)
386 RETVAL = ok ? &PL_sv_yes : &PL_sv_undef;
391 WRITE(stream, bufsv, len, ...)
401 offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
403 if (DO_UTF8(bufsv) && !sv_utf8_downgrade(bufsv, 1) && ckWARN_d(WARN_UTF8))
404 Perl_warner(aTHX_ WARN_UTF8, WIDE_CHAR_DEPRECATION_MSG,
405 "FCGI::Stream::WRITE");
407 buf = SvPV(bufsv, blen);
408 if (offset < 0) offset += blen;
409 if (len > blen - offset)
411 if (offset < 0 || offset >= blen ||
412 (n = FCGX_PutStr(buf+offset, len, stream)) < 0)
413 ST(0) = &PL_sv_undef;
415 ST(0) = sv_newmortal();
420 READ(stream, bufsv, len, ...)
429 if (items < 3 || items > 4)
430 croak("Usage: FCGI::Stream::READ(STREAM, SCALAR, LENGTH [, OFFSET ])");
432 croak("Negative length");
434 sv_setpvn(bufsv, "", 0);
436 if (DO_UTF8(bufsv) && !sv_utf8_downgrade(bufsv, 1) && ckWARN_d(WARN_UTF8))
437 Perl_warner(aTHX_ WARN_UTF8, WIDE_CHAR_DEPRECATION_MSG,
438 "FCGI::Stream::READ");
440 buf = SvPV_force(bufsv, blen);
442 offset = SvIV(ST(3));
444 if (-offset > (int)blen)
445 croak("Offset outside string");
449 buf = SvGROW(bufsv, len + offset + 1);
451 Zero(buf + blen, offset - blen, char);
452 len = FCGX_GetStr(buf + offset, len, stream);
453 SvCUR_set(bufsv, len + offset);
454 *SvEND(bufsv) = '\0';
455 (void)SvPOK_only(bufsv);
465 if ((retval = FCGX_GetChar(stream)) != -1) {
466 ST(0) = sv_newmortal();
467 sv_setpvf(ST(0), "%c", retval);
470 ST(0) = &PL_sv_undef;
473 EOF(stream, called=0)
477 RETVAL = boolSV(FCGX_HasSeenEOF(stream));
485 if (FCGX_HasSeenEOF(stream) != 0)
494 RETVAL = FCGX_FClose(stream) != -1;