Skip to content

HTTPS clone URL

Subversion checkout URL

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