Small clean ups
[catagits/fcgi2.git] / perl / FCGI.PL
CommitLineData
1b64d24d 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)) {
9 print OUT "#define PL_$_ $_\n"
10 }
11}
12print OUT while <DATA>;
13close OUT;
14__END__
b716743a 15/* $Id: FCGI.PL,v 1.10 1999/08/03 15:52:53 skimo Exp $ */
1b64d24d 16
17#include "EXTERN.h"
18#include "perl.h"
19#include "XSUB.h"
20
b716743a 21#include "fcgi_config.h"
1b64d24d 22#include "fcgiapp.h"
23
24#ifndef FALSE
25#define FALSE (0)
26#endif
27
28#ifndef TRUE
29#define TRUE (1)
30#endif
31
b716743a 32#ifndef dTHX
33#define dTHX
34#endif
35
1b64d24d 36#ifdef USE_SFIO
37typedef struct
38{
39 Sfdisc_t disc;
40 FCGX_Stream *stream;
41} FCGI_Disc;
42
43static ssize_t
44sffcgiread(f, buf, n, disc)
45Sfio_t* f; /* stream involved */
46Void_t* buf; /* buffer to read into */
47size_t n; /* number of bytes to read */
48Sfdisc_t* disc; /* discipline */
49{
50 return FCGX_GetStr(buf, n, ((FCGI_Disc *)disc)->stream);
51}
52
53static ssize_t
54sffcgiwrite(f, buf, n, disc)
55Sfio_t* f; /* stream involved */
56const Void_t* buf; /* buffer to read into */
57size_t n; /* number of bytes to read */
58Sfdisc_t* disc; /* discipline */
59{
60 n = FCGX_PutStr(buf, n, ((FCGI_Disc *)disc)->stream);
61 FCGX_FFlush(((FCGI_Disc *)disc)->stream);
62 return n;
63}
64
65Sfdisc_t *
66sfdcnewfcgi(stream)
67 FCGX_Stream *stream;
68{
69 FCGI_Disc* disc;
70
71 New(1000,disc,1,FCGI_Disc);
72 if (!disc) return (Sfdisc_t *)disc;
73
74 disc->disc.exceptf = (Sfexcept_f)NULL;
75 disc->disc.seekf = (Sfseek_f)NULL;
76 disc->disc.readf = sffcgiread;
77 disc->disc.writef = sffcgiwrite;
78 disc->stream = stream;
79 return (Sfdisc_t *)disc;
80}
81
82Sfdisc_t *
83sfdcdelfcgi(disc)
84 Sfdisc_t* disc;
85{
86 Safefree(disc);
87 return 0;
88}
89#endif
90
90a18d65 91static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: FCGI */
92
b716743a 93#if defined(USE_LOCKING) && defined(USE_THREADS)
94static perl_mutex accept_mutex;
95#endif
96
90a18d65 97typedef struct FCGP_Request {
b716743a 98 int bound;
90a18d65 99 SV* svin;
100 SV* svout;
101 SV* sverr;
eede4b76 102 GV* gv[3];
cebfd7c4 103 GV* gvNew[3];
34bfd355 104 HV* hvEnv;
90a18d65 105 FCGX_Stream* in;
106 FCGX_Request* requestPtr;
2c38ecd7 107#ifdef USE_SFIO
108 int sfcreated[3];
109#endif
90a18d65 110} FCGP_Request;
111
1b64d24d 112static int
90a18d65 113FCGI_Flush(FCGP_Request* request)
1b64d24d 114{
b716743a 115 dTHX;
116
117 if(!request->bound) {
1b64d24d 118 return;
119 }
120#ifdef USE_SFIO
2c38ecd7 121 sfsync(IoOFP(GvIOp(request->gv[1])));
122 sfsync(IoOFP(GvIOp(request->gv[2])));
1b64d24d 123#else
90a18d65 124 FCGX_FFlush((FCGX_Stream *) SvIV((SV*) SvRV(request->svout)));
125 FCGX_FFlush((FCGX_Stream *) SvIV((SV*) SvRV(request->sverr)));
1b64d24d 126#endif
127}
128
34bfd355 129static void
130FCGI_UndoBinding(FCGP_Request* request)
131{
132#ifdef USE_SFIO
2c38ecd7 133 IO *io[3];
134 int i;
135#endif
b716743a 136 dTHX;
2c38ecd7 137
138#ifdef USE_SFIO
139 sfdcdelfcgi(sfdisc(IoIFP(io[0] = GvIOp(request->gv[0])), SF_POPDISC));
140 sfdcdelfcgi(sfdisc(IoOFP(io[1] = GvIOp(request->gv[1])), SF_POPDISC));
141 sfdcdelfcgi(sfdisc(IoOFP(io[2] = GvIOp(request->gv[2])), SF_POPDISC));
142 for (i = 0; i < 3; ++i) {
143 if (request->sfcreated[i]) {
144 sfclose(IoIFP(io[i]));
145 IoIFP(io[i]) = IoOFP(io[i]) = Nullfp;
146 request->sfcreated[i] = FALSE;
147 }
148 }
34bfd355 149#else
150 FCGI_Flush(request);
151 sv_unmagic((SV *)request->gv[0], 'q');
152 sv_unmagic((SV *)request->gv[1], 'q');
153 sv_unmagic((SV *)request->gv[2], 'q');
154#endif
b716743a 155 request->in = NULL;
156 FCGX_Finish_r(request->requestPtr);
157 request->bound = FALSE;
158}
159
160static void
161populate_env(envp, hv)
162char **envp;
163HV *hv;
164{
165 int i;
166 char *p, *p1;
167 SV *sv;
168 dTHX;
169
170 for(i = 0; ; i++) {
171 if((p = envp[i]) == NULL) {
172 break;
173 }
174 p1 = strchr(p, '=');
175 assert(p1 != NULL);
176 sv = newSVpv(p1 + 1, 0);
177 /* call magic for this value ourselves */
178 hv_store(hv, p, p1 - p, sv, 0);
179 SvSETMAGIC(sv);
180 }
34bfd355 181}
182
1b64d24d 183static int
cebfd7c4 184FCGI_Accept(FCGP_Request* request)
1b64d24d 185{
b716743a 186 dTHX;
187
90a18d65 188 if(isCGI == -1) {
1b64d24d 189 /*
190 * First call to FCGI_Accept. Is application running
191 * as FastCGI or as CGI?
192 */
193 isCGI = FCGX_IsCGI();
194 } else if(isCGI) {
195 /*
196 * Not first call to FCGI_Accept and running as CGI means
197 * application is done.
198 */
199 return(EOF);
eede4b76 200 }
1b64d24d 201 if(!isCGI) {
2c38ecd7 202#ifdef USE_SFIO
203 IO *io[3];
204 int i;
205#endif
1b64d24d 206 FCGX_Stream *out, *error;
d8cc97fb 207 FCGX_ParamArray envp;
b716743a 208 int acceptResult;
209
210 if(request->bound) {
211 FCGI_UndoBinding(request);
212 }
213#if defined(USE_LOCKING) && defined(USE_THREADS)
214 MUTEX_LOCK(&accept_mutex);
215#endif
216 acceptResult = FCGX_Accept_r(&request->in, &out, &error,
d8cc97fb 217 &envp, request->requestPtr);
b716743a 218#if defined(USE_LOCKING) && defined(USE_THREADS)
219 MUTEX_UNLOCK(&accept_mutex);
220#endif
1b64d24d 221 if(acceptResult < 0) {
222 return acceptResult;
223 }
d8cc97fb 224
225 populate_env(envp, request->hvEnv);
226
1b64d24d 227#ifdef USE_SFIO
2c38ecd7 228 for (i = 0; i < 3; ++i) {
cebfd7c4 229 io[i] = GvIOn(request->gv[i] = request->gvNew[i]);
2c38ecd7 230 if (!(i == 0 ? IoIFP(io[i]) : IoOFP(io[i]))) {
231 IoIFP(io[i]) = sftmp(0);
232 /*IoIFP(io[i]) = sfnew(NULL, NULL, SF_UNBOUND, 0,
233 SF_STRING | (i ? SF_WRITE : SF_READ));*/
234 if (i != 0) IoOFP(io[i]) = IoIFP(io[i]);
235 request->sfcreated[i] = TRUE;
236 }
237 }
238 sfdisc(IoIFP(io[0]), sfdcnewfcgi(request->in));
239 sfdisc(IoOFP(io[1]), sfdcnewfcgi(out));
240 sfdisc(IoOFP(io[2]), sfdcnewfcgi(error));
1b64d24d 241#else
90a18d65 242 if (!request->svout) {
eede4b76 243 newSVrv(request->svout = newSV(0), "FCGI::Stream");
eede4b76 244 newSVrv(request->sverr = newSV(0), "FCGI::Stream");
eede4b76 245 newSVrv(request->svin = newSV(0), "FCGI::Stream");
1b64d24d 246 }
cebfd7c4 247 sv_magic((SV *)request->gv[1] = request->gvNew[1],
248 request->svout, 'q', Nullch, 0);
249 sv_magic((SV *)request->gv[2] = request->gvNew[2],
250 request->sverr, 'q', Nullch, 0);
251 sv_magic((SV *)request->gv[0] = request->gvNew[0],
252 request->svin, 'q', Nullch, 0);
90a18d65 253 sv_setiv(SvRV(request->svout), (IV) out);
254 sv_setiv(SvRV(request->sverr), (IV) error);
255 sv_setiv(SvRV(request->svin), (IV) request->in);
1b64d24d 256#endif
b716743a 257 request->bound = TRUE;
1b64d24d 258 }
1b64d24d 259 return 0;
260}
261
262static void
90a18d65 263FCGI_Finish(FCGP_Request* request)
1b64d24d 264{
b716743a 265 dTHX;
266
267 if(!request->bound) {
1b64d24d 268 return;
269 }
34bfd355 270 FCGI_UndoBinding(request);
1b64d24d 271}
272
273static int
90a18d65 274FCGI_StartFilterData(FCGP_Request* request)
275{
276 return request->in ? FCGX_StartFilterData(request->in) : -1;
277}
278
279static void
280FCGI_SetExitStatus(FCGP_Request* request, int status)
281{
282 if (request->in) FCGX_SetExitStatus(status, request->in);
283}
284
285static FCGP_Request *
286FCGI_Request()
1b64d24d 287{
90a18d65 288 FCGX_Request* fcgx_req;
289 FCGP_Request* req;
290
291 Newz(551, fcgx_req, 1, FCGX_Request);
292 Newz(551, req, 1, FCGP_Request);
293 req->requestPtr = fcgx_req;
294
295 return req;
1b64d24d 296}
297
298static void
90a18d65 299FCGI_Release_Request(FCGP_Request *req)
1b64d24d 300{
90a18d65 301 Safefree(req->requestPtr);
302 Safefree(req);
1b64d24d 303}
304
34bfd355 305static void
b716743a 306FCGI_Init()
34bfd355 307{
b716743a 308#if defined(USE_LOCKING) && defined(USE_THREADS)
309 dTHX;
34bfd355 310
b716743a 311 MUTEX_INIT(&accept_mutex);
312#endif
34bfd355 313}
314
eede4b76 315typedef FCGX_Stream * FCGI__Stream;
316typedef FCGP_Request * FCGI;
d8cc97fb 317typedef GV* GLOBREF;
318typedef HV* HASHREF;
1b64d24d 319
320MODULE = FCGI PACKAGE = FCGI
321
b716743a 322BOOT:
323 FCGI_Init();
eede4b76 324
325SV *
d8cc97fb 326Request()
eede4b76 327
328 PROTOTYPE:
329 CODE:
b716743a 330 RETVAL = sv_setref_pv(newSV(0), "FCGI", FCGI_Request());
eede4b76 331
332 OUTPUT:
333 RETVAL
334
335
336int
d8cc97fb 337Accept(request, in, out, err, env)
eede4b76 338
d8cc97fb 339 FCGI request;
340 GLOBREF in;
341 GLOBREF out;
342 GLOBREF err;
343 HASHREF env;
eede4b76 344
d8cc97fb 345 PROTOTYPE: $***$
eede4b76 346
347 CODE:
d8cc97fb 348 request->gvNew[0] = in;
349 request->gvNew[1] = out;
350 request->gvNew[2] = err;
351 request->hvEnv = env;
352
353 RETVAL = FCGI_Accept(request);
eede4b76 354
eede4b76 355 OUTPUT:
356 RETVAL
357
358
359void
d8cc97fb 360Finish(request)
eede4b76 361
d8cc97fb 362 FCGI request;
eede4b76 363
d8cc97fb 364 PROTOTYPE: $
eede4b76 365
366 CODE:
eede4b76 367 {
368 /*
eede4b76 369 * Finish the request.
370 */
371 FCGI_Finish(request);
372 }
373
374
375void
d8cc97fb 376Flush(request)
eede4b76 377
d8cc97fb 378 FCGI request;
eede4b76 379
d8cc97fb 380 PROTOTYPE: $
eede4b76 381
382 CODE:
eede4b76 383 FCGI_Flush(request);
384
eede4b76 385
386int
d8cc97fb 387StartFilterData(request)
eede4b76 388
d8cc97fb 389 FCGI request;
eede4b76 390
d8cc97fb 391 PROTOTYPE: $
eede4b76 392
393 CODE:
eede4b76 394 RETVAL = FCGI_StartFilterData(request);
395
396 OUTPUT:
397 RETVAL
398
eede4b76 399void
400DESTROY(request)
401 FCGI request;
402
403 CODE:
404 FCGI_Release_Request(request);
405
406
407
408MODULE = FCGI PACKAGE = FCGI::Stream
90a18d65 409
1b64d24d 410#ifndef USE_SFIO
1b64d24d 411
412void
413PRINT(stream, ...)
eede4b76 414 FCGI::Stream stream;
1b64d24d 415
416 PREINIT:
417 int n;
418
419 CODE:
420 for (n = 1; n < items; ++n) {
421 STRLEN len;
422 register char *tmps = (char *)SvPV(ST(n),len);
423 FCGX_PutStr(tmps, len, stream);
424 }
425 if (SvTRUEx(perl_get_sv("|", FALSE)))
426 FCGX_FFlush(stream);
427
428int
429WRITE(stream, bufsv, len, ...)
eede4b76 430 FCGI::Stream stream;
1b64d24d 431 SV * bufsv;
432 int len;
433
434 PREINIT:
435 int offset;
436 char * buf;
437 STRLEN blen;
438 int n;
439
440 CODE:
441 offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
442 buf = SvPV(bufsv, blen);
443 if (offset < 0) offset += blen;
444 if (len > blen - offset)
445 len = blen - offset;
446 if (offset < 0 || offset >= blen ||
447 (n = FCGX_PutStr(buf+offset, len, stream)) < 0)
448 ST(0) = &PL_sv_undef;
449 else {
450 ST(0) = sv_newmortal();
451 sv_setpvf(ST(0), "%c", n);
452 }
453
454int
455READ(stream, bufsv, len, ...)
eede4b76 456 FCGI::Stream stream;
1b64d24d 457 SV * bufsv;
458 int len;
459
460 PREINIT:
461 int offset;
462 char * buf;
463
464 CODE:
465 offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
466 if (! SvOK(bufsv))
467 sv_setpvn(bufsv, "", 0);
468 buf = SvGROW(bufsv, len+offset+1);
469 len = FCGX_GetStr(buf+offset, len, stream);
470 SvCUR_set(bufsv, len+offset);
471 *SvEND(bufsv) = '\0';
472 (void)SvPOK_only(bufsv);
473 SvSETMAGIC(bufsv);
474 RETVAL = len;
475
476 OUTPUT:
477 RETVAL
478
479SV *
480GETC(stream)
eede4b76 481 FCGI::Stream stream;
1b64d24d 482
483 PREINIT:
484 int retval;
485
486 CODE:
487 if ((retval = FCGX_GetChar(stream)) != -1) {
488 ST(0) = sv_newmortal();
489 sv_setpvf(ST(0), "%c", retval);
490 } else ST(0) = &PL_sv_undef;
491
492bool
493CLOSE(stream)
eede4b76 494 FCGI::Stream stream;
1b64d24d 495
496 ALIAS:
497 DESTROY = 1
498
499 CODE:
500 RETVAL = FCGX_FClose(stream) != -1;
501
502 OUTPUT:
503 RETVAL
504
505#endif