2 suPHP - (c)2002-2005 Sebastian Marsching <sebastian@marsching.com>
4 This file is part of suPHP.
6 suPHP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 suPHP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with suPHP; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "http_config.h"
26 #include "http_request.h"
27 #include "http_core.h"
28 #include "http_protocol.h"
29 #include "http_main.h"
31 #include "util_script.h"
34 #define SUPHP_CONFIG_MODE_SERVER 1
35 #define SUPHP_CONFIG_MODE_DIRECTORY 2
37 #define SUPHP_ENGINE_OFF 0
38 #define SUPHP_ENGINE_ON 1
39 #define SUPHP_ENGINE_UNDEFINED 2
41 #ifndef SUPHP_PATH_TO_SUPHP
42 #define SUPHP_PATH_TO_SUPHP "/usr/sbin/suphp"
46 /* Module declaration */
47 module MODULE_VAR_EXPORT suphp_module
;
50 /* Configuration structure */
52 int engine
; // Status of suPHP_Engine
54 int cmode
; // Server of directory configuration?
55 #ifdef SUPHP_USE_USERGROUP
64 /* Configuration mergers/creators */
66 static void *suphp_create_dir_config(pool
*p
, char *dir
) {
67 suphp_conf
*cfg
= (suphp_conf
*) ap_pcalloc(p
, sizeof(suphp_conf
));
68 cfg
->php_config
= NULL
;
69 cfg
->engine
= SUPHP_ENGINE_UNDEFINED
;
70 cfg
->cmode
= SUPHP_CONFIG_MODE_DIRECTORY
;
72 #ifdef SUPHP_USE_USERGROUP
73 cfg
->target_user
= NULL
;
74 cfg
->target_group
= NULL
;
77 /* Create table with 0 initial elements */
78 /* This size may be increased for performance reasons */
79 cfg
->handlers
= ap_make_table(p
, 0);
84 static void *suphp_merge_dir_config(pool
*p
, void *base
, void *overrides
) {
85 suphp_conf
*parent
= (suphp_conf
*) base
;
86 suphp_conf
*child
= (suphp_conf
*) overrides
;
87 suphp_conf
*merged
= (suphp_conf
*) ap_pcalloc(p
, sizeof(suphp_conf
));
89 merged
->cmode
= SUPHP_CONFIG_MODE_DIRECTORY
;
91 if (child
->php_config
)
92 merged
->php_config
= ap_pstrdup(p
, child
->php_config
);
93 else if (parent
->php_config
)
94 merged
->php_config
= ap_pstrdup(p
, parent
->php_config
);
96 merged
->php_config
= NULL
;
98 if (child
->engine
!= SUPHP_ENGINE_UNDEFINED
)
99 merged
->engine
= child
->engine
;
101 merged
->engine
= parent
->engine
;
103 #ifdef SUPHP_USE_USERGROUP
104 if (child
->target_user
)
105 merged
->target_user
= ap_pstrdup(p
, child
->target_user
);
106 else if (parent
->target_user
)
107 merged
->target_user
= ap_pstrdup(p
, parent
->target_user
);
109 merged
->target_user
= NULL
;
111 if (child
->target_group
)
112 merged
->target_group
= ap_pstrdup(p
, child
->target_group
);
113 else if (parent
->target_group
)
114 merged
->target_group
= ap_pstrdup(p
, parent
->target_group
);
116 merged
->target_group
= NULL
;
119 merged
->handlers
= ap_overlay_tables(p
, child
->handlers
, parent
->handlers
);
121 return (void *) merged
;
125 static void *suphp_create_server_config(pool
*p
, server_rec
*s
) {
126 suphp_conf
*cfg
= (suphp_conf
*) ap_pcalloc(p
, sizeof(suphp_conf
));
128 cfg
->engine
= SUPHP_ENGINE_UNDEFINED
;
129 cfg
->php_path
= NULL
;
130 cfg
->cmode
= SUPHP_CONFIG_MODE_SERVER
;
132 #ifdef SUPHP_USE_USERGROUP
133 cfg
->target_user
= NULL
;
134 cfg
->target_group
= NULL
;
137 /* Create table with 0 initial elements */
138 /* This size may be increased for performance reasons */
139 cfg
->handlers
= ap_make_table(p
, 0);
145 static void *suphp_merge_server_config(pool
*p
, void *base
, void *overrides
) {
146 suphp_conf
*parent
= (suphp_conf
*) base
;
147 suphp_conf
*child
= (suphp_conf
*) overrides
;
148 suphp_conf
*merged
= (suphp_conf
*) ap_pcalloc(p
, sizeof(suphp_conf
));
150 if (child
->engine
!= SUPHP_ENGINE_UNDEFINED
)
151 merged
->engine
= child
->engine
;
153 merged
->engine
= parent
->engine
;
155 if (child
->php_path
!= NULL
)
156 merged
->php_path
= ap_pstrdup(p
, child
->php_path
);
158 merged
->php_path
= ap_pstrdup(p
, parent
->php_path
);
160 #ifdef SUPHP_USE_USERGROUP
161 if (child
->target_user
)
162 merged
->target_user
= ap_pstrdup(p
, child
->target_user
);
163 else if (parent
->target_user
)
164 merged
->target_user
= ap_pstrdup(p
, parent
->target_user
);
166 merged
->target_user
= NULL
;
168 if (child
->target_group
)
169 merged
->target_group
= ap_pstrdup(p
, child
->target_group
);
170 else if (parent
->target_group
)
171 merged
->target_group
= ap_pstrdup(p
, parent
->target_group
);
173 merged
->target_group
= NULL
;
176 merged
->handlers
= ap_overlay_tables(p
, child
->handlers
, parent
->handlers
);
178 return (void *) merged
;
182 /* Command handlers */
184 static const char *suphp_handle_cmd_engine(cmd_parms
*cmd
, void *mconfig
,
189 cfg
= (suphp_conf
*) mconfig
;
191 cfg
= (suphp_conf
*) ap_get_module_config(cmd
->server
->module_config
,
195 cfg
->engine
= SUPHP_ENGINE_ON
;
197 cfg
->engine
= SUPHP_ENGINE_OFF
;
203 static const char *suphp_handle_cmd_config(cmd_parms
*cmd
, void *mconfig
,
205 suphp_conf
*cfg
= (suphp_conf
*) mconfig
;
207 cfg
->php_config
= ap_pstrdup(cmd
->pool
, arg
);
213 #ifdef SUPHP_USE_USERGROUP
214 static const char *suphp_handle_cmd_user_group(cmd_parms
*cmd
, void *mconfig
,
220 cfg
= (suphp_conf
*) mconfig
;
222 cfg
= ap_get_module_config(cmd
->server
->module_config
, &suphp_module
);
224 cfg
->target_user
= ap_pstrdup(cmd
->pool
, arg1
);
225 cfg
->target_group
= ap_pstrdup(cmd
->pool
, arg2
);
232 static const char *suphp_handle_cmd_add_handler(cmd_parms
*cmd
, void *mconfig
,
236 cfg
= (suphp_conf
*) mconfig
;
238 cfg
= ap_get_module_config(cmd
->server
->module_config
, &suphp_module
);
240 // Mark active handlers with '1'
241 ap_table_set(cfg
->handlers
, arg
, "1");
246 static const char *suphp_handle_cmd_remove_handler(cmd_parms
*cmd
,
251 cfg
= (suphp_conf
*) mconfig
;
253 cfg
= ap_get_module_config(cmd
->server
->module_config
, &suphp_module
);
255 // Mark deactivated handlers with '0'
256 ap_table_set(cfg
->handlers
, arg
, "0");
262 static const char *suphp_handle_cmd_phppath(cmd_parms
*cmd
, void* mconfig
, const char *arg
)
266 cfg
= (suphp_conf
*) ap_get_module_config(cmd
->server
->module_config
, &suphp_module
);
268 cfg
->php_path
= ap_pstrdup(cmd
->pool
, arg
);
276 static const command_rec suphp_cmds
[] = {
277 {"suPHP_Engine", suphp_handle_cmd_engine
, NULL
, RSRC_CONF
|ACCESS_CONF
,
278 FLAG
, "Whether suPHP is on or off, default is off"},
279 {"suPHP_ConfigPath", suphp_handle_cmd_config
, NULL
, OR_OPTIONS
, TAKE1
,
280 "Where the php.ini resides, default is the PHP default"},
281 #ifdef SUPHP_USE_USERGROUP
282 {"suPHP_UserGroup", suphp_handle_cmd_user_group
, NULL
,
283 RSRC_CONF
|ACCESS_CONF
, TAKE2
, "User and group scripts shall be run as"},
285 {"suPHP_AddHandler", suphp_handle_cmd_add_handler
, NULL
, RSRC_CONF
| ACCESS_CONF
,
286 ITERATE
, "Tells mod_suphp to handle these MIME-types"},
287 {"suphp_RemoveHandler", suphp_handle_cmd_remove_handler
, NULL
, RSRC_CONF
| ACCESS_CONF
,
288 ITERATE
, "Tells mod_suphp not to handle these MIME-types"},
289 {"suPHP_PHPPath", suphp_handle_cmd_phppath
, NULL
, RSRC_CONF
, TAKE1
, "Path to the PHP binary used to render source view"},
294 /* Helper function which is called when spawning child process */
296 int suphp_source_child(void *rp
, child_info
*cinfo
) {
297 request_rec
*r
= (request_rec
*) rp
;
299 pool
*p
= r
->main
? r
->main
->pool
: r
->pool
;
302 conf
= ap_get_module_config(r
->server
->module_config
, &suphp_module
);
304 /* We want to log output written to stderr */
305 ap_error_log2stderr(r
->server
);
307 /* prepare argv for new process */
309 argv
= ap_palloc(p
, 4 * sizeof(char *));
310 argv
[0] = ap_pstrdup(p
, conf
->php_path
);
312 argv
[2] = ap_pstrdup(p
, r
->filename
);
315 /* prepare environment */
317 env
= ap_create_environment(p
, r
->subprocess_env
);
319 /* We cannot use ap_call_exec because of the interference with suExec */
320 /* So we do everything ourselves */
322 /* mandatory cleanup before execution */
323 ap_cleanup_for_exec();
325 execve(ap_pstrdup(p
, conf
->php_path
), argv
, env
);
327 /* We are still here? Okay - exec failed */
328 ap_log_error(APLOG_MARK
, APLOG_ERR
, NULL
, "exec of %s failed",
336 int suphp_child(void *rp
, child_info
*cinfo
) {
337 request_rec
*r
= (request_rec
*) rp
;
338 core_dir_config
*core_conf
;
339 pool
*p
= r
->main
? r
->main
->pool
: r
->pool
;
343 core_conf
= (core_dir_config
*) ap_get_module_config(
344 r
->per_dir_config
, &core_module
);
346 /* We want to log output written to stderr */
347 ap_error_log2stderr(r
->server
);
349 /* prepare argv for new process */
351 argv
= ap_palloc(p
, 2 * sizeof(char *));
352 argv
[0] = SUPHP_PATH_TO_SUPHP
;
355 /* prepare environment */
357 env
= ap_create_environment(p
, r
->subprocess_env
);
359 /* We cannot use ap_call_exec because of the interference with suExec */
360 /* So we do everything ourselves */
362 /* Set resource limits from core config */
365 if (core_conf
->limit_cpu
!= NULL
) {
366 if ((setrlimit(RLIMIT_CPU
, core_conf
->limit_cpu
)) != 0) {
367 ap_log_error(APLOG_MARK
, APLOG_ERR
, r
->server
,
368 "setrlimit: failed to set CPU usage limit");
371 #endif /* RLIMIT_CPU */
373 if (core_conf
->limit_nproc
!= NULL
) {
374 if ((setrlimit(RLIMIT_NPROC
, core_conf
->limit_nproc
)) != 0) {
375 ap_log_error(APLOG_MARK
, APLOG_ERR
, r
->server
,
376 "setrlimit: failed to set process limit");
379 #endif /* RLIMIT_NPROC */
381 if (core_conf
->limit_mem
!= NULL
) {
382 if ((setrlimit(RLIMIT_AS
, core_conf
->limit_mem
)) != 0) {
383 ap_log_error(APLOG_MARK
, APLOG_ERR
, r
->server
,
384 "setrlimit: failed to set memory limit");
387 #endif /* RLIMIT_VMEM */
389 if (core_conf
->limit_mem
!= NULL
) {
390 if ((setrlimit(RLIMIT_DATA
, core_conf
->limit_mem
)) != 0) {
391 ap_log_error(APLOG_MARK
, APLOG_ERR
, r
->server
,
392 "setrlimit: failed to set memory limit");
395 #endif /* RLIMIT_VMEM */
397 if (core_conf
->limit_mem
!= NULL
) {
398 if ((setrlimit(RLIMIT_VMEM
, core_conf
->limit_mem
)) != 0) {
399 ap_log_error(APLOG_MARK
, APLOG_ERR
, r
->server
,
400 "setrlimit: failed to set memory limit");
403 #endif /* RLIMIT_VMEM */
405 /* mandatory cleanup before execution */
406 ap_cleanup_for_exec();
408 execve(SUPHP_PATH_TO_SUPHP
, argv
, env
);
410 /* We are still here? Okay - exec failed */
411 ap_log_error(APLOG_MARK
, APLOG_ERR
, NULL
, "exec of %s failed",
412 SUPHP_PATH_TO_SUPHP
);
421 static int suphp_source_handler(request_rec
*r
) {
426 BUFF
*script_in
, *script_out
, *script_err
;
427 char buffer
[HUGE_STRING_LEN
];
429 if (strcmp(r
->method
, "GET")) {
433 conf
= ap_get_module_config(r
->server
->module_config
, &suphp_module
);
434 if (conf
->php_path
== NULL
) {
438 p
= r
->main
? r
->main
->pool
: r
->pool
;
440 fd
= open(r
->filename
, O_NOCTTY
, O_RDONLY
);
443 } else if (errno
== EACCES
) {
444 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, r
, "access to %s denied",
446 return HTTP_FORBIDDEN
;
447 } else if (errno
== ENOENT
|| errno
== ENOTDIR
) {
448 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, r
, "File does not exist: %s",
450 return HTTP_NOT_FOUND
;
452 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, r
, "could open file: %s",
454 return HTTP_NOT_FOUND
;
457 /* Fork child process */
459 if (!ap_bspawn_child(p
, suphp_source_child
, (void *) r
, kill_after_timeout
,
460 &script_in
, &script_out
, &script_err
)) {
461 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, r
,
462 "couldn't spawn child process for: %s", r
->filename
);
463 return HTTP_INTERNAL_SERVER_ERROR
;
466 /* Read request body */
468 if (ap_should_client_block(r
)) {
469 char buffer
[HUGE_STRING_LEN
];
472 ap_hard_timeout("reading request body", r
);
474 while (ap_get_client_block(r
, buffer
, HUGE_STRING_LEN
) > 0) {
479 ap_bflush(script_in
);
483 ap_bclose(script_in
);
485 /* Transfer output from PHP to client */
488 /* Output headers and body */
490 r
->content_type
= "text/html";
491 ap_send_http_header(r
);
492 if (!r
->header_only
) {
493 ap_send_fb(script_out
, r
);
495 ap_bclose(script_out
);
496 /* Errors have already been logged by child */
497 ap_bclose(script_err
);
505 static int suphp_handler(request_rec
*r
) {
509 #ifdef SUPHP_USE_USERGROUP
510 char *ud_user
= NULL
;
511 char *ud_group
= NULL
;
518 char *auth_user
= NULL
;
519 char *auth_pass
= NULL
;
523 BUFF
*script_in
, *script_out
, *script_err
;
527 sconf
= ap_get_module_config(r
->server
->module_config
, &suphp_module
);
528 dconf
= ap_get_module_config(r
->per_dir_config
, &suphp_module
);
530 p
= r
->main
? r
->main
->pool
: r
->pool
;
532 /* only handle request if mod_suphp is active for this handler */
533 /* check only first byte of value (second has to be \0) */
534 if (r
->handler
!= NULL
) {
535 handler
= r
->handler
;
537 handler
= r
->content_type
;
539 if ((ap_table_get(dconf
->handlers
, handler
) == NULL
)) {
540 if ((ap_table_get(sconf
->handlers
, handler
) == NULL
)
541 || (*(ap_table_get(sconf
->handlers
, handler
)) == '0')) {
544 } else if (*(ap_table_get(dconf
->handlers
, handler
)) == '0') {
548 /* check if suPHP is enabled for this request */
550 if (((sconf
->engine
!= SUPHP_ENGINE_ON
)
551 && (dconf
->engine
!= SUPHP_ENGINE_ON
))
552 || ((sconf
->engine
== SUPHP_ENGINE_ON
)
553 && (dconf
->engine
== SUPHP_ENGINE_OFF
)))
556 /* check if file is existing and accessible */
558 rv
= stat(ap_pstrdup(p
, r
->filename
), &finfo
);
561 } else if (errno
== EACCES
) {
562 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, r
, "access to %s denied",
564 return HTTP_FORBIDDEN
;
565 } else if (errno
== ENOENT
|| errno
== ENOTDIR
) {
566 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, r
, "File does not exist: %s",
568 return HTTP_NOT_FOUND
;
570 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, r
, "could not get fileinfo: %s",
572 return HTTP_NOT_FOUND
;
575 #ifdef SUPHP_USE_USERGROUP
576 if ((sconf
->target_user
== NULL
|| sconf
->target_group
== NULL
)
577 && (dconf
->target_user
== NULL
|| dconf
->target_group
== NULL
)) {
579 /* Identify mod_userdir request
580 As Apache 1.3 does not yet provide a clean way to see
581 whether a request was handled by mod_userdir, we assume
582 this is true for any request beginning with ~ */
584 int ud_success
= 0; /* set to 1 on success */
586 if (!strncmp("/~", r
->uri
, 2)) {
587 char *username
= ap_pstrdup(r
->pool
, r
->uri
+ 2);
588 char *pos
= strchr(username
, '/');
591 if (strlen(username
)) {
596 if ((pw
= getpwnam(username
)) != NULL
) {
599 if ((gr
= getgrgid(gid
)) != NULL
) {
600 grpname
= gr
->gr_name
;
602 if ((grpname
= ap_palloc(r
->pool
, 16)) == NULL
) {
603 return HTTP_INTERNAL_SERVER_ERROR
;
605 ap_snprintf(grpname
, 16, "#%ld", (long) gid
);
617 /* This is not a userdir request and user/group are not
618 set, so log the error and return */
619 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, r
,
620 "No user or group set - set suPHP_UserGroup");
621 return HTTP_INTERNAL_SERVER_ERROR
;
624 #endif /* SUPHP_USE_USERGROUP */
627 /* prepare environment for new process */
629 ap_add_common_vars(r
);
632 ap_table_unset(r
->subprocess_env
, "SUPHP_PHP_CONFIG");
633 ap_table_unset(r
->subprocess_env
, "SUPHP_AUTH_USER");
634 ap_table_unset(r
->subprocess_env
, "SUPHP_AUTH_PW");
636 #ifdef SUPHP_USE_USERGROUP
637 ap_table_unset(r
->subprocess_env
, "SUPHP_USER");
638 ap_table_unset(r
->subprocess_env
, "SUPHP_GROUP");
639 #endif /* SUPHP_USE_USERGROUP */
641 if (dconf
->php_config
) {
642 ap_table_set(r
->subprocess_env
, "SUPHP_PHP_CONFIG", dconf
->php_config
);
645 ap_table_set(r
->subprocess_env
, "SUPHP_HANDLER", handler
);
649 auth
= ap_table_get(r
->headers_in
, "Authorization");
650 if (auth
&& auth
[0] != 0 && strncmp(auth
, "Basic ", 6) == 0) {
653 user
= ap_pbase64decode(p
, auth
+ 6);
655 pass
= strchr(user
, ':');
658 auth_user
= ap_pstrdup(p
, user
);
659 auth_pass
= ap_pstrdup(p
, pass
);
665 if (auth_user
&& auth_pass
) {
666 ap_table_setn(r
->subprocess_env
, "SUPHP_AUTH_USER", auth_user
);
667 ap_table_setn(r
->subprocess_env
, "SUPHP_AUTH_PW", auth_pass
);
670 #ifdef SUPHP_USE_USERGROUP
671 if (dconf
->target_user
) {
672 ap_table_set(r
->subprocess_env
, "SUPHP_USER", dconf
->target_user
);
673 } else if (sconf
->target_user
) {
674 ap_table_set(r
->subprocess_env
, "SUPHP_USER", sconf
->target_user
);
676 ap_table_set(r
->subprocess_env
, "SUPHP_USER", ud_user
);
679 if (dconf
->target_group
) {
680 ap_table_set(r
->subprocess_env
, "SUPHP_GROUP", dconf
->target_group
);
681 } else if (sconf
->target_group
) {
682 ap_table_set(r
->subprocess_env
, "SUPHP_GROUP", sconf
->target_group
);
684 ap_table_set(r
->subprocess_env
, "SUPHP_GROUP", ud_group
);
686 #endif /* SUPHP_USE_USERGROUP */
688 /* Fork child process */
690 if (!ap_bspawn_child(p
, suphp_child
, (void *) r
, kill_after_timeout
,
691 &script_in
, &script_out
, &script_err
)) {
692 ap_log_rerror(APLOG_MARK
, APLOG_ERR
, r
,
693 "couldn't spawn child process for: %s", r
->filename
);
694 return HTTP_INTERNAL_SERVER_ERROR
;
697 /* Transfer request body to script */
699 if ((rv
= ap_setup_client_block(r
, REQUEST_CHUNKED_ERROR
)) != OK
) {
700 /* Call failed, return status */
704 if (ap_should_client_block(r
)) {
705 char buffer
[HUGE_STRING_LEN
];
708 ap_hard_timeout("reading request body", r
);
710 while ((len_read
= ap_get_client_block(r
, buffer
, HUGE_STRING_LEN
))
713 if (ap_bwrite(script_in
, buffer
, len_read
) < len_read
) {
714 /* silly script stopped reading, soak up remaining message */
715 while (ap_get_client_block(r
, buffer
, HUGE_STRING_LEN
) > 0) {
722 ap_bflush(script_in
);
726 ap_bclose(script_in
);
728 /* Transfer output from script to client */
731 const char *location
;
732 char hbuffer
[MAX_STRING_LEN
];
733 char buffer
[HUGE_STRING_LEN
];
735 rv
= ap_scan_script_header_err_buff(r
, script_out
, hbuffer
);
736 if (rv
== HTTP_NOT_MODIFIED
) {
739 return HTTP_INTERNAL_SERVER_ERROR
;
742 location
= ap_table_get(r
->headers_out
, "Location");
743 if (location
&& r
->status
== 200) {
744 /* Soak up all the script output */
745 ap_hard_timeout("reading from script", r
);
746 while (ap_bgets(buffer
, HUGE_STRING_LEN
, script_out
) > 0) {
750 ap_bclose(script_out
);
751 ap_bclose(script_err
);
753 if (location
[0] == '/') {
754 /* Redirect has always GET method */
755 r
->method
= ap_pstrdup(p
, "GET");
756 r
->method_number
= M_GET
;
758 /* Remove Content-Length - redirect should not read *
760 ap_table_unset(r
->headers_in
, "Content-Length");
762 /* Do the redirect */
763 ap_internal_redirect_handler(location
, r
);
766 /* Script did not set status 302 - so it does not want *
767 * to send its own body. Simply set redirect status */
772 /* Output headers and body */
774 ap_send_http_header(r
);
775 if (!r
->header_only
) {
776 ap_send_fb(script_out
, r
);
778 ap_bclose(script_out
);
779 /* Errors have already been logged by child */
780 ap_bclose(script_err
);
789 static handler_rec suphp_handlers
[] = {
790 {"*", suphp_handler
},
791 {"x-httpd-php-source", suphp_source_handler
},
792 {"application/x-httpd-php-source", suphp_source_handler
},
796 /* Module definition */
798 module MODULE_VAR_EXPORT suphp_module
= {
799 STANDARD_MODULE_STUFF
,
800 NULL
, /* initializer */
801 suphp_create_dir_config
, /* create directory config */
802 suphp_merge_dir_config
, /* merge directory config */
803 suphp_create_server_config
, /* create server config */
804 suphp_merge_server_config
, /* merge server config */
805 suphp_cmds
, /* command table */
806 suphp_handlers
, /* content handlers */
807 NULL
, /* URI-to-filename translation */
808 NULL
, /* check/validate user_id */
809 NULL
, /* check user_id is valid *here* */
810 NULL
, /* check access by host address */
811 NULL
, /* MIME type checker/setter */
814 NULL
, /* header parser */
815 NULL
, /* process initialaization */
816 NULL
, /* process exit/cleanup */
817 NULL
/* post read_request handling */