File Coverage

FCGI.xs
Criterion Covered Total %
statement 92 171 53.8
branch 28 178 15.7
condition n/a
subroutine n/a
pod n/a
total 120 349 34.3


line stmt bran cond sub pod time code
1             /* $Id: FCGI.XL,v 1.10 2003/06/22 00:24:11 robs Exp $ */
2              
3             #include "EXTERN.h"
4             #include "perl.h"
5             #include "XSUB.h"
6              
7             #include "fcgi_config.h"
8             #include "fcgiapp.h"
9             #include "fastcgi.h"
10              
11             #ifndef FALSE
12             #define FALSE (0)
13             #endif
14              
15             #ifndef TRUE
16             #define TRUE (1)
17             #endif
18              
19             #ifndef dTHX
20             #define dTHX
21             #endif
22              
23             #ifndef INT2PTR
24             #define INT2PTR(a,b) ((a) (b))
25             #endif
26              
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 working in a future version of FCGI"
31              
32             #if defined(USE_ITHREADS)
33             static perl_mutex accept_mutex;
34             #endif
35              
36             typedef struct FCGP_Request {
37             int accepted;
38             int bound;
39             SV* svin;
40             SV* svout;
41             SV* sverr;
42             GV* gv[3];
43             HV* hvEnv;
44             FCGX_Request* requestPtr;
45             } FCGP_Request;
46              
47             static void FCGI_Finish(FCGP_Request* request);
48              
49             static void
50 0           FCGI_Flush(FCGP_Request* request) {
51             dTHX;
52 0 0         if(!request->bound)
53 0           return;
54 0 0         FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->svout))));
55 0 0         FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->sverr))));
56             }
57              
58             static void
59 2           FCGI_UndoBinding(FCGP_Request* request) {
60             dTHX;
61             #ifdef USE_PERLIO
62 2           sv_unmagic((SV *)GvIOp(request->gv[0]), 'q');
63 2           sv_unmagic((SV *)GvIOp(request->gv[1]), 'q');
64 2           sv_unmagic((SV *)GvIOp(request->gv[2]), 'q');
65             #else
66             sv_unmagic((SV *)request->gv[0], 'q');
67             sv_unmagic((SV *)request->gv[1], 'q');
68             sv_unmagic((SV *)request->gv[2], 'q');
69             #endif
70 2           request->bound = FALSE;
71 2           }
72              
73             static void
74 2           FCGI_Bind(FCGP_Request* request) {
75             dTHX;
76             #ifdef USE_PERLIO
77             /* For tied filehandles, we apply tiedscalar magic to the IO
78             slot of the GP rather than the GV itself. */
79              
80 2 50         if (!GvIOp(request->gv[1]))
81 0           GvIOp(request->gv[1]) = newIO();
82 2 50         if (!GvIOp(request->gv[2]))
83 0           GvIOp(request->gv[2]) = newIO();
84 2 50         if (!GvIOp(request->gv[0]))
85 0           GvIOp(request->gv[0]) = newIO();
86              
87 2           sv_magic((SV *)GvIOp(request->gv[1]), request->svout, 'q', Nullch, 0);
88 2           sv_magic((SV *)GvIOp(request->gv[2]), request->sverr, 'q', Nullch, 0);
89 2           sv_magic((SV *)GvIOp(request->gv[0]), request->svin, 'q', Nullch, 0);
90             #else
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);
94             #endif
95 2           request->bound = TRUE;
96 2           }
97              
98             static void
99 2           populate_env(char **envp, HV *hv) {
100             int i;
101             char *p, *p1;
102             SV *sv;
103             dTHX;
104              
105 2           hv_clear(hv);
106 2           for(i = 0; ; i++) {
107 6 100         if((p = envp[i]) == NULL)
108 2           break;
109 4           p1 = strchr(p, '=');
110             assert(p1 != NULL);
111 4           sv = newSVpv(p1 + 1, 0);
112             /* call magic for this value ourselves */
113 4           hv_store(hv, p, p1 - p, sv, 0);
114 4 50         SvSETMAGIC(sv);
115 4           }
116 2           }
117              
118             static int
119 2           FCGI_IsFastCGI(FCGP_Request* request) {
120             static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: CGI */
121              
122 2 50         if (request->requestPtr->listen_sock == FCGI_LISTENSOCK_FILENO) {
123 0 0         if (isCGI == -1)
124 0           isCGI = FCGX_IsCGI();
125 0           return !isCGI;
126             }
127              
128             /* A explicit socket is being used -> assume FastCGI */
129 2           return 1;
130             }
131              
132             static int
133 2           FCGI_Accept(FCGP_Request* request) {
134             dTHX;
135              
136 2 50         if (!FCGI_IsFastCGI(request)) {
137             static int been_here = 0;
138              
139             /*
140             * Not first call to FCGI_Accept and running as CGI means
141             * application is done.
142             */
143 0 0         if (been_here)
144 0           return EOF;
145 0           been_here = 1;
146             }
147             else {
148 2           FCGX_Request *fcgx_req = request->requestPtr;
149             int acceptResult;
150              
151 2           FCGI_Finish(request);
152             #if defined(USE_ITHREADS)
153             MUTEX_LOCK(&accept_mutex);
154             #endif
155 2           acceptResult = FCGX_Accept_r(fcgx_req);
156             #if defined(USE_ITHREADS)
157             MUTEX_UNLOCK(&accept_mutex);
158             #endif
159 2 50         if(acceptResult < 0) {
160 0           return acceptResult;
161             }
162              
163 2           populate_env(fcgx_req->envp, request->hvEnv);
164              
165 2 100         if (!request->svout) {
166 1           newSVrv(request->svout = newSV(0), "FCGI::Stream");
167 1           newSVrv(request->sverr = newSV(0), "FCGI::Stream");
168 1           newSVrv(request->svin = newSV(0), "FCGI::Stream");
169             }
170 2           sv_setiv(SvRV(request->svout), INT2PTR(IV, fcgx_req->out));
171 2           sv_setiv(SvRV(request->sverr), INT2PTR(IV, fcgx_req->err));
172 2           sv_setiv(SvRV(request->svin), INT2PTR(IV, fcgx_req->in));
173 2           FCGI_Bind(request);
174 2           request->accepted = TRUE;
175             }
176 2           return 0;
177             }
178              
179             static void
180 3           FCGI_Finish(FCGP_Request* request) {
181             int was_bound;
182             dTHX;
183              
184 3 100         if(!request->accepted)
185 1           return;
186              
187 2 50         if (was_bound = request->bound)
188 2           FCGI_UndoBinding(request);
189 2 50         if (was_bound)
190 2           FCGX_Finish_r(request->requestPtr);
191             else
192 0           FCGX_Free(request->requestPtr, 1);
193 2           request->accepted = FALSE;
194             }
195              
196             static int
197 0           FCGI_StartFilterData(FCGP_Request* request) {
198 0           return request->requestPtr->in ?
199 0 0         FCGX_StartFilterData(request->requestPtr->in) : -1;
200             }
201              
202             static FCGP_Request *
203 1           FCGI_Request(GV *in, GV *out, GV *err, HV *env, int socket, int flags) {
204             FCGX_Request* fcgx_req;
205             FCGP_Request* req;
206              
207 1           Newz(551, fcgx_req, 1, FCGX_Request);
208 1           FCGX_InitRequest(fcgx_req, socket, flags);
209 1           Newz(551, req, 1, FCGP_Request);
210 1           req->requestPtr = fcgx_req;
211 1           SvREFCNT_inc(in);
212 1           req->gv[0] = in;
213 1           SvREFCNT_inc(out);
214 1           req->gv[1] = out;
215 1           SvREFCNT_inc(err);
216 1           req->gv[2] = err;
217 1           SvREFCNT_inc(env);
218 1           req->hvEnv = env;
219              
220 1           return req;
221             }
222              
223             static void
224 1           FCGI_Release_Request(FCGP_Request *req) {
225 1           SvREFCNT_dec(req->gv[0]);
226 1           SvREFCNT_dec(req->gv[1]);
227 1           SvREFCNT_dec(req->gv[2]);
228 1           SvREFCNT_dec(req->hvEnv);
229 1           FCGI_Finish(req);
230 1           Safefree(req->requestPtr);
231 1           Safefree(req);
232 1           }
233              
234             static void
235 3           FCGI_Init() {
236             #if defined(USE_ITHREADS)
237             dTHX;
238             MUTEX_INIT(&accept_mutex);
239             #endif
240 3           FCGX_Init();
241 3           }
242              
243             typedef FCGX_Stream* FCGI__Stream;
244             typedef FCGP_Request* FCGI;
245             typedef GV* GLOBREF;
246             typedef HV* HASHREF;
247              
248             MODULE = FCGI PACKAGE = FCGI PREFIX = FCGI_
249              
250             BOOT:
251 3           FCGI_Init();
252              
253             SV *
254             RequestX(in, out, err, env, socket, flags)
255             GLOBREF in;
256             GLOBREF out;
257             GLOBREF err;
258             HASHREF env;
259             int socket;
260             int flags;
261             PROTOTYPE: ***$$$
262             CODE:
263 1           RETVAL = sv_setref_pv(newSV(0), "FCGI",
264             FCGI_Request(in, out, err, env, socket, flags));
265             OUTPUT:
266             RETVAL
267              
268             int
269             OpenSocket(path, backlog)
270             char* path;
271             int backlog;
272             PROTOTYPE: $$
273             CODE:
274 2           RETVAL = FCGX_OpenSocket(path, backlog);
275             OUTPUT:
276             RETVAL
277              
278             void
279             CloseSocket(socket)
280             int socket;
281             PROTOTYPE: $
282             CODE:
283 1           close(socket);
284              
285             int
286             FCGI_Accept(request)
287             FCGI request;
288             PROTOTYPE: $
289              
290             void
291             FCGI_Finish(request)
292             FCGI request;
293             PROTOTYPE: $
294              
295             void
296             FCGI_Flush(request)
297             FCGI request;
298             PROTOTYPE: $
299              
300             HV *
301             GetEnvironment(request)
302             FCGI request;
303             PROTOTYPE: $
304             CODE:
305 0           RETVAL = request->hvEnv;
306             OUTPUT:
307             RETVAL
308              
309             void
310             GetHandles(request)
311             FCGI request;
312             PROTOTYPE: $
313             PREINIT:
314             int i;
315             PPCODE:
316 0 0         EXTEND(sp,3);
317 0 0         for (i = 0; i < 3; ++i)
318 0           PUSHs(sv_2mortal(newRV((SV *) request->gv[i])));
319              
320             int
321             FCGI_IsFastCGI(request)
322             FCGI request;
323             PROTOTYPE: $
324              
325             void
326             Detach(request)
327             FCGI request;
328             PROTOTYPE: $
329             CODE:
330 0 0         if (request->accepted && request->bound) {
    0          
331 0           FCGI_UndoBinding(request);
332 0           FCGX_Detach(request->requestPtr);
333             }
334              
335             void
336             Attach(request)
337             FCGI request;
338             PROTOTYPE: $
339             CODE:
340 0 0         if (request->accepted && !request->bound) {
    0          
341 0           FCGI_Bind(request);
342 0           FCGX_Attach(request->requestPtr);
343             }
344              
345             void
346             LastCall(request)
347             FCGI request;
348             PROTOTYPE: $
349             CODE:
350 0           FCGX_ShutdownPending();
351              
352             int
353             FCGI_StartFilterData(request)
354             FCGI request;
355             PROTOTYPE: $
356              
357             void
358             DESTROY(request)
359             FCGI request;
360             CODE:
361 1           FCGI_Release_Request(request);
362              
363             MODULE = FCGI PACKAGE = FCGI::Stream
364              
365             SV *
366             PRINT(stream, ...)
367             FCGI::Stream stream;
368             PREINIT:
369             int n;
370             STRLEN len;
371             register char *str;
372 4           bool ok = TRUE;
373             CODE:
374 8 50         for (n = 1; ok && n < items; ++n) {
    100          
375             #ifdef DO_UTF8
376 4 50         if (DO_UTF8(ST(n)) && !sv_utf8_downgrade(ST(n), 1) && ckWARN_d(WARN_UTF8))
    0          
    0          
    0          
377 0           Perl_warner(aTHX_ WARN_UTF8, WIDE_CHAR_DEPRECATION_MSG,
378             "FCGI::Stream::PRINT");
379             #endif
380 4 50         str = (char *)SvPV(ST(n),len);
381 4 50         if (FCGX_PutStr(str, len, stream) < 0)
382 0           ok = FALSE;
383             }
384 4 50         if (ok && SvTRUEx(perl_get_sv("|", FALSE)) && FCGX_FFlush(stream) < 0)
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
385 0           ok = FALSE;
386 4 50         RETVAL = ok ? &PL_sv_yes : &PL_sv_undef;
387             OUTPUT:
388             RETVAL
389              
390             int
391             WRITE(stream, bufsv, len, ...)
392             FCGI::Stream stream;
393             SV *bufsv;
394             int len;
395             PREINIT:
396             int offset;
397             char *buf;
398             STRLEN blen;
399             int n;
400             CODE:
401 0 0         offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
    0          
402             #ifdef DO_UTF8
403 0 0         if (DO_UTF8(bufsv) && !sv_utf8_downgrade(bufsv, 1) && ckWARN_d(WARN_UTF8))
    0          
    0          
    0          
404 0           Perl_warner(aTHX_ WARN_UTF8, WIDE_CHAR_DEPRECATION_MSG,
405             "FCGI::Stream::WRITE");
406             #endif
407 0 0         buf = SvPV(bufsv, blen);
408 0 0         if (offset < 0) offset += blen;
409 0 0         if (len > blen - offset)
410 0           len = blen - offset;
411 0 0         if (offset < 0 || offset >= blen ||
    0          
    0          
412 0           (n = FCGX_PutStr(buf+offset, len, stream)) < 0)
413 0           ST(0) = &PL_sv_undef;
414             else {
415 0           ST(0) = sv_newmortal();
416 0           sv_setiv(ST(0), n);
417             }
418              
419             void
420             READ(stream, bufsv, len, ...)
421             FCGI::Stream stream;
422             SV *bufsv;
423             int len;
424             PREINIT:
425 0           int offset = 0;
426             char *buf;
427             STRLEN blen;
428             CODE:
429 0 0         if (items < 3 || items > 4)
    0          
430 0           croak("Usage: FCGI::Stream::READ(STREAM, SCALAR, LENGTH [, OFFSET ])");
431 0 0         if (len < 0)
432 0           croak("Negative length");
433 0 0         if (!SvOK(bufsv))
    0          
    0          
434 0           sv_setpvn(bufsv, "", 0);
435             #ifdef DO_UTF8
436 0 0         if (DO_UTF8(bufsv) && !sv_utf8_downgrade(bufsv, 1) && ckWARN_d(WARN_UTF8))
    0          
    0          
    0          
437 0           Perl_warner(aTHX_ WARN_UTF8, WIDE_CHAR_DEPRECATION_MSG,
438             "FCGI::Stream::READ");
439             #endif
440 0 0         buf = SvPV_force(bufsv, blen);
441 0 0         if (items == 4) {
442 0 0         offset = SvIV(ST(3));
443 0 0         if (offset < 0) {
444 0 0         if (-offset > (int)blen)
445 0           croak("Offset outside string");
446 0           offset += blen;
447             }
448             }
449 0 0         buf = SvGROW(bufsv, len + offset + 1);
    0          
450 0 0         if (offset > blen)
451 0           Zero(buf + blen, offset - blen, char);
452 0           len = FCGX_GetStr(buf + offset, len, stream);
453 0           SvCUR_set(bufsv, len + offset);
454 0           *SvEND(bufsv) = '\0';
455 0           (void)SvPOK_only(bufsv);
456 0 0         SvSETMAGIC(bufsv);
457 0           XSRETURN_IV(len);
458              
459             SV *
460             GETC(stream)
461             FCGI::Stream stream;
462             PREINIT:
463             int retval;
464             CODE:
465 0 0         if ((retval = FCGX_GetChar(stream)) != -1) {
466 0           ST(0) = sv_newmortal();
467 0           sv_setpvf(ST(0), "%c", retval);
468             }
469             else
470 0           ST(0) = &PL_sv_undef;
471              
472             SV *
473             EOF(stream, called=0)
474             FCGI::Stream stream;
475             IV called;
476             CODE:
477 0 0         RETVAL = boolSV(FCGX_HasSeenEOF(stream));
478             OUTPUT:
479             RETVAL
480              
481             void
482             FILENO(stream)
483             FCGI::Stream stream;
484             CODE:
485 0 0         if (FCGX_HasSeenEOF(stream) != 0)
486 0           XSRETURN_UNDEF;
487             else
488 0           XSRETURN_IV(-1);
489              
490             bool
491             CLOSE(stream)
492             FCGI::Stream stream;
493             CODE:
494 0           RETVAL = FCGX_FClose(stream) != -1;
495             OUTPUT:
496             RETVAL