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