Re: RubyInitHandler Problems

Shugo Maeda <[email protected]> Thu, 05 Aug 2004 15:06:47 +0900
Newsgroups gmane.comp.apache.mod-ruby
Message-ID <[email protected]>

Hi,

Michael Granger wrote:
> I've had some success with putting initialization code in a spot that 
> runs when the file is first required, but it'd be nice to have a 
> ChildInitHandler, too. Would it be difficult to add, Shugo-san?

How about this patch?

A simple example is here:

---- sample-child-init-handler.rb --------
require 'singleton'

class SampleChildInitHandler
   include Singleton

   def child_init(r)
     r.server.log_error("ChildInit#child_init called")
     return Apache::OK
   end
end
---------------------------
---- httpd.conf -----------
RubyRequire sample-child-init-handler
RubyChildInitHandler SampleChildInitHandler.instance
---------------------------


Shugo



Index: mod_ruby.c
===================================================================
--- mod_ruby.c	(revision 16)
+++ mod_ruby.c	(working copy)
@@ -174,6 +174,9 @@
     {"RubyCleanupHandler", ruby_cmd_cleanup_handler,
      NULL, OR_ALL, TAKE1,
      "set cleanup handler object"},
+    {"RubyChildInitHandler", ruby_cmd_child_init_handler,
+     NULL, RSRC_CONF, TAKE1,
+     "set child init handler object"},
     {NULL}
 };
 
@@ -484,9 +487,11 @@
     VALUE errmsg, reqobj;
 
     errmsg = ruby_get_error_info(state);
-    reqobj = (VALUE) ap_get_module_config(r->request_config, &ruby_module);
-    if (reqobj)
-	rb_apache_request_set_error(reqobj, errmsg, ruby_errinfo);
+    if (r->request_config) {
+	reqobj = (VALUE) ap_get_module_config(r->request_config, &ruby_module);
+	if (reqobj)
+	    rb_apache_request_set_error(reqobj, errmsg, ruby_errinfo);
+    }
     ruby_log_error_string(r->server, errmsg);
 }
 
@@ -776,12 +781,29 @@
     APR_CLEANUP_RETURN_SUCCESS();
 }
 
+static request_rec *fake_request_rec(server_rec *s, pool *p, char *hook)
+{
+    request_rec *r = (request_rec *) ap_pcalloc(p, sizeof(request_rec));
+    r->pool = p; 
+    r->server = s;
+    r->per_dir_config = NULL;
+    r->request_config = NULL;
+    r->uri = hook;
+    r->notes = NULL;
+    return r;
+}
+
+static int ruby_handler(request_rec *, array_header *, ID, int, int);
+
 #ifdef APACHE2
 static void ruby_child_init(pool *p, server_rec *s)
 #else /* Apache 1.x */
 static void ruby_child_init(server_rec *s, pool *p)
 #endif
 {
+    ruby_server_config *conf;
+    request_rec *r;
+
     if (!ruby_running()) {
 #if APR_HAS_THREADS
 	apr_status_t status;
@@ -807,6 +829,11 @@
 	ap_register_cleanup(p, NULL, ruby_child_cleanup, ap_null_cleanup);
 	ruby_is_running = 1;
     }
+
+    r = fake_request_rec(s, p, "RubyChildInitHandler");
+    conf = get_server_config(r->server);
+    ruby_handler(r, conf->ruby_child_init_handler,
+		 rb_intern("child_init"), 0, 0);
 }
 
 static void mod_ruby_clearenv()
@@ -981,7 +1008,7 @@
     mod_ruby_setup_loadpath(sconf, dconf);
     ruby_debug = Qfalse;
     ruby_verbose = Qfalse;
-    if (dconf->kcode)
+    if (dconf && dconf->kcode)
 	rb_set_kcode(dconf->kcode);
     rb_request = rb_get_request_object(r);
     rb_stdin = rb_stdout = rb_request;
@@ -1091,7 +1118,7 @@
 
     sconf = get_server_config(r->server);
     dconf = get_dir_config(r);
-    safe_level = dconf->safe_level;
+    safe_level = dconf ? dconf->safe_level : MR_DEFAULT_SAFE_LEVEL;
     handlers = (char **) handlers_arr->elts;
     handlers_len = handlers_arr->nelts;
     iarg->retval = DECLINED;
Index: mod_ruby.h
===================================================================
--- mod_ruby.h	(revision 16)
+++ mod_ruby.h	(working copy)
@@ -101,6 +101,7 @@
     array_header *load_path;
     table *env;
     int timeout;
+    array_header *ruby_child_init_handler;
 } ruby_server_config;
 
 typedef struct {
@@ -165,8 +166,10 @@
 	((ruby_server_config *) ap_get_module_config(s->module_config, \
 						     &ruby_module))
 #define get_dir_config(r) \
-	((ruby_dir_config *) ap_get_module_config(r->per_dir_config, \
-						  &ruby_module))
+	(r->per_dir_config ? \
+	   ((ruby_dir_config *) ap_get_module_config(r->per_dir_config, \
+						    &ruby_module)) : \
+	   NULL)
 
 #if APR_HAS_THREADS
 typedef void *(*ruby_interp_func_t)(void*);
Index: ruby_config.c
===================================================================
--- ruby_config.c	(revision 16)
+++ ruby_config.c	(working copy)
@@ -46,9 +46,21 @@
     conf->load_path = ap_make_array(p, 1, sizeof(char*));
     conf->env = ap_make_table(p, 1);
     conf->timeout = MR_DEFAULT_TIMEOUT;
+    conf->ruby_child_init_handler = NULL;
     return conf;
 }
 
+static array_header *merge_handlers(pool *p,
+				    array_header *base,
+				    array_header *add)
+{
+    if (base == NULL)
+	return add;
+    if (add == NULL)
+	return base;
+    return ap_append_arrays(p, add, base);
+}
+
 void *ruby_merge_server_config(pool *p, void *basev, void *addv)
 {
     ruby_server_config *new =
@@ -67,6 +79,9 @@
     }
     new->env = ap_overlay_tables(p, add->env, base->env);
     new->timeout = add->timeout ? add->timeout : base->timeout;
+    new->ruby_child_init_handler =
+	merge_handlers(p, base->ruby_child_init_handler,
+		       add->ruby_child_init_handler);
     return (void *) new;
 }
 
@@ -95,17 +110,6 @@
     return conf;
 }
 
-static array_header *merge_handlers(pool *p,
-				    array_header *base,
-				    array_header *add)
-{
-    if (base == NULL)
-	return add;
-    if (add == NULL)
-	return base;
-    return ap_append_arrays(p, add, base);
-}
-
 void *ruby_merge_dir_config(pool *p, void *basev, void *addv)
 {
     ruby_dir_config *new =
@@ -409,6 +413,15 @@
     return NULL;
 }
 
+const char *ruby_cmd_child_init_handler(cmd_parms *cmd,
+					void *dummy, char *arg)
+{
+    ruby_server_config *conf = get_server_config(cmd->server);
+
+    push_handler(cmd->pool, conf->ruby_child_init_handler, arg);
+    return NULL;
+}
+
 /*
  * Local variables:
  * mode: C
Index: ruby_config.h
===================================================================
--- ruby_config.h	(revision 16)
+++ ruby_config.h	(working copy)
@@ -54,6 +54,7 @@
 const char *ruby_cmd_post_read_request_handler(cmd_parms*, ruby_dir_config*, char*);
 const char *ruby_cmd_init_handler(cmd_parms*, ruby_dir_config*, char*);
 const char *ruby_cmd_cleanup_handler(cmd_parms*, ruby_dir_config*, char*);
+const char *ruby_cmd_child_init_handler(cmd_parms*, void*, char*);
 
 #endif /* !RUBY_CONFIG_H */
 
Index: request.c
===================================================================
--- request.c	(revision 16)
+++ request.c	(working copy)
@@ -125,6 +125,8 @@
     request_rec *r = (request_rec *) data;
     VALUE reqobj;
 
+    if (r->request_config == NULL)
+	APR_CLEANUP_RETURN_SUCCESS();
     reqobj = (VALUE) ap_get_module_config(r->request_config, &ruby_module);
     if (reqobj == 0) APR_CLEANUP_RETURN_SUCCESS();
     if (TYPE(reqobj) == T_DATA) {
@@ -173,20 +175,23 @@
 #endif
     
     rb_apache_register_object(obj);
-    ap_set_module_config(r->request_config, &ruby_module, (void *) obj);
+    if (r->request_config)
+	ap_set_module_config(r->request_config, &ruby_module, (void *) obj);
     ap_register_cleanup(r->pool, (void *) r,
 			cleanup_request_object, ap_null_cleanup);
-    switch (dconf->output_mode) {
-    case MR_OUTPUT_SYNC_HEADER:
-	FL_SET(obj, REQ_SYNC_HEADER);
-	break;
-    case MR_OUTPUT_SYNC:
-	FL_SET(obj, REQ_SYNC_HEADER);
-	FL_SET(obj, REQ_SYNC_OUTPUT);
-	break;
-    case MR_OUTPUT_NOSYNC:
-    default:
-	break;
+    if (dconf) {
+	switch (dconf->output_mode) {
+	    case MR_OUTPUT_SYNC_HEADER:
+		FL_SET(obj, REQ_SYNC_HEADER);
+		break;
+	    case MR_OUTPUT_SYNC:
+		FL_SET(obj, REQ_SYNC_HEADER);
+		FL_SET(obj, REQ_SYNC_OUTPUT);
+		break;
+	    case MR_OUTPUT_NOSYNC:
+	    default:
+		break;
+	}
     }
     return obj;
 }
@@ -196,13 +201,12 @@
     VALUE reqobj;
 
     if (r == NULL) return Qnil;
-    reqobj = (VALUE) ap_get_module_config(r->request_config, &ruby_module);
-    if (reqobj) {
-	return reqobj;
+    if (r->request_config) {
+	reqobj = (VALUE) ap_get_module_config(r->request_config, &ruby_module);
+	if (reqobj)
+	    return reqobj;
     }
-    else {
-	return apache_request_new(r);
-    }
+    return apache_request_new(r);
 }
 
 static request_data *get_request_data(VALUE obj)