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 | |
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 |
47 | static perl_mutex accept_mutex; |
0833402a |
48 | #endif |
49 | |
50 | typedef 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 | |
61 | static void FCGI_Finish(FCGP_Request* request); |
62 | |
9b60732b |
63 | static void |
66cfae24 |
64 | FCGI_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 | |
72 | static void |
66cfae24 |
73 | FCGI_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 | |
87 | static void |
66cfae24 |
88 | FCGI_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 | |
112 | static void |
66cfae24 |
113 | populate_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 | |
132 | static int |
66cfae24 |
133 | FCGI_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 | |
146 | static int |
66cfae24 |
147 | FCGI_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 | |
193 | static void |
66cfae24 |
194 | FCGI_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 | |
210 | static int |
66cfae24 |
211 | FCGI_StartFilterData(FCGP_Request* request) { |
0833402a |
212 | return request->requestPtr->in ? |
5828234f |
213 | FCGX_StartFilterData(request->requestPtr->in) : -1; |
0833402a |
214 | } |
215 | |
216 | static FCGP_Request * |
66cfae24 |
217 | FCGI_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 | |
237 | static void |
66cfae24 |
238 | FCGI_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 | |
248 | static void |
66cfae24 |
249 | FCGI_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 |
257 | typedef FCGX_Stream* FCGI__Stream; |
258 | typedef FCGP_Request* FCGI; |
259 | typedef GV* GLOBREF; |
260 | typedef HV* HASHREF; |
0833402a |
261 | |
66cfae24 |
262 | MODULE = FCGI PACKAGE = FCGI PREFIX = FCGI_ |
0833402a |
263 | |
264 | BOOT: |
265 | FCGI_Init(); |
266 | |
267 | SV * |
268 | RequestX(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 | |
282 | int |
283 | OpenSocket(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 | |
292 | void |
293 | CloseSocket(socket) |
294 | int socket; |
66cfae24 |
295 | PROTOTYPE: $ |
296 | CODE: |
0833402a |
297 | close(socket); |
298 | |
299 | int |
300 | FCGI_Accept(request) |
0833402a |
301 | FCGI request; |
66cfae24 |
302 | PROTOTYPE: $ |
0833402a |
303 | |
304 | void |
305 | FCGI_Finish(request) |
66cfae24 |
306 | FCGI request; |
307 | PROTOTYPE: $ |
0833402a |
308 | |
309 | void |
310 | FCGI_Flush(request) |
66cfae24 |
311 | FCGI request; |
312 | PROTOTYPE: $ |
0833402a |
313 | |
314 | HV * |
315 | GetEnvironment(request) |
66cfae24 |
316 | FCGI request; |
317 | PROTOTYPE: $ |
318 | CODE: |
0833402a |
319 | RETVAL = request->hvEnv; |
66cfae24 |
320 | OUTPUT: |
0833402a |
321 | RETVAL |
322 | |
323 | void |
324 | GetHandles(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 | |
334 | int |
335 | FCGI_IsFastCGI(request) |
66cfae24 |
336 | FCGI request; |
337 | PROTOTYPE: $ |
0833402a |
338 | |
339 | void |
340 | Detach(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 | |
349 | void |
350 | Attach(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 |
359 | void |
360 | LastCall(request) |
66cfae24 |
361 | FCGI request; |
362 | PROTOTYPE: $ |
363 | CODE: |
7fa2de73 |
364 | FCGX_ShutdownPending(); |
0833402a |
365 | |
366 | int |
367 | FCGI_StartFilterData(request) |
66cfae24 |
368 | FCGI request; |
369 | PROTOTYPE: $ |
0833402a |
370 | |
371 | void |
372 | DESTROY(request) |
66cfae24 |
373 | FCGI request; |
374 | CODE: |
0833402a |
375 | FCGI_Release_Request(request); |
376 | |
66cfae24 |
377 | MODULE = FCGI PACKAGE = FCGI::Stream |
0833402a |
378 | |
cd90e76f |
379 | SV * |
0833402a |
380 | PRINT(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 | |
404 | int |
405 | WRITE(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 |
433 | void |
0833402a |
434 | READ(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 | |
473 | SV * |
474 | GETC(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 | |
486 | bool |
487 | CLOSE(stream) |
66cfae24 |
488 | FCGI::Stream stream; |
489 | CODE: |
5828234f |
490 | RETVAL = FCGX_FClose(stream) != -1; |
66cfae24 |
491 | OUTPUT: |
5828234f |
492 | RETVAL |