Re: patch: add error log handler, expose parsed_uri and more

Matthew Kent <[email protected]> Mon, 30 Jul 2007 11:09:04 -0700
Newsgroups gmane.comp.apache.mod-ruby
Message-ID <1185818944.6486.224.camel@fuego>
--=-vvl4qVKhLGbe9jWZbIK7
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

On Mon, 2007-30-07 at 11:32 +0900, Shugo Maeda wrote:
> Hi,
> Sorry, I missed your previous mail.
> 
> On 07/30/2007 09:15 AM, Matthew Kent wrote:
> > Bigger patch now that includes the last couple I sent to the list and adds
> > a RubyErrorLogHandler hook for APACHE2 which can be used to log per
> > request errors with
> 
> Thank you. I'll merge your patch.
> 
> But I got the following error:
> 
> $ patch -p1 < /tmp/mod_ruby-r133-additions_complete.patch
> patching file apachelib.c
> patching file apachelib.h
> patching file connection.c
> patching file error.c
> patching file Makefile.in
> patching file mod_ruby.c
> patching file mod_ruby.h
> patching file request.c
> patching file ruby_config.c
> patching file ruby_config.h
> patching file uri.c
> patch unexpectedly ends in middle of line
> patch: **** malformed patch at line 786:
> 
> What's wrong with this patch?
> 
> Shugo
> 
> 

Oops sorry, I must have trimmed the last newline from the patch when
tidying it up. 

Try this one.
-- 
Matthew Kent <[email protected]>
http://magoazul.com

--=-vvl4qVKhLGbe9jWZbIK7
Content-Disposition: attachment; filename=mod_ruby-r133-additions_complete.1.patch
Content-Type: text/x-patch; name=mod_ruby-r133-additions_complete.1.patch; charset=ANSI_X3.4-1968
Content-Transfer-Encoding: 7bit

does the following:
- expose more useful constants
- expose parsed uri data
- adds a per request error log hook
- exposes a few more useful data points in core httpd structs

mkent@

diff -urN mod_ruby_orig/apachelib.c mod_ruby/apachelib.c
--- mod_ruby_orig/apachelib.c	2007-07-22 20:52:47.000000000 -0700
+++ mod_ruby/apachelib.c	2007-07-25 23:16:37.000000000 -0700
@@ -389,6 +389,32 @@
     rb_define_const(rb_mApache, "REMOTE_DOUBLE_REV",
 		    INT2NUM(REMOTE_DOUBLE_REV));
 
+#ifdef APACHE2
+    rb_define_const(rb_mApache, "AP_CONN_UNKNOWN",
+		    INT2NUM(AP_CONN_UNKNOWN));
+    rb_define_const(rb_mApache, "AP_CONN_CLOSE",
+		    INT2NUM(AP_CONN_CLOSE));
+    rb_define_const(rb_mApache, "AP_CONN_KEEPALIVE",
+		    INT2NUM(AP_CONN_KEEPALIVE));
+#endif
+
+    rb_define_const(rb_mApache, "APLOG_EMERG",
+		    INT2NUM(APLOG_EMERG));
+    rb_define_const(rb_mApache, "APLOG_ALERT",
+		    INT2NUM(APLOG_ALERT));
+    rb_define_const(rb_mApache, "APLOG_CRIT",
+		    INT2NUM(APLOG_CRIT));
+    rb_define_const(rb_mApache, "APLOG_ERR",
+		    INT2NUM(APLOG_ERR));
+    rb_define_const(rb_mApache, "APLOG_WARNING",
+		    INT2NUM(APLOG_WARNING));
+    rb_define_const(rb_mApache, "APLOG_NOTICE",
+		    INT2NUM(APLOG_NOTICE));
+    rb_define_const(rb_mApache, "APLOG_INFO",
+		    INT2NUM(APLOG_INFO));
+    rb_define_const(rb_mApache, "APLOG_DEBUG",
+		    INT2NUM(APLOG_DEBUG));
+
     /* Policy constants for setup_client_block() */
     rb_define_const(rb_mApache, "REQUEST_NO_BODY",
 		    INT2NUM(REQUEST_NO_BODY));
@@ -425,6 +451,8 @@
 #ifdef APACHE2
     rb_init_apache_bucket();
 #endif
+    rb_init_apache_uri();
+    rb_init_apache_error();
 }
 
 /*
diff -urN mod_ruby_orig/apachelib.h mod_ruby/apachelib.h
--- mod_ruby_orig/apachelib.h	2007-07-22 20:52:47.000000000 -0700
+++ mod_ruby/apachelib.h	2007-07-25 23:16:37.000000000 -0700
@@ -80,6 +80,16 @@
 void rb_init_apache_bucket();
 #endif
 
+/* uri.c */
+extern VALUE rb_cApacheUri;
+void rb_init_apache_uri();
+VALUE rb_apache_uri_new(uri_components *uri);
+
+/* error.c */
+extern VALUE rb_cApacheError;
+void rb_init_apache_error();
+VALUE rb_apache_error_new(request_rec *r, error_log_data *error);
+
 /* --- Libapreq Extensions ------------------------------  */
 
 extern VALUE rb_eApacheRequestError;
diff -urN mod_ruby_orig/connection.c mod_ruby/connection.c
--- mod_ruby_orig/connection.c	2007-07-22 20:52:47.000000000 -0700
+++ mod_ruby/connection.c	2007-07-25 23:16:37.000000000 -0700
@@ -36,6 +36,13 @@
 }
 
 DEFINE_BOOL_ATTR_READER(connection_aborted, conn_rec, aborted);
+/* in APACHE1: -1 fatal error, 0 undecided, 1 yes 
+ *    APACHE2: 0 AP_CONN_UNKNOWN, 1 AP_CONN_CLOSE, 2 AP_CONN_KEEPALIVE
+ * fun... */
+DEFINE_INT_ATTR_READER(connection_keepalive, conn_rec, keepalive);
+/* -1 yes/failure, 0 not yet, 1 yes/success */
+DEFINE_INT_ATTR_READER(connection_double_reverse, conn_rec, double_reverse);
+DEFINE_INT_ATTR_READER(connection_keepalives, conn_rec, keepalives);
 DEFINE_STRING_ATTR_READER(connection_remote_ip, conn_rec, remote_ip);
 DEFINE_STRING_ATTR_READER(connection_remote_host, conn_rec, remote_host);
 DEFINE_STRING_ATTR_READER(connection_remote_logname, conn_rec, remote_logname);
@@ -124,12 +131,39 @@
 #endif
 }
 
+#ifdef APACHE2
+static VALUE connection_notes(VALUE self)
+{
+    conn_rec *conn;
+
+    Data_Get_Struct(self, conn_rec, conn);
+    if (conn->notes) {
+        return rb_apache_table_new(conn->notes);
+    }
+    else {
+        return Qnil;
+    }
+}
+#else
+static VALUE connection_notes(VALUE self)
+{
+    rb_notimplement();
+    return Qnil;
+}
+#endif
+
 void rb_init_apache_connection()
 {
     rb_cApacheConnection = rb_define_class_under(rb_mApache, "Connection", rb_cObject);
     rb_undef_method(CLASS_OF(rb_cApacheConnection), "new");
     rb_define_method(rb_cApacheConnection, "aborted?",
                      connection_aborted, 0);
+    rb_define_method(rb_cApacheConnection, "keepalive",
+                     connection_keepalive, 0);
+    rb_define_method(rb_cApacheConnection, "double_reverse",
+                     connection_double_reverse, 0);
+    rb_define_method(rb_cApacheConnection, "keepalives",
+                     connection_keepalives, 0);
     rb_define_method(rb_cApacheConnection, "remote_ip",
 		     connection_remote_ip, 0);
     rb_define_method(rb_cApacheConnection, "remote_host",
@@ -150,6 +184,8 @@
 		     connection_local_host, 0);
     rb_define_method(rb_cApacheConnection, "local_port",
                      connection_local_port, 0);
+    rb_define_method(rb_cApacheConnection, "notes",
+                     connection_notes, 0);
 }
 
 /* vim: set filetype=c ts=8 sw=4 : */
diff -urN mod_ruby_orig/error.c mod_ruby/error.c
--- mod_ruby_orig/error.c	1969-12-31 16:00:00.000000000 -0800
+++ mod_ruby/error.c	2007-07-25 23:27:49.000000000 -0700
@@ -0,0 +1,58 @@
+/*
+ * $Id$
+ * Copyright (C) 2001  Shugo Maeda <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "mod_ruby.h"
+#include "apachelib.h"
+
+VALUE rb_cApacheError;
+
+VALUE rb_apache_error_new(request_rec *r, error_log_data *error)
+{
+    if (error == NULL)
+        return Qnil;
+    return Data_Wrap_Struct(rb_cApacheError, NULL, NULL, error);
+}
+
+DEFINE_STRING_ATTR_READER(error_file, error_log_data, file);
+DEFINE_INT_ATTR_READER(error_line, error_log_data, line);
+DEFINE_INT_ATTR_READER(error_level, error_log_data, level);
+DEFINE_INT_ATTR_READER(error_status, error_log_data, status);
+DEFINE_STRING_ATTR_READER(error_string, error_log_data, error);
+
+void rb_init_apache_error()
+{
+    rb_cApacheError = rb_define_class_under(rb_mApache, "ErrorLogItem", rb_cObject);
+    rb_define_method(rb_cApacheError, "file", error_file, 0);
+    rb_define_method(rb_cApacheError, "line", error_line, 0);
+    rb_define_method(rb_cApacheError, "level", error_level, 0);
+    rb_define_method(rb_cApacheError, "status", error_status, 0);
+    rb_define_method(rb_cApacheError, "errstr", error_string, 0);
+    rb_define_method(rb_cApacheError, "msg", error_string, 0);
+    rb_define_method(rb_cApacheError, "string", error_string, 0);
+}
+
+/* vim: set filetype=c ts=8 sw=4 : */
diff -urN mod_ruby_orig/Makefile.in mod_ruby/Makefile.in
--- mod_ruby_orig/Makefile.in	2007-07-22 20:52:47.000000000 -0700
+++ mod_ruby/Makefile.in	2007-07-25 23:16:37.000000000 -0700
@@ -98,6 +98,8 @@
 		  paramtable.@OBJEXT@ \
 		  multival.@OBJEXT@ \
 		  bucket.@OBJEXT@ \
+		  uri.@OBJEXT@ \
+		  error.@OBJEXT@ \
 		  apache_request.@OBJEXT@ \
 		  apache_multipart_buffer.@OBJEXT@ \
 		  apache_cookie.@OBJEXT@
@@ -183,6 +185,8 @@
 paramtable.@OBJEXT@: paramtable.c mod_ruby.h apachelib.h
 multival.@OBJEXT@: multival.c mod_ruby.h apachelib.h
 bucket.@OBJEXT@: bucket.c mod_ruby.h apachelib.h
+uri.@OBJEXT@: uri.c mod_ruby.h apachelib.h
+error.@OBJEXT@: error.c mod_ruby.h apachelib.h
 
 apache_request.@OBJEXT@: apache_request.c mod_ruby.h apache_request.h
 apache_multipart_buffer.@OBJEXT@: apache_multipart_buffer.c mod_ruby.h apache_request.h apache_multipart_buffer.h
diff -urN mod_ruby_orig/mod_ruby.c mod_ruby/mod_ruby.c
--- mod_ruby_orig/mod_ruby.c	2007-07-22 20:52:47.000000000 -0700
+++ mod_ruby/mod_ruby.c	2007-07-29 15:43:25.000000000 -0700
@@ -198,6 +198,10 @@
      "set fixup handler object"),
     AP_INIT_TAKE1("RubyLogHandler", ruby_cmd_log_handler, NULL, OR_ALL,
      "set log handler object"),
+#ifdef APACHE2
+    AP_INIT_TAKE1("RubyErrorLogHandler", ruby_cmd_error_log_handler, NULL, OR_ALL,
+     "set log handler object"),
+#endif
     AP_INIT_TAKE1("RubyHeaderParserHandler", ruby_cmd_header_parser_handler,
      NULL, OR_ALL,
      "set header parser object"),
@@ -220,6 +224,7 @@
 
 static int ruby_startup(pool*, pool*, pool*, server_rec*);
 static void ruby_child_init(pool*, server_rec*);
+static void ruby_error_log_handler(const char*, int, int, apr_status_t, const server_rec*, const request_rec*, pool*, const char*);
 
 static void ruby_register_hooks(pool *p)
 {
@@ -233,6 +238,9 @@
     ap_hook_type_checker(ruby_type_handler, NULL, NULL, APR_HOOK_MIDDLE);
     ap_hook_fixups(ruby_fixup_handler, NULL, NULL, APR_HOOK_MIDDLE);
     ap_hook_log_transaction(ruby_log_handler, NULL, NULL, APR_HOOK_MIDDLE);
+#ifdef APACHE2
+    ap_hook_error_log(ruby_error_log_handler, NULL, NULL, APR_HOOK_MIDDLE);
+#endif
     ap_hook_child_init(ruby_child_init, NULL, NULL, APR_HOOK_MIDDLE);
     ap_hook_post_read_request(ruby_post_read_request_handler,
 			      NULL, NULL, APR_HOOK_MIDDLE);
@@ -851,7 +859,7 @@
     return r;
 }
 
-static int ruby_handler(request_rec *, array_header *, ID, int, int);
+static int ruby_handler(request_rec *, array_header *, error_log_data *, ID, int, int);
 
 #ifdef APACHE2
 static void ruby_child_init(pool *p, server_rec *s)
@@ -916,7 +924,7 @@
 
     r = fake_request_rec(s, p, "RubyChildInitHandler");
     conf = get_server_config(r->server);
-    ruby_handler(r, conf->ruby_child_init_handler,
+    ruby_handler(r, conf->ruby_child_init_handler, NULL,
 		 rb_intern("child_init"), 0, 0);
 }
 
@@ -1115,10 +1123,14 @@
     ruby_dir_config *dconf;
 
     if (r->request_config) {
-	rconf = apr_palloc(r->pool, sizeof(ruby_request_config));
-	rconf->saved_env = save_env(r->pool);
-	rconf->request_object = Qnil;
-	ap_set_module_config(r->request_config, &ruby_module, rconf);
+	rconf = get_request_config(r);
+        /* may already have request object from successive handler calls */
+	if (rconf == NULL || NIL_P(rconf->request_object)) {
+            rconf = apr_palloc(r->pool, sizeof(ruby_request_config));
+            rconf->saved_env = save_env(r->pool);
+            rconf->request_object = Qnil;
+            ap_set_module_config(r->request_config, &ruby_module, rconf);
+        }
     }
     dconf = get_dir_config(r);
     sconf = get_server_config(r->server);
@@ -1184,6 +1196,7 @@
 typedef struct handler_0_arg {
     request_rec *r;
     char *handler;
+    error_log_data *err;
     ID mid;
 } handler_0_arg_t;
 
@@ -1191,13 +1204,19 @@
 {
     handler_0_arg_t *ha = (handler_0_arg_t *) arg;
     request_rec *r = ha->r;
+    error_log_data *err = ha->err;
     char *handler = ha->handler;
     ID mid = ha->mid;
     VALUE ret;
     int state;
 
-    ret = rb_protect_funcall(rb_eval_string(handler), mid, &state,
-			     1, rb_request);
+    if (err) {
+        ret = rb_protect_funcall(rb_eval_string(handler), mid, &state,
+		                 2, rb_request, rb_apache_error_new(r, err));
+    } else {
+        ret = rb_protect_funcall(rb_eval_string(handler), mid, &state,
+			         1, rb_request);
+    }
     if (state) {
 	if (state == TAG_RAISE &&
 	    rb_obj_is_kind_of(ruby_errinfo, rb_eSystemExit)) {
@@ -1222,6 +1241,7 @@
 typedef struct handler_internal_arg {
     request_rec *r;
     array_header *handlers_arr;
+    error_log_data *err;
     ID mid;
     int run_all;
     int flush;
@@ -1232,6 +1252,7 @@
 {
     request_rec *r = iarg->r;
     array_header *handlers_arr = iarg->handlers_arr;
+    error_log_data *err = iarg->err;
     ID mid = iarg->mid;
     int run_all = iarg->run_all;
     int flush = iarg->flush;
@@ -1259,6 +1280,7 @@
     for (i = 0; i < handlers_len; i++) {
 	arg.r = r;
 	arg.handler = handlers[i];
+	arg.err = err;
 	arg.mid = mid;
 	ap_soft_timeout("call ruby handler", r);
 	timeout = sconf->timeout;
@@ -1289,8 +1311,9 @@
 }
 
 static int ruby_handler(request_rec *r,
-			array_header *handlers_arr, ID mid,
-			int run_all, int flush)
+			array_header *handlers_arr,
+			error_log_data *error,
+			ID mid, int run_all, int flush)
 {
     handler_internal_arg_t *arg;
 
@@ -1300,6 +1323,7 @@
     arg = apr_palloc(r->pool, sizeof(handler_internal_arg_t));
     arg->r = r;
     arg->handlers_arr = handlers_arr;
+    arg->err = error;
     arg->mid = mid;
     arg->run_all = run_all;
     arg->flush = flush;
@@ -1340,7 +1364,7 @@
     }
 #endif
     dconf = get_dir_config(r);
-    retval = ruby_handler(r, dconf->ruby_handler, rb_intern("handler"), 0, 1);
+    retval = ruby_handler(r, dconf->ruby_handler, NULL, rb_intern("handler"), 0, 1);
 #ifdef APACHE2
     if (retval == DECLINED && r->finfo.filetype == APR_DIR)
         r->handler = DIR_MAGIC_TYPE;
@@ -1352,7 +1376,7 @@
 {
     ruby_dir_config *dconf = get_dir_config(r);
 
-    return ruby_handler(r, dconf->ruby_trans_handler,
+    return ruby_handler(r, dconf->ruby_trans_handler, NULL,
 			rb_intern("translate_uri"), 0, 0);
 }
 
@@ -1362,7 +1386,7 @@
     int retval;
 
     if (dconf->ruby_authen_handler == NULL) return DECLINED;
-    retval = ruby_handler(r, dconf->ruby_authen_handler,
+    retval = ruby_handler(r, dconf->ruby_authen_handler, NULL,
 			  rb_intern("authenticate"), 0, 0);
     return retval;
 }
@@ -1371,7 +1395,7 @@
 {
     ruby_dir_config *dconf = get_dir_config(r);
 
-    return ruby_handler(r, dconf->ruby_authz_handler,
+    return ruby_handler(r, dconf->ruby_authz_handler, NULL,
 			rb_intern("authorize"), 0, 0);
 }
 
@@ -1379,7 +1403,7 @@
 {
     ruby_dir_config *dconf = get_dir_config(r);
 
-    return ruby_handler(r, dconf->ruby_access_handler,
+    return ruby_handler(r, dconf->ruby_access_handler, NULL,
 			rb_intern("check_access"), 1, 0);
 }
 
@@ -1388,7 +1412,7 @@
     ruby_dir_config *dconf = get_dir_config(r);
 
     if (dconf->ruby_type_handler == NULL) return DECLINED;
-    return ruby_handler(r, dconf->ruby_type_handler,
+    return ruby_handler(r, dconf->ruby_type_handler, NULL,
 			rb_intern("find_types"), 0, 0);
 }
 
@@ -1397,7 +1421,7 @@
     ruby_dir_config *dconf = get_dir_config(r);
 
     if (dconf->ruby_fixup_handler == NULL) return DECLINED;
-    return ruby_handler(r, dconf->ruby_fixup_handler,
+    return ruby_handler(r, dconf->ruby_fixup_handler, NULL,
 			rb_intern("fixup"), 1, 0);
 }
 
@@ -1406,7 +1430,7 @@
     ruby_dir_config *dconf = get_dir_config(r);
 
     if (dconf->ruby_log_handler == NULL) return DECLINED;
-    return ruby_handler(r, dconf->ruby_log_handler,
+    return ruby_handler(r, dconf->ruby_log_handler, NULL,
 			rb_intern("log_transaction"), 1, 0);
 }
 
@@ -1418,13 +1442,13 @@
 
     if (dconf->ruby_init_handler &&
 	ap_table_get(r->notes, "ruby_init_ran") == NULL) {
-	retval = ruby_handler(r, dconf->ruby_init_handler,
+	retval = ruby_handler(r, dconf->ruby_init_handler, NULL,
 			      rb_intern("init"), 1, 0);
 	if (retval != OK && retval != DECLINED)
 	    return retval;
     }
     if (dconf->ruby_header_parser_handler == NULL) return DECLINED;
-    return ruby_handler(r, dconf->ruby_header_parser_handler,
+    return ruby_handler(r, dconf->ruby_header_parser_handler, NULL,
 			rb_intern("header_parse"), 1, 0);
 }
 #endif
@@ -1434,7 +1458,7 @@
     request_rec *r = (request_rec *) data;
     ruby_dir_config *dconf = get_dir_config(r);
 
-    ruby_handler(r, dconf->ruby_cleanup_handler,
+    ruby_handler(r, dconf->ruby_cleanup_handler, NULL,
 		 rb_intern("cleanup"), 1, 0);
     APR_CLEANUP_RETURN_SUCCESS();
 }
@@ -1448,16 +1472,43 @@
 			apr_pool_cleanup_null);
 
     if (dconf->ruby_init_handler) {
-	retval = ruby_handler(r, dconf->ruby_init_handler,
+	retval = ruby_handler(r, dconf->ruby_init_handler, NULL,
 			      rb_intern("init"), 1, 0);
 	apr_table_set(r->notes, "ruby_init_ran", "true");
 	if (retval != OK && retval != DECLINED)
 	    return retval;
     }
-    return ruby_handler(r, dconf->ruby_post_read_request_handler,
+    return ruby_handler(r, dconf->ruby_post_read_request_handler, NULL,
 			rb_intern("post_read_request"), 1, 0);
 }
 
+#ifdef APACHE2
+static void ruby_error_log_handler(const char *file, int line, int level, apr_status_t status, const server_rec *s, const request_rec *r, apr_pool_t *pool, const char *error) {
+    ruby_dir_config *dconf;
+    error_log_data *e;
+ 
+    /* only interested in errors produced as the result of requests.
+     * 
+     * [this handler is called multiple times during startup but since this is
+     * prior to config stage, we'll ignore them] */
+    if (r == NULL) return;
+
+    dconf = get_dir_config(r);
+    if (dconf->ruby_error_log_handler == NULL) return;
+    
+    e = apr_palloc(r->pool, sizeof(error_log_data));
+    e->file = file;
+    e->line = line;
+    e->level = level;
+    e->status = status;
+    e->error = error;
+
+    ruby_handler((request_rec *) r, dconf->ruby_error_log_handler, e,
+                 rb_intern("log_error"), 1, 0);
+    return;
+}
+#endif
+
 /*
  * Local variables:
  * mode: C
diff -urN mod_ruby_orig/mod_ruby.h mod_ruby/mod_ruby.h
--- mod_ruby_orig/mod_ruby.h	2007-07-22 20:52:47.000000000 -0700
+++ mod_ruby/mod_ruby.h	2007-07-29 16:12:06.000000000 -0700
@@ -83,6 +83,7 @@
 #include "apr_tables.h"
 
 #define ap_pool apr_pool_t
+#define uri_components apr_uri_t
 
 typedef apr_pool_t pool;
 typedef apr_array_header_t array_header;
@@ -193,6 +194,7 @@
     array_header *ruby_type_handler;
     array_header *ruby_fixup_handler;
     array_header *ruby_log_handler;
+    array_header *ruby_error_log_handler;
     array_header *ruby_header_parser_handler;
     array_header *ruby_post_read_request_handler;
     array_header *ruby_init_handler;
@@ -210,6 +212,18 @@
     VALUE request_object;
 } ruby_request_config;
 
+typedef struct {
+    const char *file;
+    int line;
+    int level;
+#ifdef APACHE2
+    apr_status_t status;
+#else
+    int status;
+#endif
+    const char *error;
+} error_log_data;
+        
 #define MR_DEFAULT_TIMEOUT 0
 #define MR_DEFAULT_SAFE_LEVEL 1
 #define MR_DEFAULT_RESTRICT_DIRECTIVES 0
diff -urN mod_ruby_orig/request.c mod_ruby/request.c
--- mod_ruby_orig/request.c	2007-07-22 20:52:47.000000000 -0700
+++ mod_ruby/request.c	2007-07-25 23:16:37.000000000 -0700
@@ -56,6 +56,7 @@
     VALUE subprocess_env;
     VALUE notes;
     VALUE finfo;
+    VALUE parsed_uri;
     VALUE attributes;
     VALUE error_message;
     VALUE exception;
@@ -106,6 +107,10 @@
 	DEFINE_INT_ATTR_READER(fname, request_data, request->member)
 #define REQUEST_INT_ATTR_WRITER(fname, member) \
 	DEFINE_INT_ATTR_WRITER(fname, request_data, request->member)
+#define REQUEST_BOOL_ATTR_READER(fname, member) \
+	DEFINE_BOOL_ATTR_READER(fname, request_data, request->member)
+#define REQUEST_BOOL_ATTR_WRITER(fname, member) \
+	DEFINE_BOOL_ATTR_WRITER(fname, request_data, request->member)
 
 static void request_mark(request_data *data)
 {
@@ -119,6 +124,7 @@
     rb_gc_mark(data->subprocess_env);
     rb_gc_mark(data->notes);
     rb_gc_mark(data->finfo);
+    rb_gc_mark(data->parsed_uri);
     rb_gc_mark(data->attributes);
     rb_gc_mark(data->error_message);
     rb_gc_mark(data->exception);
@@ -182,6 +188,7 @@
     data->subprocess_env = Qnil;
     data->notes = Qnil;
     data->finfo = Qnil;
+    data->parsed_uri = Qnil;
     data->attributes = Qnil;
     data->error_message = Qnil;
     data->exception = Qnil;
@@ -605,6 +612,8 @@
 REQUEST_STRING_ATTR_READER(request_get_status_line, status_line);
 REQUEST_STRING_ATTR_WRITER(request_set_status_line, status_line);
 REQUEST_STRING_ATTR_READER(request_the_request, the_request);
+REQUEST_BOOL_ATTR_READER(request_get_assbackwards, assbackwards);
+REQUEST_BOOL_ATTR_WRITER(request_set_assbackwards, assbackwards);
 REQUEST_STRING_ATTR_READER(request_request_method, method);
 REQUEST_INT_ATTR_READER(request_method_number, method_number);
 REQUEST_INT_ATTR_READER(request_get_allowed, allowed);
@@ -876,6 +885,17 @@
     return data->finfo;
 }
 
+static VALUE request_parsed_uri(VALUE self)
+{
+    request_data *data;
+    
+    data = get_request_data(self);
+    if (NIL_P(data->parsed_uri)) {
+      data->parsed_uri = rb_apache_uri_new(&data->request->parsed_uri);
+    }
+    return data->parsed_uri;
+}
+
 static VALUE request_attributes(VALUE self)
 {
     request_data *data;
@@ -1049,6 +1069,14 @@
     return type ? rb_tainted_str_new2(type) : Qnil;
 }
 
+static VALUE request_default_port(VALUE self)
+{
+    request_data *data;
+
+    data = get_request_data(self);
+    return INT2NUM(ap_default_port(data->request));
+}
+
 static VALUE request_remote_host(int argc, VALUE *argv, VALUE self)
 {
     request_data *data;
@@ -2135,6 +2163,8 @@
     rb_define_method(rb_cApacheRequest, "allowed=", request_set_allowed, 1);
     rb_define_method(rb_cApacheRequest, "the_request",
 		     request_the_request, 0);
+    rb_define_method(rb_cApacheRequest, "assbackwards?", request_get_assbackwards, 0);
+    rb_define_method(rb_cApacheRequest, "assbackwards=", request_set_assbackwards, 1);
     rb_define_method(rb_cApacheRequest, "header_only?", request_header_only, 0);
     rb_define_method(rb_cApacheRequest, "args", request_get_args, 0);
     rb_define_method(rb_cApacheRequest, "args=", request_set_args, 1);
@@ -2160,6 +2190,7 @@
 		     request_subprocess_env, 0);
     rb_define_method(rb_cApacheRequest, "notes", request_notes, 0);
     rb_define_method(rb_cApacheRequest, "finfo", request_finfo, 0);
+    rb_define_method(rb_cApacheRequest, "parsed_uri", request_parsed_uri, 0);
     rb_define_method(rb_cApacheRequest, "attributes", request_attributes, 0);
     rb_define_method(rb_cApacheRequest, "setup_client_block",
 		     request_setup_client_block, -1);
@@ -2180,6 +2211,7 @@
 		     request_allow_overrides, 0);
     rb_define_method(rb_cApacheRequest, "default_type",
 		     request_default_type, 0);
+    rb_define_method(rb_cApacheRequest, "default_port", request_default_port, 0);
     rb_define_method(rb_cApacheRequest, "remote_host",
 		     request_remote_host, -1);
     rb_define_method(rb_cApacheRequest, "remote_logname",
diff -urN mod_ruby_orig/ruby_config.c mod_ruby/ruby_config.c
--- mod_ruby_orig/ruby_config.c	2007-07-22 20:52:47.000000000 -0700
+++ mod_ruby/ruby_config.c	2007-07-25 23:16:37.000000000 -0700
@@ -109,6 +109,9 @@
     conf->ruby_type_handler = NULL;
     conf->ruby_fixup_handler = NULL;
     conf->ruby_log_handler = NULL;
+#ifdef APACHE2
+    conf->ruby_error_log_handler = NULL;
+#endif
     conf->ruby_header_parser_handler = NULL;
     conf->ruby_post_read_request_handler = NULL;
     conf->ruby_init_handler = NULL;
@@ -164,7 +167,11 @@
 	merge_handlers(p, base->ruby_fixup_handler, add->ruby_fixup_handler);
     new->ruby_log_handler =
 	merge_handlers(p, base->ruby_log_handler, add->ruby_log_handler);
-    new->ruby_header_parser_handler =
+#ifdef APACHE2
+    new->ruby_error_log_handler =
+	merge_handlers(p, base->ruby_error_log_handler, add->ruby_error_log_handler);
+#endif
+     new->ruby_header_parser_handler =
 	merge_handlers(p, base->ruby_header_parser_handler,
 		       add->ruby_header_parser_handler);
     new->ruby_post_read_request_handler =
@@ -472,6 +479,15 @@
     return NULL;
 }
 
+#ifdef APACHE2
+const char *ruby_cmd_error_log_handler(cmd_parms *cmd, void *conf, const char *arg)
+{
+    check_restrict_directives(cmd, conf)
+    push_handler(cmd->pool, ((ruby_dir_config *) conf)->ruby_error_log_handler, arg);
+    return NULL;
+}
+#endif
+
 const char *ruby_cmd_header_parser_handler(cmd_parms *cmd,
 					   void *conf, const char *arg)
 {
diff -urN mod_ruby_orig/ruby_config.h mod_ruby/ruby_config.h
--- mod_ruby_orig/ruby_config.h	2007-07-22 20:52:47.000000000 -0700
+++ mod_ruby/ruby_config.h	2007-07-25 23:16:37.000000000 -0700
@@ -53,6 +53,9 @@
 const char *ruby_cmd_type_handler(cmd_parms*, void*, const char*);
 const char *ruby_cmd_fixup_handler(cmd_parms*, void*, const char*);
 const char *ruby_cmd_log_handler(cmd_parms*, void*, const char*);
+#ifdef APACHE2
+const char *ruby_cmd_error_log_handler(cmd_parms*, void*, const char*);
+#endif
 const char *ruby_cmd_header_parser_handler(cmd_parms*, void*, const char*);
 const char *ruby_cmd_post_read_request_handler(cmd_parms*, void*, const char*);
 const char *ruby_cmd_init_handler(cmd_parms*, void*, const char*);
diff -urN mod_ruby_orig/uri.c mod_ruby/uri.c
--- mod_ruby_orig/uri.c	1969-12-31 16:00:00.000000000 -0800
+++ mod_ruby/uri.c	2007-07-25 23:16:37.000000000 -0700
@@ -0,0 +1,77 @@
+/*
+ * $Id$
+ * Copyright (C) 2001  Shugo Maeda <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "mod_ruby.h"
+#include "apachelib.h"
+
+VALUE rb_cApacheUri;
+
+VALUE rb_apache_uri_new(uri_components *uri)
+{
+    if (uri == NULL)
+        return Qnil;
+    return Data_Wrap_Struct(rb_cApacheUri, NULL, NULL, uri);
+}
+
+DEFINE_STRING_ATTR_READER(uri_scheme, uri_components, scheme);
+DEFINE_STRING_ATTR_READER(uri_hostinfo, uri_components, hostinfo);
+DEFINE_STRING_ATTR_READER(uri_user, uri_components, user);
+DEFINE_STRING_ATTR_READER(uri_password, uri_components, password);
+DEFINE_STRING_ATTR_READER(uri_hostname, uri_components, hostname);
+DEFINE_STRING_ATTR_READER(uri_port_str, uri_components, port_str);
+DEFINE_STRING_ATTR_READER(uri_path, uri_components, path);
+DEFINE_STRING_ATTR_READER(uri_query, uri_components, query);
+DEFINE_STRING_ATTR_READER(uri_fragment, uri_components, fragment);
+DEFINE_INT_ATTR_READER(uri_port, uri_components, port);
+DEFINE_BOOL_ATTR_READER(uri_is_initialized, uri_components, is_initialized);
+DEFINE_BOOL_ATTR_READER(uri_dns_looked_up, uri_components, dns_looked_up);
+DEFINE_BOOL_ATTR_READER(uri_dns_resolved, uri_components, dns_resolved);
+
+/* 
+ * struct hostent *hostent; defined but unused by apr-util or apache at present
+ */
+
+void rb_init_apache_uri()
+{
+    rb_cApacheUri = rb_define_class_under(rb_mApache, "Uri", rb_cObject);
+    rb_define_method(rb_cApacheUri, "scheme", uri_scheme, 0);
+    rb_define_method(rb_cApacheUri, "hostinfo", uri_hostinfo, 0);
+    rb_define_method(rb_cApacheUri, "user", uri_user, 0);
+    rb_define_method(rb_cApacheUri, "password", uri_password, 0);
+    rb_define_method(rb_cApacheUri, "hostname", uri_hostname, 0);
+    rb_define_method(rb_cApacheUri, "port_str", uri_port_str, 0);
+    rb_define_method(rb_cApacheUri, "path", uri_path, 0);
+    rb_define_method(rb_cApacheUri, "query", uri_query, 0);
+    rb_define_method(rb_cApacheUri, "fragment", uri_fragment, 0);
+    rb_define_method(rb_cApacheUri, "port", uri_port, 0);
+    rb_define_method(rb_cApacheUri, "is_initialized", uri_is_initialized, 0);
+    rb_define_method(rb_cApacheUri, "initialized?", uri_is_initialized, 0);
+    rb_define_method(rb_cApacheUri, "dns_looked_up?", uri_dns_looked_up, 0);
+    rb_define_method(rb_cApacheUri, "dns_resolved?", uri_dns_resolved, 0);
+}
+
+/* vim: set filetype=c ts=8 sw=4 : */


--=-vvl4qVKhLGbe9jWZbIK7--