You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Stas Bekman <st...@stason.org> on 2003/05/23 06:01:45 UTC

[BUG] in 2.0's ap_read_request with regards to removing the first connection filter in chain

there is an edge case bug in filter removal code.

ap_read_request has the following code:

     r->proto_output_filters = conn->output_filters;
     r->output_filters  = r->proto_output_filters;
     r->proto_input_filters = conn->input_filters;
     r->input_filters   = r->proto_input_filters;

this makes it impossible to remove the very first filter in 
conn->output_filters or conn->input_filters, because while it gets removed 
from the corresponding conn filter chain. r->output_filters and 
r->input_filters are still pointing to that filter, which was removed. Result: 
the filter gets invoked again and again...

I was toying with different possible solutions but they all have failed to 
work perfectly. I believe the only long-term solution, which doesn't slow 
things down, is to extend the filter struct to add a 'prev' entry, turning the 
filter chain into double-linked list, so remove_any_filter can fix 
r->input_filters directly.

I was thinking to plug a dummy pass-through filter as an alternative solution, 
but one has to ensure that no user filter will be able to insert a filter in 
front of it. So if we can ensure that conn->output_filters always starts with 
a dummy filter, removing any other filters will work correctly. This can be 
accomplished by changing add_any_filter and other functions to keep the dummy 
edge filter at the top of the connection filter chain.

I have a cheating solution though, the patch below, instead of removing the 
edge filter, replaces its frec with an frec for a dummy pass-through filter.
I've run multiple filter tests on it and it seems to work fine. The only 
potential problem with this solution if anything is trying to access frec of 
the filter that was removed (just because it may still be running). So this 
solution is not clean, because it reminds me of cutting the brach ones sit on.

Index: include/http_core.h
===================================================================
RCS file: /home/cvs/httpd-2.0/include/http_core.h,v
retrieving revision 1.70.2.2
diff -u -r1.70.2.2 http_core.h
--- include/http_core.h	8 May 2003 20:49:32 -0000	1.70.2.2
+++ include/http_core.h	23 May 2003 03:56:18 -0000
@@ -609,7 +609,9 @@
  extern AP_DECLARE_DATA ap_filter_rec_t *ap_content_length_filter_handle;
  extern AP_DECLARE_DATA ap_filter_rec_t *ap_net_time_filter_handle;
  extern AP_DECLARE_DATA ap_filter_rec_t *ap_core_input_filter_handle;
-
+extern AP_DECLARE_DATA ap_filter_rec_t *ap_core_dummy_input_filter_handle;
+extern AP_DECLARE_DATA ap_filter_rec_t *ap_core_dummy_output_filter_handle;
+
  /**
   * This hook provdes a way for modules to provide metrics/statistics about
   * their operational status.
Index: server/core.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/core.c,v
retrieving revision 1.225.2.6
diff -u -r1.225.2.6 core.c
--- server/core.c	13 May 2003 16:01:04 -0000	1.225.2.6
+++ server/core.c	23 May 2003 03:56:18 -0000
@@ -125,6 +125,8 @@
  AP_DECLARE_DATA ap_filter_rec_t *ap_content_length_filter_handle;
  AP_DECLARE_DATA ap_filter_rec_t *ap_net_time_filter_handle;
  AP_DECLARE_DATA ap_filter_rec_t *ap_core_input_filter_handle;
+AP_DECLARE_DATA ap_filter_rec_t *ap_core_dummy_input_filter_handle;
+AP_DECLARE_DATA ap_filter_rec_t *ap_core_dummy_output_filter_handle;

  static void *create_core_dir_config(apr_pool_t *a, char *dir)
  {
@@ -3483,6 +3485,19 @@
      } while (!APR_BRIGADE_EMPTY(b) && (e != APR_BRIGADE_SENTINEL(b))); \
  } while (0)

+static int core_dummy_input_filter(ap_filter_t *f, apr_bucket_brigade *b,
+                                   ap_input_mode_t mode, apr_read_type_e block,
+                                   apr_off_t readbytes)
+{
+    return ap_get_brigade(f->next, b, mode, block, readbytes);
+}
+
+static int core_dummy_output_filter(ap_filter_t *f,
+                                    apr_bucket_brigade *b)
+{
+    return ap_pass_brigade(f->next, b);
+}
+
  static int core_input_filter(ap_filter_t *f, apr_bucket_brigade *b,
                               ap_input_mode_t mode, apr_read_type_e block,
                               apr_off_t readbytes)
@@ -4288,6 +4303,12 @@
       */
      ap_hook_insert_filter(core_insert_filter, NULL, NULL, APR_HOOK_MIDDLE);

+    ap_core_dummy_input_filter_handle =
+        ap_register_input_filter("CORE_DUMMY_IN", core_dummy_input_filter,
+                                 NULL, AP_FTYPE_NETWORK);
+    ap_core_dummy_output_filter_handle =
+        ap_register_output_filter("CORE_DUMMY_OUT", core_dummy_output_filter,
+                                  NULL, AP_FTYPE_NETWORK);
      ap_core_input_filter_handle =
          ap_register_input_filter("CORE_IN", core_input_filter,
                                   NULL, AP_FTYPE_NETWORK);
Index: server/util_filter.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/util_filter.c,v
retrieving revision 1.93.2.2
diff -u -r1.93.2.2 util_filter.c
--- server/util_filter.c	22 Feb 2003 18:09:57 -0000	1.93.2.2
+++ server/util_filter.c	23 May 2003 03:56:18 -0000
@@ -61,6 +61,7 @@
  #include "httpd.h"
  #include "http_log.h"
  #include "util_filter.h"
+#include "http_core.h"

  /* NOTE: Apache's current design doesn't allow a pool to be passed thru,
     so we depend on a global to hold the correct pool
@@ -459,8 +460,11 @@
                                   &c->output_filters);
  }

-static void remove_any_filter(ap_filter_t *f, ap_filter_t **r_filt, 
ap_filter_t **p_filt,
-                              ap_filter_t **c_filt)
+typedef enum { INPUT, OUTPUT } type;
+
+static void remove_any_filter(ap_filter_t *f, ap_filter_t **r_filt,
+                              ap_filter_t **p_filt,
+                              ap_filter_t **c_filt, type in_out)
  {
      ap_filter_t **curr = r_filt ? r_filt : c_filt;
      ap_filter_t *fscan = *curr;
@@ -469,7 +473,12 @@
          *p_filt = (*p_filt)->next;

      if (*curr == f) {
-        *curr = (*curr)->next;
+        if (in_out == INPUT) {
+            (*curr)->frec = ap_core_dummy_input_filter_handle;
+        }
+        else {
+            (*curr)->frec = ap_core_dummy_output_filter_handle;
+        }
          return;
      }

@@ -486,14 +495,14 @@
  {
      remove_any_filter(f, f->r ? &f->r->input_filters : NULL,
                        f->r ? &f->r->proto_input_filters : NULL,
-                      &f->c->input_filters);
+                      &f->c->input_filters, INPUT);
  }

  AP_DECLARE(void) ap_remove_output_filter(ap_filter_t *f)
  {
      remove_any_filter(f, f->r ? &f->r->output_filters : NULL,
                        f->r ? &f->r->proto_output_filters : NULL,
-                      &f->c->output_filters);
+                      &f->c->output_filters, OUTPUT);
  }

  /*


__________________________________________________________________
Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/     mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com


Re: How to attach user data to request_rec structure?

Posted by Bill Stoddard <bi...@wstoddard.com>.
> Check out these examples from mod_cache:
>
> ap_set_module_config(r->request_config, &cache_module, cache);
> conf = (cache_server_conf *) 
> ap_get_module_config(r->server->module_config, &cache_module);


Ooops, that response was a little skitzo... :-)

Try this:
ap_set_module_config(r->request_config, &cache_module, cache);
cache = (cache_request_rec *) ap_get_module_config(r->request_config, 
&cache_module);

Bill


Re: How to attach user data to request_rec structure?

Posted by Bill Stoddard <bi...@wstoddard.com>.
Nedelcho Stanev wrote:

>Hello,
>
>I want to pass some data between modules, functions etc.
>At all i want to write some flag or string for way of authentication
>in authentication callback on my module and to get this data
>latter in handler functions.
>Does any know way to do  this with apache 2.0 ?
>
>decho
>
Check out these examples from mod_cache:

 ap_set_module_config(r->request_config, &cache_module, cache);
 conf = (cache_server_conf *) 
ap_get_module_config(r->server->module_config, &cache_module);

'cache' happens to be a pointer to a struct of type cache_server_conf. 
You can make it anything you want in your module.

Bill


How to attach user data to request_rec structure?

Posted by Nedelcho Stanev <ne...@atlanticsky.com>.
Hello,

I want to pass some data between modules, functions etc.
At all i want to write some flag or string for way of authentication
in authentication callback on my module and to get this data
latter in handler functions.
Does any know way to do  this with apache 2.0 ?

decho