On Wed, May 30, 2001 at 03:40:36PM -0700, Doug MacEachern wrote:
> On Tue, 29 May 2001, barries wrote:
> 
> > I know you don't need *FunctionTable.pm, but hey, it's free.
> 
> we do need the ModPerl::FunctionTable entries.

I meant that I should probably omit FunctionTable.pm, requiring you to
source_scan.  This would catch any goofs in *.map.  I can't seem to run
it (v0.75) here at the moment, it's barfing like so:

[barries@//sizzle] stdio$ /home/barries/2.0/bleedperl/bin/perl 
util/modperl_source_scan.pl
panic: multiple types without intervening comma in
         regexp*( *regcomp_t  ) (  PerlInterpreter *my_perl ,  char* exp, char* xend, 
PMOP* pm)
whited-out as
         regexp*( *regcomp_t  ) (                                                      
       )
Expecting parenth after identifier in `regcomp_t  * Perl_Tregcompp_ptr(  
PerlInterpreter *my_perl  )'
after `regcomp_t  ' at /home/barries/2.0/bleedperl/lib/site_perl/5.7.1/C/Scan.pm line 
783.
        C::Scan::do_declaration('extern    \x{9}regcomp_t  * Perl_Tregcompp_ptr(  
PerlInterpreter *my_perl  );','HASH(0x8386bf8)','HASH(0x8477d2c)') called at 
/home/barries/2.0/bleedperl/lib/site_perl/5.7.1/C/Scan.pm line 738
        
C::Scan::do_declarations('ARRAY(0x83fdfec)','HASH(0x8386bf8)','HASH(0x8477d2c)') 
called at /home/barries/2.0/bleedperl/lib/site_perl/5.7.1/Data/Flow.pm line 69
        
Data::Flow::request('Apache::ParseSource::Scan=ARRAY(0x8478a60)','parsed_fdecls') 
called at /home/barries/2.0/bleedperl/lib/site_perl/5.7.1/Data/Flow.pm line 39
        Data::Flow::get('Apache::ParseSource::Scan=ARRAY(0x8478a60)','parsed_fdecls') 
called at lib/Apache/ParseSource.pm line 49
        
Apache::ParseSource::Scan::get('Apache::ParseSource::Scan=ARRAY(0x8478a60)','parsed_fdecls')
 called at lib/Apache/ParseSource.pm line 289
        Apache::ParseSource::get_functions('ModPerl::ParseSource=HASH(0x83a1524)') 
called at lib/Apache/ParseSource.pm line 367
        
Apache::ParseSource::write_functions_pm('ModPerl::ParseSource=HASH(0x83a1524)','FunctionTable.pm','ModPerl::FunctionTable')
 called at lib/ModPerl/ParseSource.pm line 40
        
ModPerl::ParseSource::write_functions_pm('ModPerl::ParseSource=HASH(0x83a1524)') 
called at util/modperl_source_scan.pl line 25

> for these xsubs, pTHX_ is not needed, and we know the number of arguments.

Thanks.  This patch

- fixes the bugs you pointed out and some other bugs in my first patch
  (which was not triggered by the test suite, since it only ever sends
  one brigade downstream from the response_handler).
- adds shutdown() and makes close() == shutdown(2)
- tries to prevent us from sending multiple EOSs via the stdio
  simulation.
- also includes the older patch for only sending EOS at the end of the
  last time the filter_handler is called.

Open issues I can think of at the moment (comments?):

- Apache::Filter->shutdown(1) doesn't send all pending & future upstream
  data to /dev/null.
- seek().  seek(0,0) and seek(0,2) break badly in a multi-brigade
  stream.  Yes, there can be an upstream filter to aggregate, but I
  think it's safe to leave seek() alone for now.
- Adding EOF, TELL, and CLOSE wrappers.  Wonder if there needs to be a
  SHUTDOWN added to perl.
- tacking an EOS on the last brigade sent from a PerlResponseHandler
- it'd be nice if there were an option to each filter handler in it's
  own thread, the stdio socket simulation could be a lot better.
- tweaking the response_handler code to be able to flush (haven't
  checked to see if it already can) and send an EOS before it exits.
- need to look for ways multiple EOSs can be sent (there's at least one
  way, but that's in code I want to delete)
- delete the guard around the handler code that prevents EOS-only
  brigades from causing the handler to fire.
- the C-level ap_pass_brigade() wrapper needs to notice when an EOS is
  sent so the handler doesn't send another one.
- It would be nice if Apache::Test could emit it's output to an
  intermediate file so things can be tested after all content is sent;
  like testing the result codes from ->close and ->shutdown, or looking
  to see that things like tell() whinge when called after close().
- all of the stdio socket emulation functions should return an error if
  called after whichever stream is appropriate shutdown().
- I wonder if having two simulated filehandles would be a more accurate
  and flexible API, rather than this thing that drives sorta like a
  socket (read/print/shutdown) and sorta like a filehandle (eof/tell).

diff -ur modperl-2.0/src/modules/perl/modperl_filter.c 
stdio/src/modules/perl/modperl_filter.c
--- modperl-2.0/src/modules/perl/modperl_filter.c       Thu May 31 22:25:47 2001
+++ stdio/src/modules/perl/modperl_filter.c     Thu May 31 23:07:48 2001
@@ -152,9 +152,18 @@
 
 MP_INLINE static apr_status_t send_eos(ap_filter_t *f)
 {
-    apr_bucket_brigade *bb = apr_brigade_create(f->r->pool);
-    apr_bucket *b = apr_bucket_eos_create();
+
+    modperl_filter_ctx_t *ctx= (modperl_filter_ctx_t *)f->ctx;
+    apr_bucket_brigade *bb;
+    apr_bucket *b;
+
+    if (ctx->eos_sent)
+        return APR_EINVALSOCK;
+
+    bb = apr_brigade_create(f->r->pool);
+    b = apr_bucket_eos_create();
     APR_BRIGADE_INSERT_TAIL(bb, b);
+    ctx->eos_sent=1;
     return ap_pass_brigade(f->next, bb);
 }
 
@@ -223,6 +232,7 @@
             sv_catpvn(buffer, filter->leftover, wanted);
             filter->leftover += wanted;
             filter->remaining -= wanted;
+            ((modperl_filter_ctx_t *)filter->f->ctx)->read_cnt+= wanted;
             return wanted;
         }
         else {
@@ -237,6 +247,9 @@
 
     if (!filter->bb) {
         MP_TRACE_f(MP_FUNC, "bucket brigade has been emptied\n");
+        if (filter->eos) {
+            ((modperl_filter_ctx_t *)filter->f->ctx)->eof=1;
+        }
         return 0;
     }
 
@@ -269,6 +282,7 @@
             MP_TRACE_f(MP_FUNC,
                        "apr_bucket_read error: %s\n",
                        modperl_apr_strerror(filter->rc));
+            ((modperl_filter_ctx_t *)filter->f->ctx)->read_cnt+= len;
             return len;
         }
 
@@ -298,14 +312,43 @@
     }
 #endif
 
-    if (filter->eos && (len == 0)) {
-        /* if len > 0 then $filter->write will flush */
-        modperl_output_filter_flush(filter);
+    if (!len && filter->eos && !filter->remaining) {
+        ((modperl_filter_ctx_t *)filter->f->ctx)->eof=1;
     }
 
+    ((modperl_filter_ctx_t *)filter->f->ctx)->read_cnt+= len;
     return len;
 }
 
+MP_INLINE int modperl_output_filter_tell(modperl_filter_ctx_t *ctx)
+{
+    return ctx->read_cnt;
+}
+
+MP_INLINE int modperl_output_filter_eof(modperl_filter_ctx_t *ctx)
+{
+    return ctx->eof;
+}
+
+MP_INLINE apr_status_t modperl_output_filter_shutdown(ap_filter_t *f, int how)
+{
+    apr_status_t r = APR_SUCCESS;
+    if ( how == 0 || how == 2 ) {
+        /* XXX: Pretend EOS seen */
+    }
+    if ( how == 1 || how == 2 ) {
+        int r1 = send_eos(f);
+        if (r1 != APR_SUCCESS)
+            r = r1 ;
+    }
+    return r;
+}
+
+MP_INLINE apr_status_t modperl_output_filter_close(ap_filter_t *f)
+{
+    return modperl_output_filter_shutdown(f,2);
+}
+
 MP_INLINE apr_status_t modperl_output_filter_flush(modperl_filter_t *filter)
 {
     filter->rc = modperl_wbucket_flush(&filter->wbucket);
@@ -313,13 +356,26 @@
         return filter->rc;
     }
 
+    return filter->rc;
+}
+
+MP_INLINE apr_status_t modperl_output_filter_send_EOS(modperl_filter_t *filter)
+{
+
+    filter->rc = modperl_output_filter_flush(filter);
+    if (filter->rc != APR_SUCCESS) {
+        return filter->rc;
+    }
+
     if (filter->eos) {
         MP_TRACE_f(MP_FUNC, "sending EOS bucket\n");
         filter->rc = send_eos(filter->f);
-        apr_brigade_destroy(filter->bb);
-        filter->bb = NULL;
-        filter->eos = 0;
+        if (filter->bb) {
+            apr_brigade_destroy(filter->bb);
+            filter->bb = NULL;
+        }
     }
+    filter->eos = 0;
 
     return filter->rc;
 }
@@ -348,6 +404,11 @@
     else {
         filter = modperl_filter_new(f, bb, MP_OUTPUT_FILTER_MODE);
         status = modperl_run_filter(filter, 0, 0);
+        if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb)) &&
+            !((modperl_filter_ctx_t*)f->ctx)->eos_sent
+        ) {
+            modperl_output_filter_send_EOS(filter);
+        }
     }
 
     switch (status) {
diff -ur modperl-2.0/src/modules/perl/modperl_filter.h 
stdio/src/modules/perl/modperl_filter.h
--- modperl-2.0/src/modules/perl/modperl_filter.h       Thu May 31 22:25:47 2001
+++ stdio/src/modules/perl/modperl_filter.h     Thu May 31 21:48:25 2001
@@ -35,11 +35,20 @@
 void modperl_output_filter_register(request_rec *r);
 
 MP_INLINE apr_status_t modperl_output_filter_flush(modperl_filter_t *filter);
+MP_INLINE apr_status_t modperl_output_filter_send_EOS(modperl_filter_t *filter);
 
 MP_INLINE apr_ssize_t modperl_output_filter_read(pTHX_
                                                  modperl_filter_t *filter,
                                                  SV *buffer,
                                                  apr_ssize_t wanted);
+
+MP_INLINE int modperl_output_filter_tell(modperl_filter_ctx_t *ctx);
+
+MP_INLINE int modperl_output_filter_eof(modperl_filter_ctx_t *ctx);
+
+MP_INLINE apr_status_t modperl_output_filter_shutdown(ap_filter_t *f, int how);
+
+MP_INLINE apr_status_t modperl_output_filter_close(ap_filter_t *f);
 
 MP_INLINE apr_status_t modperl_output_filter_write(modperl_filter_t *filter,
                                                    const char *buf,
diff -ur modperl-2.0/src/modules/perl/modperl_types.h 
stdio/src/modules/perl/modperl_types.h
--- modperl-2.0/src/modules/perl/modperl_types.h        Thu May 31 22:25:48 2001
+++ stdio/src/modules/perl/modperl_types.h      Thu May 31 22:21:12 2001
@@ -195,6 +195,9 @@
     SV *data;
     modperl_handler_t *handler;
     PerlInterpreter *perl;
+    uint eof:1;           /* No more data to send to Perl code */
+    uint eos_sent:1;      /* an EOS has been sent downstream */
+    apr_ssize_t read_cnt; /* bytes actually read */
 } modperl_filter_ctx_t;
 
 typedef struct {
diff -ur modperl-2.0/t/filter/TestFilter/api.pm stdio/t/filter/TestFilter/api.pm
--- modperl-2.0/t/filter/TestFilter/api.pm      Thu Apr 19 21:57:26 2001
+++ stdio/t/filter/TestFilter/api.pm    Thu May 31 22:08:00 2001
@@ -3,6 +3,7 @@
 use strict;
 use warnings FATAL => 'all';
 
+use APR::Const qw( SUCCESS );
 use Apache::Filter ();
 use Apache::FilterRec ();
 
@@ -23,15 +24,33 @@
 sub handler {
     my $filter = shift;
 
-    $filter->read(my $buffer); #slurp everything;
-
     init_test_pm($filter);
 
-    plan tests => 6;
+    plan tests => 13;
+
+    ok $filter->isa('Apache::Filter');
+
+    ok !$filter->eof;
+
+    ok !$filter->tell;
+
+    my $s = $filter->read(my $buffer); #slurp everything;
+
+    ok $s == length $response_data;
 
     ok $buffer eq $response_data;
 
-    ok $filter->isa('Apache::Filter');
+    ok $filter->tell == length $response_data;
+
+    ok !$filter->eof;
+
+    $s = $filter->read($buffer); #try to slurp a bit more
+
+    ok $filter->tell == length $response_data;
+
+    ok !$s;
+
+    #ok $filter->eof; Hmmm, no EOS => no eof. Rats.
 
     my $frec = $filter->frec;
 
@@ -44,6 +63,19 @@
     ok $r->isa('Apache::RequestRec');
 
     ok $r->uri eq '/' . __PACKAGE__;
+
+    $r = $filter->close ;         # Can't send to our own STDOUT anymore!
+
+    warn "Apache::Filter->close returned $r" unless $r == SUCCESS ;
+
+    $r = $filter->shutdown(0) ;
+    warn "Apache::Filter->shutdown(0) returned $r" unless $r == SUCCESS ;
+
+    $r = $filter->shutdown(1) ;
+    warn "Apache::Filter->shutdown(1) returned $r" unless $r == SUCCESS ;
+
+    $r = $filter->shutdown(2) ;
+    warn "Apache::Filter->shutdown(2) returned $r" unless $r == SUCCESS ;
 
     0;
 }
diff -ur modperl-2.0/xs/Apache/Filter/Apache__Filter.h 
stdio/xs/Apache/Filter/Apache__Filter.h
--- modperl-2.0/xs/Apache/Filter/Apache__Filter.h       Thu May 31 22:26:10 2001
+++ stdio/xs/Apache/Filter/Apache__Filter.h     Thu May 31 22:35:28 2001
@@ -32,6 +32,29 @@
     return bytes;
 }
 
+
+static MP_INLINE int mpxs_Apache__Filter_eof(ap_filter_t *filter)
+{
+    return modperl_output_filter_eof(filter->ctx);
+}
+
+
+static MP_INLINE int mpxs_Apache__Filter_tell(ap_filter_t *filter)
+{
+    return modperl_output_filter_tell(filter->ctx);
+}
+
+static MP_INLINE int mpxs_Apache__Filter_shutdown(ap_filter_t *filter,int how)
+{
+    return modperl_output_filter_shutdown(filter,how);
+}
+
+static MP_INLINE int mpxs_Apache__Filter_close(ap_filter_t *filter)
+{
+    return modperl_output_filter_close(filter);
+}
+
+
 static MP_INLINE apr_size_t mpxs_Apache__Filter_read(pTHX_ I32 items,
                                                      SV **MARK, SV **SP)
 {
diff -ur modperl-2.0/xs/maps/modperl_functions.map stdio/xs/maps/modperl_functions.map
--- modperl-2.0/xs/maps/modperl_functions.map   Thu May 31 22:26:48 2001
+++ stdio/xs/maps/modperl_functions.map Thu May 31 21:49:01 2001
@@ -36,6 +36,10 @@
 
  mpxs_Apache__Filter_print | | ...
  mpxs_Apache__Filter_read  | | ...
+ mpxs_Apache__Filter_eof
+ mpxs_Apache__Filter_tell
+ mpxs_Apache__Filter_shutdown
+ mpxs_Apache__Filter_close
 
  SV *:DEFINE_TIEHANDLE | | SV *:stashsv, SV *:sv=Nullsv
  int:DEFINE_PRINT      | | ...
diff -ur modperl-2.0/xs/maps/modperl_types.map stdio/xs/maps/modperl_types.map
--- modperl-2.0/xs/maps/modperl_types.map       Thu May 31 22:26:48 2001
+++ stdio/xs/maps/modperl_types.map     Thu May 31 17:39:36 2001
@@ -1,6 +1,6 @@
 ##########  mod_perl types  ##########
 
-struct modperl_filter_t | Apache::OutputFilter
+struct modperl_filter_t | Apache::Filter
 
 ##########  Perl types  ##########
 
diff -ur modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm 
stdio/xs/tables/current/ModPerl/FunctionTable.pm
--- modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm      Thu May 31 22:25:10 
2001
+++ stdio/xs/tables/current/ModPerl/FunctionTable.pm    Thu May 31 22:53:18 2001
@@ -2151,6 +2151,50 @@
     'name' => 'modperl_output_filter_read'
   },
   {
+    'return_type' => 'int',
+    'args' => [
+      {
+        'name' => 'ctx',
+        'type' => 'modperl_filter_ctx_t *'
+      },
+    ],
+    'name' => 'modperl_output_filter_tell'
+  },
+  {
+    'return_type' => 'int',
+    'args' => [
+      {
+        'name' => 'ctx',
+        'type' => 'modperl_filter_ctx_t *'
+      },
+    ],
+    'name' => 'modperl_output_filter_eof'
+  },
+  {
+    'return_type' => 'int',
+    'args' => [
+      {
+        'name' => 'f',
+        'type' => 'ap_filter_t *'
+      },
+      {
+        'name' => 'how',
+        'type' => 'int'
+      },
+    ],
+    'name' => 'modperl_output_filter_shutdown'
+  },
+  {
+    'return_type' => 'int',
+    'args' => [
+      {
+        'name' => 'f',
+        'type' => 'ap_filter_t *'
+      },
+    ],
+    'name' => 'modperl_output_filter_close'
+  },
+  {
     'return_type' => 'apr_status_t',
     'args' => [
       {
@@ -3526,6 +3570,46 @@
     'name' => 'mpxs_Apache__RequestRec_parsed_uri'
   },
   {
+    'return_type' => 'char *',
+    'args' => [
+      {
+        'name' => 'my_perl',
+        'type' => 'PerlInterpreter *'
+      },
+      {
+        'name' => 'uptr',
+        'type' => 'uri_components *'
+      },
+      {
+        'name' => 'flags',
+        'type' => 'unsigned'
+      }
+    ],
+    'name' => 'mpxs_ap_unparse_uri_components'
+  },
+  {
+    'return_type' => 'uri_components *',
+    'args' => [
+      {
+        'name' => 'my_perl',
+        'type' => 'PerlInterpreter *'
+      },
+      {
+        'name' => 'classname',
+        'type' => 'SV *'
+      },
+      {
+        'name' => 'obj',
+        'type' => 'SV *'
+      },
+      {
+        'name' => 'uri_string',
+        'type' => 'const char *'
+      }
+    ],
+    'name' => 'mpxs_ap_parse_uri_components'
+  },
+  {
     'return_type' => 'int',
     'args' => [
       {
@@ -3540,6 +3624,20 @@
     'name' => 'mpxs_ap_unescape_url'
   },
   {
+    'return_type' => 'char *',
+    'args' => [
+      {
+        'name' => 'uri',
+        'type' => 'uri_components *'
+      },
+      {
+        'name' => 'portsv',
+        'type' => 'SV *'
+      }
+    ],
+    'name' => 'mpxs_Apache__URI_port'
+  },
+  {
     'return_type' => 'SV *',
     'args' => [
       {
@@ -3782,6 +3880,50 @@
       }
     ],
     'name' => 'mpxs_Apache__Filter_read'
+  },
+  {
+    'return_type' => 'int',
+    'args' => [
+      {
+        'name' => 'filter',
+        'type' => 'ap_filter_t *'
+      },
+    ],
+    'name' => 'mpxs_Apache__Filter_tell'
+  },
+  {
+    'return_type' => 'int',
+    'args' => [
+      {
+        'name' => 'filter',
+        'type' => 'ap_filter_t *'
+      },
+    ],
+    'name' => 'mpxs_Apache__Filter_eof'
+  },
+  {
+    'return_type' => 'int',
+    'args' => [
+      {
+        'name' => 'filter',
+        'type' => 'ap_filter_t *'
+      },
+      {
+        'name' => 'how',
+        'type' => 'int'
+      },
+    ],
+    'name' => 'mpxs_Apache__Filter_shutdown'
+  },
+  {
+    'return_type' => 'int',
+    'args' => [
+      {
+        'name' => 'filter',
+        'type' => 'ap_filter_t *'
+      },
+    ],
+    'name' => 'mpxs_Apache__Filter_close'
   },
   {
     'return_type' => 'apr_status_t',

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to