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