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