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