Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 646 lines (570 sloc) 17.366 kB
f61f188 @spiritloose Initial commit
authored
1 /*
2 * Copyright 2009 Jiro Nishiguchi <jiro@cpan.org>
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
03fb93e @mattn win32 porting.
mattn authored
16 #ifdef _WIN32
17 /* avoid to define duplicate definition of uid_t/gid_t in perl/CORE.h */
18 #define uid_t _uid_t
19 #define gid_t _gid_t
20 #endif
f61f188 @spiritloose Initial commit
authored
21 #include "httpd.h"
22 #include "http_log.h"
23 #include "http_config.h"
24 #include "http_protocol.h"
25 #include "util_script.h"
26 #include "ap_config.h"
27 #include "ap_mpm.h"
03fb93e @mattn win32 porting.
mattn authored
28 #include "apr_buckets.h"
f61f188 @spiritloose Initial commit
authored
29 #include "apr_strings.h"
c115693 @spiritloose 'do $psgi_app' at post_config
authored
30 #include "apr_hash.h"
f61f188 @spiritloose Initial commit
authored
31
03fb93e @mattn win32 porting.
mattn authored
32 #ifdef _WIN32
33 /* use perl's uid_t/gid_t. disable apr's macros. */
34 #undef uid_t
35 #undef gid_t
36 #undef exit
37 #endif
38
f61f188 @spiritloose Initial commit
authored
39 #include "EXTERN.h"
40 #include "perl.h"
41 #include "XSUB.h"
42 #define NEED_eval_pv
43 #define NEED_newRV_noinc
44 #define NEED_sv_2pv_flags
45 #include "ppport.h"
46
03fb93e @mattn win32 porting.
mattn authored
47 #ifdef _WIN32
48 /* no use perl compatible macros. it break apr's structure. ex: bucket->link */
49 #undef link
50 #undef read
51 #endif
52
098e77e @spiritloose ap_add_version_component
authored
53 #define PSGI_HANDLER_NAME "psgi"
54
f61f188 @spiritloose Initial commit
authored
55 #ifdef DEBUG
56 #define TRACE(...) ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, NULL, __VA_ARGS__)
57 #endif
58
59 module AP_MODULE_DECLARE_DATA psgi_module;
60
61 typedef struct {
ace1272 @spiritloose Make PerlInterpreter persistent
authored
62 char *file;
430ccf9 @fujiwara fix PATH_INFO and SCRIPT_NAME
fujiwara authored
63 char *location;
f61f188 @spiritloose Initial commit
authored
64 } psgi_dir_config;
65
c115693 @spiritloose 'do $psgi_app' at post_config
authored
66 static PerlInterpreter *perlinterp = NULL;
67
68 static apr_hash_t *app_mapping = NULL;
69
70 static apr_array_header_t *psgi_apps = NULL;
e284234 @spiritloose Call PERL_SYS_INIT3,PERL_SYS_TERM once per process
authored
71
f61f188 @spiritloose Initial commit
authored
72 static void server_error(request_rec *r, const char *fmt, ...)
73 {
74 va_list argp;
75 const char *msg;
76 va_start(argp, fmt);
77 msg = apr_pvsprintf(r->pool, fmt, argp);
78 va_end(argp);
79 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r->server, "%s", msg);
80 }
81
82 EXTERN_C void xs_init (pTHX);
83
84 EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
85
86 XS(ModPSGI_exit);
87 XS(ModPSGI_exit)
88 {
89 dXSARGS;
90 croak("exit");
91 XSRETURN(0);
92 }
93
94 XS(ModPSGI_Input_read);
95 XS(ModPSGI_Input_read)
96 {
97 dXSARGS;
98 SV *self = ST(0);
99 SV *buf = ST(1);
100 request_rec *r = (request_rec *) mg_find(SvRV(self), PERL_MAGIC_ext)->mg_obj;
101 apr_size_t len = SvIV(ST(2));
102 apr_size_t offset = items >= 4 ? SvIV(ST(3)) : 0;
103 apr_status_t rv;
104 apr_bucket_brigade *bb;
105 apr_bucket *bucket;
106 int eos = 0;
107 SV *ret;
108 dXSTARG;
109
110 ret = newSVpv("", 0);
111 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
112 rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, len);
113 if (rv != APR_SUCCESS) {
114 ST(0) = &PL_sv_undef;
115 XSRETURN(1);
116 }
117
118 for (bucket = APR_BRIGADE_FIRST(bb);
119 bucket != APR_BRIGADE_SENTINEL(bb);
120 bucket = APR_BUCKET_NEXT(bucket)) {
121 const char *bbuf;
122 apr_size_t blen;
123 if (APR_BUCKET_IS_EOS(bucket)) {
124 eos = 1;
125 break;
126 }
127 if (APR_BUCKET_IS_METADATA(bucket)) {
128 continue;
129 }
130 apr_bucket_read(bucket, &bbuf, &blen, APR_BLOCK_READ);
131 sv_catpvn(ret, bbuf, blen);
132 }
133
134 sv_setsv(buf, ret);
135 ST(0) = sv_2mortal(newSViv(SvCUR(buf)));
136 XSRETURN(1);
137 }
138
139 XS(ModPSGI_Errors_print);
140 XS(ModPSGI_Errors_print)
141 {
142 dXSARGS;
143 SV *self = ST(0);
144 SV *msg = ST(1);
145 dXSTARG;
146 request_rec *r = (request_rec *) mg_find(SvRV(self), PERL_MAGIC_ext)->mg_obj;
147 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r->server, "%s", SvPV_nolen(msg));
148 ST(0) = newSViv(1);
149 XSRETURN(1);
150 }
151
152 EXTERN_C void
153 xs_init(pTHX)
154 {
155 char *file = __FILE__;
156 dXSUB_SYS;
157
158 newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
159 newXS("ModPSGI::exit", ModPSGI_exit, file);
160 newXSproto("ModPSGI::Input::read", ModPSGI_Input_read, file, "$$$;$");
161 newXSproto("ModPSGI::Errors::print", ModPSGI_Errors_print, file, "$$");
162 }
163
164 static int copy_env(void *rec, const char *key, const char *val)
165 {
fe98cae @spiritloose use dTHX
authored
166 dTHX;
f61f188 @spiritloose Initial commit
authored
167 HV *env = (HV *) rec;
168 hv_store(env, key, strlen(key), newSVpv(val, 0), 0);
169 return 1;
170 }
171
172 static SV *make_env(request_rec *r)
173 {
fe98cae @spiritloose use dTHX
authored
174 dTHX;
f61f188 @spiritloose Initial commit
authored
175 HV *env;
176 AV *version;
430ccf9 @fujiwara fix PATH_INFO and SCRIPT_NAME
fujiwara authored
177 char *url_scheme, *location, *vpath, *path_info;
f61f188 @spiritloose Initial commit
authored
178 SV *input, *errors;
430ccf9 @fujiwara fix PATH_INFO and SCRIPT_NAME
fujiwara authored
179 psgi_dir_config *c;
f61f188 @spiritloose Initial commit
authored
180
181 env = newHV();
430ccf9 @fujiwara fix PATH_INFO and SCRIPT_NAME
fujiwara authored
182 c = (psgi_dir_config *) ap_get_module_config(r->per_dir_config, &psgi_module);
f61f188 @spiritloose Initial commit
authored
183
184 ap_add_cgi_vars(r);
185 ap_add_common_vars(r);
430ccf9 @fujiwara fix PATH_INFO and SCRIPT_NAME
fujiwara authored
186
187 // fix SCRIPT_NAME & PATH_INFO
f61f188 @spiritloose Initial commit
authored
188 if (apr_table_get(r->subprocess_env, "PATH_INFO") == NULL) {
189 apr_table_set(r->subprocess_env, "PATH_INFO", "");
190 }
430ccf9 @fujiwara fix PATH_INFO and SCRIPT_NAME
fujiwara authored
191 location = c->location == NULL ? "" : c->location;
192 if (strcmp(location, "/") == 0) {
193 location = "";
f61f188 @spiritloose Initial commit
authored
194 }
430ccf9 @fujiwara fix PATH_INFO and SCRIPT_NAME
fujiwara authored
195 vpath = apr_pstrcat(r->pool,
196 apr_table_get(r->subprocess_env, "SCRIPT_NAME"),
197 apr_table_get(r->subprocess_env, "PATH_INFO"),
198 NULL);
199 path_info = &vpath[ (int) strlen(location) ];
200 apr_table_set(r->subprocess_env, "PATH_INFO", path_info);
201 apr_table_set(r->subprocess_env, "SCRIPT_NAME", location);
202
f61f188 @spiritloose Initial commit
authored
203 apr_table_do(copy_env, env, r->subprocess_env, NULL);
204
205 version = newAV();
206 av_push(version, newSViv(1));
207 av_push(version, newSViv(0));
208 hv_store(env, "psgi.version", 12, newRV_inc((SV *) version), 0);
209
210 url_scheme = apr_table_get(r->subprocess_env, "HTTPS") == NULL ? "http" : "https";
211 hv_store(env, "psgi.url_scheme", 15, newSVpv(url_scheme, 0), 0);
212
213 input = newRV_noinc(newSV(0));
214 sv_magic(SvRV(input), NULL, PERL_MAGIC_ext, NULL, 0);
215 mg_find(SvRV(input), PERL_MAGIC_ext)->mg_obj = (void *) r;
216 sv_bless(input, gv_stashpv("ModPSGI::Input", 1));
217 hv_store(env, "psgi.input", 10, input, 0);
218
219 errors = newRV_noinc(newSV(0));
220 sv_magic(SvRV(errors), NULL, PERL_MAGIC_ext, NULL, 0);
221 mg_find(SvRV(errors), PERL_MAGIC_ext)->mg_obj = (void *) r;
222 sv_bless(errors, gv_stashpv("ModPSGI::Errors", 1));
223 hv_store(env, "psgi.errors", 11, errors, 0);
224
225 hv_store(env, "psgi.multithread", 16, newSViv(0), 0);
226 hv_store(env, "psgi.multiprocess", 17, newSViv(1), 0);
227 hv_store(env, "psgi.run_once", 13, newSViv(1), 0);
3377795 @spiritloose psgi.async -> psgi.nonblocking
authored
228 hv_store(env, "psgi.nonblocking", 16, newSViv(0), 0);
f61f188 @spiritloose Initial commit
authored
229
230 return newRV_inc((SV *) env);
231 }
232
233 static SV *run_app(request_rec *r, SV *app, SV *env)
234 {
fe98cae @spiritloose use dTHX
authored
235 dTHX;
f61f188 @spiritloose Initial commit
authored
236 int count;
237 SV *res;
238 dSP;
239 ENTER;
240 SAVETMPS;
241 PUSHMARK(SP) ;
242 XPUSHs(sv_2mortal(env));
243 PUTBACK;
244
5fc2eef @spiritloose Do not use G_KEEPERR in run_app
authored
245 count = call_sv(app, G_EVAL|G_SCALAR);
f61f188 @spiritloose Initial commit
authored
246 SPAGAIN;
247 if (SvTRUE(ERRSV)) {
248 res = NULL;
249 server_error(r, "%s", SvPV_nolen(ERRSV));
250 POPs;
251 } else if (count > 0) {
252 res = POPs;
253 SvREFCNT_inc(res);
254 } else {
255 res = NULL;
256 }
257 PUTBACK;
258 FREETMPS;
259 LEAVE;
260 return res;
261 }
262
263 static int output_status(request_rec *r, SV *status)
264 {
fe98cae @spiritloose use dTHX
authored
265 dTHX;
f61f188 @spiritloose Initial commit
authored
266 int s = SvIV(status);
267 if (s < 100) {
268 server_error(r, "invalid response status %d", s);
269 return HTTP_INTERNAL_SERVER_ERROR;
270 }
271 r->status = s;
272 return OK;
273 }
274
275 static int output_headers(request_rec *r, AV *headers)
276 {
fe98cae @spiritloose use dTHX
authored
277 dTHX;
f61f188 @spiritloose Initial commit
authored
278 SV *key_sv, *val_sv;
947bdac @spiritloose use ap_set_content_length
authored
279 char *key;
280
281 r->content_type = NULL;
f61f188 @spiritloose Initial commit
authored
282 while (av_len(headers) > -1) {
283 key_sv = av_shift(headers);
284 val_sv = av_shift(headers);
285 if (key_sv == NULL || val_sv == NULL) break;
286 key = SvPV_nolen(key_sv);
aab7f6a @spiritloose Do not check header value
authored
287 if (strcmp(key, "Content-Type") == 0) {
947bdac @spiritloose use ap_set_content_length
authored
288 r->content_type = apr_pstrdup(r->pool, SvPV_nolen(val_sv));
289 } else if (strcmp(key, "Content-Length") == 0) {
290 ap_set_content_length(r, SvIV(val_sv));
f61f188 @spiritloose Initial commit
authored
291 } else if (strcmp(key, "Status") == 0) {
292 server_error(r, "headers must not contain a Status");
293 return HTTP_INTERNAL_SERVER_ERROR;
294 } else {
947bdac @spiritloose use ap_set_content_length
authored
295 apr_table_add(r->headers_out, key, SvPV_nolen(val_sv));
f61f188 @spiritloose Initial commit
authored
296 }
297 }
298 return OK;
299 }
300
301 static int respond_to(SV *obj, const char *method)
302 {
fe98cae @spiritloose use dTHX
authored
303 dTHX;
f61f188 @spiritloose Initial commit
authored
304 int res;
305 dSP;
306 ENTER;
307 SAVETMPS;
308 PUSHMARK(SP);
309 XPUSHs(obj);
310 XPUSHs(sv_2mortal(newSVpv(method, 0)));
311 PUTBACK;
312
313 call_method("can", G_SCALAR);
314 SPAGAIN;
315 res = SvROK(POPs);
316 PUTBACK;
317 FREETMPS;
318 LEAVE;
319 return res;
320 }
321
322 static int output_body_ary(request_rec *r, AV *bodys)
323 {
fe98cae @spiritloose use dTHX
authored
324 dTHX;
f61f188 @spiritloose Initial commit
authored
325 SV **body;
326 I32 i;
327 I32 lastidx;
328 char *buf;
329 STRLEN len;
03fb93e @mattn win32 porting.
mattn authored
330 apr_off_t clen = 0;
f61f188 @spiritloose Initial commit
authored
331
332 lastidx = av_len(bodys);
333 for (i = 0; i <= lastidx; i++) {
334 body = av_fetch(bodys, i, 0);
335 if (SvOK(*body)) {
336 buf = SvPV(*body, len);
337 ap_rwrite(buf, len, r);
338 clen += len;
339 }
340 }
947bdac @spiritloose use ap_set_content_length
authored
341 if (clen > 0) {
342 ap_set_content_length(r, clen);
343 }
f61f188 @spiritloose Initial commit
authored
344 return OK;
345 }
346
347 static int output_body_obj(request_rec *r, SV *obj, int type)
348 {
fe98cae @spiritloose use dTHX
authored
349 dTHX;
f61f188 @spiritloose Initial commit
authored
350 SV *buf_sv, *rs;
351 apr_off_t clen = 0;
352 STRLEN len;
03fb93e @mattn win32 porting.
mattn authored
353 dSP;
f61f188 @spiritloose Initial commit
authored
354 char *buf;
355 int count;
356
357 if (type == SVt_PVMG && !respond_to(obj, "getline")) {
358 server_error(r, "response body object must be able to getline");
359 return HTTP_INTERNAL_SERVER_ERROR;
360 }
361
362 ENTER;
363 SAVETMPS;
364 SAVESPTR(PL_rs);
365 PL_rs = newRV_inc(newSViv(AP_IOBUFSIZE));
366 while (1) {
367 PUSHMARK(SP);
368 XPUSHs(obj);
369 PUTBACK;
370 count = call_method("getline", G_SCALAR);
371 if (count != 1) croak("Big trouble\n");
372 SPAGAIN;
373 buf_sv = POPs;
374 if (SvOK(buf_sv)) {
375 buf = SvPV(buf_sv, len);
376 clen += len;
377 ap_rwrite(buf, len, r);
378 } else {
379 break;
380 }
381 }
947bdac @spiritloose use ap_set_content_length
authored
382 if (len > 0) {
383 ap_set_content_length(r, len);
384 }
f61f188 @spiritloose Initial commit
authored
385 PUSHMARK(SP);
386 XPUSHs(obj);
387 PUTBACK;
388 call_method("close", G_DISCARD);
389 SPAGAIN;
390 PUTBACK;
391 FREETMPS;
392 LEAVE;
393 return OK;
394 }
395
396 static int output_body(request_rec *r, SV *body)
397 {
fe98cae @spiritloose use dTHX
authored
398 dTHX;
f61f188 @spiritloose Initial commit
authored
399 int rc, type;
400 switch (type = SvTYPE(SvRV(body))) {
401 case SVt_PVAV:
402 rc = output_body_ary(r, (AV *) SvRV(body));
403 break;
404 case SVt_PVGV:
405 require_pv("IO/Handle.pm");
406 case SVt_PVMG:
407 rc = output_body_obj(r, body, type);
408 break;
409 default:
410 server_error(r, "response body must be an array reference or object");
411 rc = HTTP_INTERNAL_SERVER_ERROR;
412 break;
413 }
414 return rc;
415 }
416
417 static int output_response(request_rec *r, SV *res)
418 {
fe98cae @spiritloose use dTHX
authored
419 dTHX;
f61f188 @spiritloose Initial commit
authored
420 AV *res_av;
421 SV **status;
422 SV **headers;
423 AV *headers_av;
424 SV **body;
425 int rc;
426
427 if (!SvROK(res) || SvTYPE(SvRV(res)) != SVt_PVAV) {
428 server_error(r, "response must be an array reference");
429 return HTTP_INTERNAL_SERVER_ERROR;
430 }
431 res_av = (AV *) SvRV(res);
432 if (av_len(res_av) != 2) {
433 server_error(r, "response must have 3 elements");
434 return HTTP_INTERNAL_SERVER_ERROR;
435 }
436
437 status = av_fetch(res_av, 0, 0);
438 if (!SvOK(*status)) {
439 server_error(r, "response status must be a scalar value");
440 return HTTP_INTERNAL_SERVER_ERROR;
441 }
442 rc = output_status(r, *status);
443 if (rc != OK) return rc;
444
445 headers = av_fetch(res_av, 1, 0);
446 if (!SvROK(*headers) || SvTYPE(SvRV(*headers)) != SVt_PVAV) {
447 server_error(r, "response headers must be an array reference");
448 return HTTP_INTERNAL_SERVER_ERROR;
449 }
450 headers_av = (AV *) SvRV(*headers);
451 if ((av_len(headers_av) + 1) % 2 != 0) {
452 server_error(r, "num of response headers must be even");
453 return HTTP_INTERNAL_SERVER_ERROR;
454 }
455 rc = output_headers(r, headers_av);
456 if (rc != OK) return rc;
457
458 body = av_fetch(res_av, 2, 0);
459 if (!SvROK(*body)) {
460 server_error(r, "response body must be a reference");
461 return HTTP_INTERNAL_SERVER_ERROR;
462 }
463 rc = output_body(r, *body);
464
465 return rc;
466 }
467
ace1272 @spiritloose Make PerlInterpreter persistent
authored
468 static void init_perl_variables()
f61f188 @spiritloose Initial commit
authored
469 {
fe98cae @spiritloose use dTHX
authored
470 dTHX;
f61f188 @spiritloose Initial commit
authored
471 GV *exit_gv = gv_fetchpv("CORE::GLOBAL::exit", TRUE, SVt_PVCV);
472 GvCV(exit_gv) = get_cv("ModPSGI::exit", TRUE);
473 GvIMPORTED_CV_on(exit_gv);
474 hv_store(GvHV(PL_envgv), "MOD_PSGI", 8, newSVpv(MOD_PSGI_VERSION, 0), 0);
475 }
476
ecd58df @spiritloose Load .psgi from .htaccess
authored
477 static SV *load_psgi(apr_pool_t *pool, const char *file)
478 {
479 dTHX;
480 SV *app;
481 char *code;
482
483 code = apr_psprintf(pool, "do q\"%s\" or die $@",
484 ap_escape_quotes(pool, file));
485 app = eval_pv(code, FALSE);
486
487 if (SvTRUE(ERRSV)) {
488 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, NULL, "%s", SvPV_nolen(ERRSV));
489 return NULL;
490 }
491 if (!SvOK(app) || !SvROK(app) || SvTYPE(SvRV(app)) != SVt_PVCV) {
492 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, NULL,
493 "%s does not return an application code reference", file);
494 return NULL;
495 }
496 return app;
497 }
498
4e00d63 @spiritloose init and destroy in handler
authored
499 static int psgi_handler(request_rec *r)
f61f188 @spiritloose Initial commit
authored
500 {
501 SV *app, *env, *res;
502 psgi_dir_config *c;
503
098e77e @spiritloose ap_add_version_component
authored
504 if (strcmp(r->handler, PSGI_HANDLER_NAME)) {
f61f188 @spiritloose Initial commit
authored
505 return DECLINED;
506 }
507 c = (psgi_dir_config *) ap_get_module_config(r->per_dir_config, &psgi_module);
ace1272 @spiritloose Make PerlInterpreter persistent
authored
508 if (c->file == NULL) {
f61f188 @spiritloose Initial commit
authored
509 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, r->server,
510 "PSGIApp not configured");
511 return DECLINED;
512 }
5b66763 @spiritloose PERL_SET_CONTEXT
authored
513
514 PERL_SET_CONTEXT(perlinterp);
c115693 @spiritloose 'do $psgi_app' at post_config
authored
515 app = apr_hash_get(app_mapping, c->file, APR_HASH_KEY_STRING);
ecd58df @spiritloose Load .psgi from .htaccess
authored
516 if (app == NULL) {
517 app = load_psgi(r->pool, c->file);
518 if (app == NULL) {
519 server_error(r, "%s had compilation errors.", c->file);
520 return HTTP_INTERNAL_SERVER_ERROR;
521 }
522 apr_hash_set(app_mapping, c->file, APR_HASH_KEY_STRING, app);
523 }
f61f188 @spiritloose Initial commit
authored
524 env = make_env(r);
c115693 @spiritloose 'do $psgi_app' at post_config
authored
525 res = run_app(r, app, env);
f61f188 @spiritloose Initial commit
authored
526 if (res == NULL) {
527 server_error(r, "invalid response");
c115693 @spiritloose 'do $psgi_app' at post_config
authored
528 return HTTP_INTERNAL_SERVER_ERROR;
f61f188 @spiritloose Initial commit
authored
529 }
c115693 @spiritloose 'do $psgi_app' at post_config
authored
530 return output_response(r, res);
f61f188 @spiritloose Initial commit
authored
531 }
532
e284234 @spiritloose Call PERL_SYS_INIT3,PERL_SYS_TERM once per process
authored
533 static apr_status_t psgi_child_exit(void *p)
534 {
03fb93e @mattn win32 porting.
mattn authored
535 if (perlinterp == NULL) {
536 PERL_SET_CONTEXT(perlinterp);
537 PL_perl_destruct_level = 1;
538 perl_destruct(perlinterp);
539 perl_free(perlinterp);
540 PERL_SYS_TERM();
541 perlinterp = NULL;
542 }
e284234 @spiritloose Call PERL_SYS_INIT3,PERL_SYS_TERM once per process
authored
543 return OK;
544 }
545
546 static void psgi_child_init(apr_pool_t *p, server_rec *s)
547 {
548 apr_pool_cleanup_register(p, NULL, psgi_child_exit, psgi_child_exit);
549 }
550
c115693 @spiritloose 'do $psgi_app' at post_config
authored
551 static apr_status_t
552 psgi_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
ace1272 @spiritloose Make PerlInterpreter persistent
authored
553 {
554 int argc = 2;
555 char *argv[] = { "perl", "-e;0", NULL };
556 char **envp = NULL;
557
558 PERL_SYS_INIT3(&argc, (char ***) argv, &envp);
559 perlinterp = perl_alloc();
560 PL_perl_destruct_level = 1;
561 perl_construct(perlinterp);
562 perl_parse(perlinterp, xs_init, argc, argv, envp);
563 PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
564 perl_run(perlinterp);
565 init_perl_variables();
c115693 @spiritloose 'do $psgi_app' at post_config
authored
566
567 psgi_apps = apr_array_make(pconf, 10, sizeof(char *));
568 app_mapping = apr_hash_make(pconf);
569
570 return OK;
571 }
572
573 static int
574 psgi_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
575 {
576 dTHX;
577 int i;
578 char *file, **elts;
579 SV *app;
8fd6f10 @spiritloose Ignore first call psgi_post_config
authored
580 void *data;
581 const char *userdata_key = "psgi_post_config";
582
583 apr_pool_userdata_get(&data, userdata_key, s->process->pool);
584 if (data == NULL) {
585 apr_pool_userdata_set((const void *)1, userdata_key,
586 apr_pool_cleanup_null, s->process->pool);
587 return OK;
588 }
c115693 @spiritloose 'do $psgi_app' at post_config
authored
589 elts = (char **) psgi_apps->elts;
590 for (i = 0; i < psgi_apps->nelts; i++) {
591 file = elts[i];
592 app = load_psgi(pconf, file);
593 if (app == NULL) {
594 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, NULL,
595 "%s had compilation errors.", file);
596 return DONE;
597 }
598 apr_hash_set(app_mapping, file, APR_HASH_KEY_STRING, app);
599 }
098e77e @spiritloose ap_add_version_component
authored
600
601 ap_add_version_component(pconf, apr_psprintf(pconf, "mod_psgi/%s", MOD_PSGI_VERSION));
602
ace1272 @spiritloose Make PerlInterpreter persistent
authored
603 return OK;
604 }
605
f61f188 @spiritloose Initial commit
authored
606 static void psgi_register_hooks(apr_pool_t *p)
607 {
03fb93e @mattn win32 porting.
mattn authored
608 ap_hook_pre_config(psgi_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
609 ap_hook_post_config(psgi_post_config, NULL, NULL, APR_HOOK_MIDDLE);
610 ap_hook_child_init(psgi_child_init, NULL, NULL, APR_HOOK_MIDDLE);
611 ap_hook_handler(psgi_handler, NULL, NULL, APR_HOOK_MIDDLE);
f61f188 @spiritloose Initial commit
authored
612 }
613
614 static void *create_dir_config(apr_pool_t *p, char *path)
615 {
616 psgi_dir_config *c = apr_pcalloc(p, sizeof(psgi_dir_config));
ace1272 @spiritloose Make PerlInterpreter persistent
authored
617 c->file = NULL;
430ccf9 @fujiwara fix PATH_INFO and SCRIPT_NAME
fujiwara authored
618 c->location = path;
f61f188 @spiritloose Initial commit
authored
619 return (void *) c;
620 }
621
622 static const char *cmd_psgi_app(cmd_parms *cmd, void *conf, const char *v)
623 {
624 psgi_dir_config *c = (psgi_dir_config *) conf;
ace1272 @spiritloose Make PerlInterpreter persistent
authored
625 c->file = (char *) apr_pstrdup(cmd->pool, v);
c115693 @spiritloose 'do $psgi_app' at post_config
authored
626 *(const char **) apr_array_push(psgi_apps) = c->file;
f61f188 @spiritloose Initial commit
authored
627 return NULL;
628 }
629
630 static const command_rec command_table[] = {
631 AP_INIT_TAKE1("PSGIApp", cmd_psgi_app, NULL,
b991f34 @spiritloose Allow PSGIApp in .htaccess
authored
632 OR_LIMIT, "set PSGI application"),
f61f188 @spiritloose Initial commit
authored
633 { NULL }
634 };
635
636 module AP_MODULE_DECLARE_DATA psgi_module = {
637 STANDARD20_MODULE_STUFF,
638 create_dir_config, /* create per-dir config structures */
639 NULL, /* merge per-dir config structures */
640 NULL, /* create per-server config structures */
641 NULL, /* merge per-server config structures */
642 command_table, /* table of config file commands */
643 psgi_register_hooks /* register hooks */
644 };
645
Something went wrong with that request. Please try again.