Commit | Line | Data |
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 |
33 | static perl_mutex accept_mutex; |
0833402a |
34 | #endif |
35 | |
36 | typedef 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 | |
47 | static void FCGI_Finish(FCGP_Request* request); |
48 | |
9b60732b |
49 | static void |
66cfae24 |
50 | FCGI_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 | |
58 | static void |
66cfae24 |
59 | FCGI_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 | |
73 | static void |
66cfae24 |
74 | FCGI_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 | |
98 | static void |
66cfae24 |
99 | populate_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 | |
118 | static int |
66cfae24 |
119 | FCGI_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 | |
132 | static int |
66cfae24 |
133 | FCGI_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 | |
179 | static void |
66cfae24 |
180 | FCGI_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 | |
196 | static int |
66cfae24 |
197 | FCGI_StartFilterData(FCGP_Request* request) { |
0833402a |
198 | return request->requestPtr->in ? |
5828234f |
199 | FCGX_StartFilterData(request->requestPtr->in) : -1; |
0833402a |
200 | } |
201 | |
202 | static FCGP_Request * |
66cfae24 |
203 | FCGI_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 | |
223 | static void |
66cfae24 |
224 | FCGI_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 | |
234 | static void |
66cfae24 |
235 | FCGI_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 |
243 | typedef FCGX_Stream* FCGI__Stream; |
244 | typedef FCGP_Request* FCGI; |
245 | typedef GV* GLOBREF; |
246 | typedef HV* HASHREF; |
0833402a |
247 | |
66cfae24 |
248 | MODULE = FCGI PACKAGE = FCGI PREFIX = FCGI_ |
0833402a |
249 | |
250 | BOOT: |
251 | FCGI_Init(); |
252 | |
253 | SV * |
254 | RequestX(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 | |
268 | int |
269 | OpenSocket(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 | |
278 | void |
279 | CloseSocket(socket) |
280 | int socket; |
66cfae24 |
281 | PROTOTYPE: $ |
282 | CODE: |
0833402a |
283 | close(socket); |
284 | |
285 | int |
286 | FCGI_Accept(request) |
0833402a |
287 | FCGI request; |
66cfae24 |
288 | PROTOTYPE: $ |
0833402a |
289 | |
290 | void |
291 | FCGI_Finish(request) |
66cfae24 |
292 | FCGI request; |
293 | PROTOTYPE: $ |
0833402a |
294 | |
295 | void |
296 | FCGI_Flush(request) |
66cfae24 |
297 | FCGI request; |
298 | PROTOTYPE: $ |
0833402a |
299 | |
300 | HV * |
301 | GetEnvironment(request) |
66cfae24 |
302 | FCGI request; |
303 | PROTOTYPE: $ |
304 | CODE: |
0833402a |
305 | RETVAL = request->hvEnv; |
66cfae24 |
306 | OUTPUT: |
0833402a |
307 | RETVAL |
308 | |
309 | void |
310 | GetHandles(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 | |
320 | int |
321 | FCGI_IsFastCGI(request) |
66cfae24 |
322 | FCGI request; |
323 | PROTOTYPE: $ |
0833402a |
324 | |
325 | void |
326 | Detach(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 | |
335 | void |
336 | Attach(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 |
345 | void |
346 | LastCall(request) |
66cfae24 |
347 | FCGI request; |
348 | PROTOTYPE: $ |
349 | CODE: |
7fa2de73 |
350 | FCGX_ShutdownPending(); |
0833402a |
351 | |
352 | int |
353 | FCGI_StartFilterData(request) |
66cfae24 |
354 | FCGI request; |
355 | PROTOTYPE: $ |
0833402a |
356 | |
357 | void |
358 | DESTROY(request) |
66cfae24 |
359 | FCGI request; |
360 | CODE: |
0833402a |
361 | FCGI_Release_Request(request); |
362 | |
66cfae24 |
363 | MODULE = FCGI PACKAGE = FCGI::Stream |
0833402a |
364 | |
cd90e76f |
365 | SV * |
0833402a |
366 | PRINT(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 | |
390 | int |
391 | WRITE(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 |
419 | void |
0833402a |
420 | READ(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 | |
459 | SV * |
460 | GETC(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 |
472 | SV * |
473 | EOF(stream, called=0) |
474 | FCGI::Stream stream; |
475 | IV called; |
476 | CODE: |
477 | RETVAL = boolSV(FCGX_HasSeenEOF(stream)); |
478 | OUTPUT: |
479 | RETVAL |
480 | |
da653cb4 |
481 | void |
482 | FILENO(stream) |
483 | FCGI::Stream stream; |
484 | CODE: |
485 | if (FCGX_HasSeenEOF(stream) != 0) |
486 | XSRETURN_UNDEF; |
487 | else |
488 | XSRETURN_IV(-1); |
489 | |
0833402a |
490 | bool |
491 | CLOSE(stream) |
66cfae24 |
492 | FCGI::Stream stream; |
493 | CODE: |
5828234f |
494 | RETVAL = FCGX_FClose(stream) != -1; |
66cfae24 |
495 | OUTPUT: |
5828234f |
496 | RETVAL |