Return-Path: Delivered-To: apmail-httpd-dev-archive@www.apache.org Received: (qmail 38958 invoked from network); 22 Aug 2007 06:24:08 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 22 Aug 2007 06:24:08 -0000 Received: (qmail 49358 invoked by uid 500); 22 Aug 2007 06:23:57 -0000 Delivered-To: apmail-httpd-dev-archive@httpd.apache.org Received: (qmail 49286 invoked by uid 500); 22 Aug 2007 06:23:57 -0000 Mailing-List: contact dev-help@httpd.apache.org; run by ezmlm Precedence: bulk Reply-To: dev@httpd.apache.org list-help: list-unsubscribe: List-Post: List-Id: Delivered-To: mailing list dev@httpd.apache.org Received: (qmail 49259 invoked by uid 99); 22 Aug 2007 06:23:56 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 21 Aug 2007 23:23:56 -0700 X-ASF-Spam-Status: No, hits=3.8 required=10.0 tests=HTML_MESSAGE,MIME_QP_LONG_LINE,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: domain of TOKILEY@aol.com designates 205.188.139.136 as permitted sender) Received: from [205.188.139.136] (HELO imo-d20.mx.aol.com) (205.188.139.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 22 Aug 2007 06:24:22 +0000 Received: from TOKILEY@aol.com by imo-d20.mx.aol.com (mail_out_v38_r9.2.) id e.c1a.1fe531fd (48552); Wed, 22 Aug 2007 02:22:39 -0400 (EDT) From: TOKILEY@aol.com Message-ID: Date: Wed, 22 Aug 2007 02:23:20 EDT Subject: Re: Completely transform a request ( Followup: Example code mod_transform ) To: dev@httpd.apache.org CC: TOKILEY@aol.com MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="-----------------------------1187763800" X-Mailer: 9.0 for Windows sub 5129 X-Virus-Checked: Checked by ClamAV on apache.org X-Old-Spam-Flag: NO -------------------------------1187763800 Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit * HOW TO COMPLETELY TRANSFORM AN INBOUND APACHE REQUEST >Arturo wrote... > >I want to Completely Transform a Request. >100% transformation. > >Based on a certain logic, If an incoming request matches one >of my action triggers, then I want to apply a transformation >to the 100% of the incoming request. I know I can do that when >I just want to modify brigade-by-brigade. But I need to read >the WHOLE request before doing so. Even the METHOD line. >Even the headers. Even the body. All of it. Then, completely >transform that into another request, and have Apache process it. > >With the current input filtering framework, at the connection >level, I should be able to do it. But I can't. > >If you NEED an example of what I'd like to transform, and into >WHAT i want to transform it, see this post: > >What I'd like to transform: >http://www.mail-archive.com/dev@httpd.apache.org/msg37206.html > >Into WHAT I want to transform it: a completely different request >(i.e different method line, different headers and different body, >and I can't do that in stages, I have to read the whole request first). > >Sincerely, > >Arturo "Buanzo" Busleiman - >Consultor Independiente en Seguridad Informatica > > In case you want to take a look, you can check out the filter > function from... > > _http://www.buanzo.com.ar/files/openpgp.conn.filter.in.c_ (http://www.buanzo.com.ar/files/openpgp.conn.filter.in.c) I've looked at the code there and you definitely are on the right track. There is nothing fundamentally wrong with your code except, as you discovered, you have to be totally aware of what is actually happening during the input phase or it's easy to trip up and get an "Error reading headers" from inside the ap_get_mime_headers_core() routine. >> Kevin wrote... >> >> Just to satisfy my own curiosity I worked up >> a module here that is, in fact, able to do what >> you want. There don't seem to be any fatal flaws >> in the input filtering that would prevent it. > > Arturo responded... > > Great, Can I take a look? That'd be cool. Sure. Entire filter source code is included below. The following "mod_transform.c" filter does EXACTLY what you are trying to do. It performs a complete, 100 percent transformation on an inbound Apache request. I tested it with your own sample non-encrypted transformation input test and it works perfectly fine here. The code can certainly be consolidated but I used a STATE HANDLER to make it CLEAR what is happening when and why your code was having problems. I hope this is of some help and if anyone who knows more than I do about filtering wants to follow up with more pointers please go for it. We all have things to learn. Later... Kevin COMPLETE SOURCE CODE FOR MOD_TRANSFORM.C /* mod_transform.c - Completely transform an inbound request * * Author: Kevin Kiley - 08/12/07 * * There are no configuration commands. * * To install and run just put mod_transform.so in your server's * ../modules directory and then add the following to the * HTTPD config file... * * LoadModule transform_module modules/mod_transform.so * * The filter will be loaded automatically at runtime. * * See the 'YOUR CODE GOES HERE' comment in the TRANSFORMATION * section to add any custom transformation(s). * * This demo assumes that the POST data is NOT encrypted and * is already a fully formed secondary request. It simply * "Transforms" the initial request into the secondary one. */ #include "httpd.h" #include "http_connection.h" /* Required for ap_hook_pre_xxxx() references */ #include "http_config.h" #include "http_core.h" #include "http_log.h" /* Globals */ /* The 'trigger string' * If this string is part of the inbound request line * then the transformation will take place. * Case matters. */ char trigger_string[] = "HTTP_OPENPGP_DECRYPT"; /* Module related items... */ module AP_MODULE_DECLARE_DATA transform_module ; #define MOD_TRANSFORM_DEFAULT_BUFFERSIZE 8096 /* The transformation STATES... */ #define MOD_TRANSFORM_STATE_IDLE 0 #define MOD_TRANSFORM_STATE_GET_REQUEST_LINE 1 #define MOD_TRANSFORM_STATE_GET_REQUEST_HEADERS 2 #define MOD_TRANSFORM_STATE_GET_REQUEST_CONTENT 3 #define MOD_TRANSFORM_STATE_DO_THE_TRANSFORMATION 4 #define MOD_TRANSFORM_STATE_PUT_REQUEST_LINE 5 #define MOD_TRANSFORM_STATE_PUT_REQUEST_HEADERS 6 #define MOD_TRANSFORM_STATE_PUT_REQUEST_CONTENT 7 /* Our own filter CONTEXT data... */ typedef struct transform_ctx_t { int state; long content_length; int content_length_is_known; /* A flat buffer for transforming the request... */ unsigned char *content_data_buffer; long content_data_buffer_len; unsigned char *content_data_buffer_ptr; long content_data_buffer_bytesleft; } transform_ctx; /* The input filter function itself... */ static int transform_input_filter( ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { transform_ctx *ctx = f->ctx; apr_status_t status; apr_status_t ret; apr_bucket *b; apr_bucket *b2; apr_off_t bytes_to_read = 0; unsigned char *p1; unsigned char *p2; const char *buf = 0; int return_to_caller = 0; int transform_this_request = 0; long p2len; long p2maxlen; long bytes_read = 0; long bytes_left = 0; long bytes_to_copy = 0; #define CONTENT_LENGTH_STRING_MAXLEN 90 char content_length_string[ CONTENT_LENGTH_STRING_MAXLEN + 2 ]; if ( mode == AP_MODE_EATCRLF ) { /* Not something we are concerned with... */ return ap_get_brigade( f->next, bb, mode, block, readbytes ); } if ( !ctx ) { ctx = f->ctx = apr_pcalloc( f->c->pool, sizeof( *ctx ) ); if ( ctx ) { ctx->state = MOD_TRANSFORM_STATE_GET_REQUEST_LINE; ctx->content_length = 0; ctx->content_length_is_known = 0; ctx->content_data_buffer = 0; ctx->content_data_buffer_len = 0; ctx->content_data_buffer_ptr = 0; ctx->content_data_buffer_bytesleft = 0; } else /* Whoops! We didn't get the memory we needed */ { /* TODO: Log an error message */ return( APR_EGENERAL ); /* Abort */ } }/* End 'if( !ctx )' */ for ( ;; ) /* Stay in the state handler until it's OK to exit... */ { bytes_read = 0; buf = NULL; /* Process the current state... */ switch( ctx->state ) { case MOD_TRANSFORM_STATE_IDLE: /* Do nothing... */ return( ap_get_brigade( f->next, bb, mode, block, readbytes )); case MOD_TRANSFORM_STATE_GET_REQUEST_LINE: ret = ap_get_brigade( f->next, bb, mode, block, readbytes ); if ( ret == APR_SUCCESS ) { b = APR_BRIGADE_FIRST(bb); /* Call apr_bucket_read() and get the new request line */ status = (apr_status_t) apr_bucket_read(b, &buf, &bytes_read, APR_BLOCK_READ); if ( status != APR_SUCCESS ) { /* Something weird happened. */ /* Just return to caller... */ return_to_caller = 1; break; } /* If we got some data... process it... */ if ( bytes_read > 0 ) { /* We only check POST requests for now... */ if ( strnicmp( buf, "POST", 4 ) == 0 ) { if ( strstr( buf, trigger_string ) ) { transform_this_request = 1; } }/* End 'if( POST )' */ if ( transform_this_request ) { /* Get all the request headers now... */ ctx->state = MOD_TRANSFORM_STATE_GET_REQUEST_HEADERS; apr_bucket_delete( b ); /* Discard the bucket */ } else /* Leave this one alone... */ { ctx->state = MOD_TRANSFORM_STATE_IDLE; return_to_caller = 1; } }/* End 'if( bytes_read > 0 )' */ }/* End 'if ( apr_get_brigade() call SUCCEEDED )' */ else /* ap_get_brigade() call FAILED... */ { /* TODO: Log an error */ return_to_caller = 1; } break; case MOD_TRANSFORM_STATE_GET_REQUEST_HEADERS: /* Stay in AP_MODE_GETLINE until "End Of Header" is seen */ ret = ap_get_brigade( f->next, bb, mode, block, readbytes ); if ( ret == APR_SUCCESS ) { b = APR_BRIGADE_FIRST(bb); /* Call apr_bucket_read() and get some data... */ status = (apr_status_t) apr_bucket_read(b, &buf, &bytes_read, APR_BLOCK_READ); if ( status != APR_SUCCESS ) { return_to_caller = 1; break; } /* If we got some data... process it... */ if ( bytes_read > 0 ) { bytes_left = bytes_read; /* Bytes left to process */ if ( strnicmp( buf, "Content-length:", 15 ) == 0 ) { /* Get the Content-Length value... */ p1 = (char *) buf; p1 += 15; p2 = &content_length_string[0]; p2len = 0; p2maxlen = CONTENT_LENGTH_STRING_MAXLEN; while( *p1!=0 && *p1<33) p1++; while( *p1!=0 && *p1>32 && p2lencontent_length = (long) atol( content_length_string ); ctx->content_length_is_known = 1; } else if ( buf[0]==13 || buf[0]==10 ) { /* Is there any content data coming? */ if ( !ctx->content_length_is_known ) { /* TODO: Create a brigade and read * into it until "Transfer-encoding" * indicates "End of Data". */ } else if ( ctx->content_length > 0 ) { /* There is content data coming so record it */ ctx->state = MOD_TRANSFORM_STATE_GET_REQUEST_CONTENT; /* Allocate a buffer to hold the content data */ ctx->content_data_buffer = malloc( (ctx->content_length+2) ); if ( ctx->content_data_buffer ) { /* Reset the memory to all NULLS... */ memset( ctx->content_data_buffer, 0, (ctx->content_length+2) ); /* Reset the content data work pointer to */ /* the start of the allocated buffer... */ ctx->content_data_buffer_len = (long) 0L; ctx->content_data_buffer_bytesleft = (long) 0L; ctx->content_data_buffer_ptr = ctx->content_data_buffer; }/* End 'if( ctx->content_data_buffer )' */ else /* Memory allocation FAILED... */ { /* We are not going to be able to */ /* record the data. */ /* Drop into IDLE mode... */ ctx->state = MOD_TRANSFORM_STATE_IDLE; /* TODO: Log an error */ return APR_EGENERAL; } }/* End 'if( ctx->content_length > 0 )' */ }/* End 'else if ( buf[0]==13 || buf[0]==10 )' */ }/* End 'if( bytes_read > 0 )' */ apr_bucket_delete( b ); /* Destroy the bucket */ }/* End 'if ( apr_get_brigade() call SUCCEEDED )' */ else /* ap_get_brigade() call FAILED... */ { /* TODO: Log an error */ return_to_caller = 1; } break; case MOD_TRANSFORM_STATE_GET_REQUEST_CONTENT: bytes_to_read = ( ctx->content_length - ctx->content_data_buffer_len ); ret = ap_get_brigade( f->next, bb, AP_MODE_READBYTES, APR_BLOCK_READ, bytes_to_read ); if ( ret == APR_SUCCESS ) { b = APR_BRIGADE_FIRST(bb); /* Call apr_bucket_read() and get some data... */ status = (apr_status_t) apr_bucket_read(b, &buf, &bytes_read, APR_BLOCK_READ); if ( status != APR_SUCCESS ) { /* Something weird happened. */ /* Just return to caller. */ return_to_caller = 1; break; } /* If we got some data... process it... */ if ( bytes_read > 0 ) { bytes_left = bytes_read; /* Bytes left to process */ p1 = (char *) buf; /* Assume ALL of the bytes are needed... */ bytes_to_copy = bytes_left; /* Check for overflow. Adjust, if necessary... */ if ( ( ctx->content_data_buffer_len + bytes_to_copy ) > ctx->content_length ) { /* Only copy as many bytes as we need to */ /* reach the actual 'Content-Length:' value... */ bytes_to_copy = ( ctx->content_length - ctx->content_data_buffer_len ); } /* Copy the data out of the bucket now... */ memcpy( ctx->content_data_buffer_ptr, buf, bytes_to_copy ); /* Advance counters and pointers... */ ctx->content_data_buffer_ptr += bytes_to_copy; ctx->content_data_buffer_len += bytes_to_copy; ctx->content_data_buffer_bytesleft += bytes_to_copy; /* Subtract what was copied from the */ /* 'bytes_left' counter... */ bytes_left -= bytes_to_copy; /* Are we done? */ if ( ctx->content_data_buffer_len >= ctx->content_length ) { ctx->state = MOD_TRANSFORM_STATE_DO_THE_TRANSFORMATION; }/* End 'if ( All Content Data Received )' */ }/* End 'if( bytes_read > 0 )' */ apr_bucket_delete( b ); /* Destroy the bucket */ }/* End 'if ( apr_get_brigade() call SUCCEEDED )' */ else /* ap_get_brigade() call FAILED... */ { /* TODO: Log an error */ return_to_caller = 1; } break; case MOD_TRANSFORM_STATE_DO_THE_TRANSFORMATION: /* YOUR CODE GOES HERE! * Transform the flat data buffer as needed. * * This demo assumes that the payload data is * NOT encoded and is already a fully formed * secondary request so it just moves on. */ /* Start the output phase now... */ ctx->state = MOD_TRANSFORM_STATE_PUT_REQUEST_LINE; break; case MOD_TRANSFORM_STATE_PUT_REQUEST_LINE: /* Send the NEW request line now... */ ctx->content_data_buffer_ptr = ctx->content_data_buffer; p2 = ctx->content_data_buffer_ptr; p2len = 0; /* Find the end of the new request line */ /* in the transformed request buffer... */ while( *p2!=0 && *p2!=10 ) { p2len++; p2++; } if ( *p2 == 10 ) p2len++; /* Include LF */ /* Create a heap bucket to hold the new */ /* request line... */ b2 = apr_bucket_heap_create(ctx->content_data_buffer_ptr, p2len, NULL, f->c->bucket_alloc); /* Add the new request line to the brigade... */ APR_BRIGADE_INSERT_TAIL( bb, b2 ); ctx->content_data_buffer_ptr += p2len; ctx->content_data_buffer_bytesleft -= p2len; /* Start sending the headers next... */ ctx->state = MOD_TRANSFORM_STATE_PUT_REQUEST_HEADERS; return_to_caller = 1; break; case MOD_TRANSFORM_STATE_PUT_REQUEST_HEADERS: p2 = ctx->content_data_buffer_ptr; p2len = 0; /* Find the next CRLF in our new data buffer... */ while( *p2!=0 && *p2!=10 ) { p2len++; p2++; } if ( *p2 == 10 ) { p2len++; /* Include LF in the data copy */ } else /* Search terminated on NULL instead of LF... */ { /* We do NOT increment 'p2len' and we keep the */ /* character that ended the search. */ } /* Create a new HEAP bucket to hold the header line... */ b2 = apr_bucket_heap_create(ctx->content_data_buffer_ptr, p2len, NULL, f->c->bucket_alloc); if ( b2 ) { /* If the bucket was created OK then add it to */ /* the end of the brigade... */ APR_BRIGADE_INSERT_TAIL( bb, b2 ); } else /* apr_bucket_heap_create() FAILED... */ { /* TODO: Log an error */ } ctx->content_data_buffer_ptr += p2len; /* Advance */ ctx->content_data_buffer_bytesleft -= p2len; /* Subtract */ /* Are we done adding headers? */ if ( p2len < 3 ) /* We just added the EOH bucket */ { /* Advance to the next 'state'... */ ctx->state = MOD_TRANSFORM_STATE_PUT_REQUEST_CONTENT; } return APR_SUCCESS; /* Just return to caller now... */ case MOD_TRANSFORM_STATE_PUT_REQUEST_CONTENT: p2 = ctx->content_data_buffer_ptr; p2len = ctx->content_data_buffer_bytesleft; /* CHECK 'readbytes' value against 'p2len' value... * * Make sure we don't 'give back' more than the specified * number of 'readbytes'... */ if ( readbytes > 0 ) /* A positive value was passed */ { if ( p2len > readbytes ) { p2len = (long) readbytes; /* Equalize */ } } /* Create a new HEAP bucket to hold the content data... */ b2 = apr_bucket_heap_create(ctx->content_data_buffer_ptr, p2len, NULL, f->c->bucket_alloc); if ( b2 ) { /* If the bucket was created OK then add it to */ /* the end of the brigade... */ APR_BRIGADE_INSERT_TAIL( bb, b2 ); } else /* apr_bucket_heap_create() FAILED... */ { /* TODO: Log an error */ } ctx->content_data_buffer_ptr += p2len; /* Advance */ ctx->content_data_buffer_bytesleft -= p2len; /* Subtract */ if ( ctx->content_data_buffer_bytesleft < 1 ) { if ( ctx->content_data_buffer ) { free( ctx->content_data_buffer ); /* Free memory */ ctx->content_data_buffer = 0; /* Reset pointer */ ctx->content_data_buffer_ptr = 0; /* Reset pointer */ ctx->content_data_buffer_len = 0; /* Reset length */ }/* End 'if( ctx->content_data_buffer )' */ /* Reset the ctx->content_length value and flag(s)... */ ctx->content_length = 0; ctx->content_length_is_known = 0; /* Drop into the IDLE state when done... */ ctx->state = MOD_TRANSFORM_STATE_IDLE; }/* End 'if ( ctx->content_data_buffer_bytesleft < 1 )' */ /* We can simply return to the caller at this point... */ return APR_SUCCESS; default: /* Safety catch */ /* TODO: We should never hit here. Log an error. */ return_to_caller = 1; /* Just return to the caller */ break; }/* End of switch( ctx->state ) */ if ( return_to_caller ) { break; /* Break out of 'for(;;)' loop and return to caller */ } }/* End 'for(;;)' loop that runs the state handler */ return APR_SUCCESS; } static int transform_pre_conn(conn_rec *c, void *csd) { ap_add_input_filter("TRANSFORM_INPUT_FILTER", NULL, NULL, c); return OK; } static void transform_register_hooks(apr_pool_t *p) { /* NOTE: SSL is CONNECTION +5 so use +3 */ ap_register_input_filter("TRANSFORM_INPUT_FILTER", transform_input_filter, NULL, AP_FTYPE_CONNECTION + 3) ; ap_hook_pre_connection(transform_pre_conn, NULL, NULL, APR_HOOK_MIDDLE); } module AP_MODULE_DECLARE_DATA transform_module = { STANDARD20_MODULE_STUFF, NULL, NULL, NULL, NULL, NULL, transform_register_hooks }; /* END OF FILE */ ************************************** Get a sneak peek of the all-new AOL at http://discover.aol.com/memed/aolcom30tour -------------------------------1187763800 Content-Type: text/html; charset="US-ASCII" Content-Transfer-Encoding: quoted-printable
* HOW TO COMPLETELY TRANSFORM AN INB= OUND APACHE REQUEST
 
>Arturo wrote...
>
>I want t= o Completely Transform a Request.
>100% transformation.
>
&g= t;Based on a certain logic, If an incoming request matches one
>of my= action triggers, then I want to apply a transformation
>to the 100%=20= of the incoming request. I know I can do that when
>I just want to mo= dify brigade-by-brigade. But I need to read
>the WHOLE request before= doing so. Even the METHOD line.
>Even the headers. Even the body. Al= l of it. Then, completely
>transform that into another request, and h= ave Apache process it.
>
>With the current input filtering frame= work, at the connection
>level, I should be able to do it. But I can'= t.
>
>If you NEED an example of what I'd like to transform, and=20= into
>WHAT i want to transform it, see this post:
>
>What= I'd like to transform:
>http://www.mail-archive.com/dev@httpd.apache.= org/msg37206.html
>
>Into WHAT I want to transform it: a complet= ely different request
>(i.e different method line, different headers=20= and different body,
>and I can't do that in stages, I have to read th= e whole request first).
>
>Sincerely,
>
>Arturo "Bua= nzo" Busleiman -
>Consultor Independiente en Seguridad Informatica>
> In case you want to take a look, you can check out the filter=20=
> function from...
>
> http://www.buanzo.com.ar/files/openpgp.con= n.filter.in.c
 
I've looked at the code there and you definit= ely are on the
right track. There is nothing fundamentally wrong with you= r
code except, as you discovered, you have to be totally aware
of what= is actually happening during the input phase or it's
easy to trip up and= get an "Error reading headers" from inside
the ap_get_mime_headers_core(= ) routine.
 
>> Kevin wrote...
>>
>> Just= to satisfy my own curiosity I worked up
>> a module here that is,=20= in fact, able to do what
>> you want. There don't seem to be any f= atal flaws
>> in the input filtering that would prevent it.
>=
> Arturo responded...
>
> Great, Can I take a look? That'= d be cool.
 
Sure. Entire filter source code is included below. 
The following "mod_transform.c" filter does
EXACTLY what you= are trying to do.
 
It performs a complete, 100 percent transfor= mation on
an inbound Apache request.
 
I tested it with your o= wn sample non-encrypted
transformation input test and it works perfectly= fine here.
 
The code can certainly be consolidated but I used a=
STATE HANDLER to make it CLEAR what is happening when
and why your c= ode was having problems.
 
I hope this is of some help and if any= one who knows more
than I do about filtering wants to follow up with more=
pointers please go for it. We all have things to learn.
 
Lat= er...
Kevin
 
COMPLETE SOURCE CODE FOR MOD_TRANSFORM.C
&nbs= p;
/* mod_transform.c - Completely tran= sform an inbound request
 *
 * Author: Kevin Kiley - 08/12/0= 7
 *
 * There are no configuration commands.
 *
&= nbsp;* To install and run just put mod_transform.so in your server's
&nbs= p;* ../modules directory and then add the following to the
 * HTTPD=20= config file...
 *
 * LoadModule transform_module modules/mod= _transform.so
 *
 * The filter will be loaded automatically=20= at runtime.
 *
 * See the 'YOUR CODE GOES HERE' comment in t= he TRANSFORMATION
 * section to add any custom transformation(s). *
 * This demo assumes that the POST data is NOT encrypted an= d
 * is already a fully formed secondary request. It simply
 = ;* "Transforms" the initial request into the secondary one.
 */
<= /FONT>
 
#include "httpd.= h"
#include "http_connection.h" /* Required for ap_hook_pre_xxxx() refere= nces */
#include "http_config.h"
#include "http_core.h"
#include "h= ttp_log.h"
 
/* Globals */
 
/* The 'trigger string' * If this string is part of the inbound request line
 * then= the transformation will take place.
 * Case matters.
 */ 
char trigger_string[] =3D "HTTP_OPENPGP_DECRYPT";
 
/*= Module related items... */
 
module AP_MODULE_DECLARE_DATA trans= form_module ;
 
#define MOD_TRANSFORM_DEFAULT_BUFFERSIZE 8096
=  
/* The transformation STATES... */
 
#define MOD_TRANSF= ORM_STATE_IDLE          &n= bsp;       0
#define MOD_TRANSFORM_STATE_GE= T_REQUEST_LINE      1
#define MOD_TRANSFORM_STAT= E_GET_REQUEST_HEADERS   2
#define MOD_TRANSFORM_STATE_GET_REQUE= ST_CONTENT   3
#define MOD_TRANSFORM_STATE_DO_THE_TRANSFORMATIO= N 4
#define MOD_TRANSFORM_STATE_PUT_REQUEST_LINE    &= nbsp; 5
#define MOD_TRANSFORM_STATE_PUT_REQUEST_HEADERS   6
= #define MOD_TRANSFORM_STATE_PUT_REQUEST_CONTENT   7
 
/= * Our own filter CONTEXT data... */
 
typedef struct transform_ct= x_t
{
    int       =      state;
    long   =         content_length;
  &n= bsp; int            c= ontent_length_is_known;
 
    /* A flat buffer for= transforming the request... */
 
    unsigned cha= r *content_data_buffer;
    long    &n= bsp;      content_data_buffer_len;
  &= nbsp; unsigned char *content_data_buffer_ptr;
    long&nbs= p;          content_data_buffer= _bytesleft;
 
} transform_ctx;
 
/* The input filter f= unction itself... */
 
static int transform_input_filter(
ap_f= ilter_t *f,
apr_bucket_brigade *bb,
ap_input_mode_t mode,
apr_read_= type_e block,
apr_off_t readbytes)
{
    transform_c= tx *ctx =3D f->ctx;
    apr_status_t status;
 &= nbsp;  apr_status_t ret;
    apr_bucket *b;
 =    apr_bucket *b2;
    apr_off_t bytes_to_read=20= =3D 0;
    unsigned char *p1;
    unsign= ed char *p2;
    const char *buf =3D 0;
  &nb= sp; int return_to_caller =3D 0;
    int transform_this_req= uest =3D 0;
    long p2len;
    long p2m= axlen;
    long bytes_read =3D 0;
    lo= ng bytes_left =3D 0;
    long bytes_to_copy =3D 0;
&nbs= p;
    #define CONTENT_LENGTH_STRING_MAXLEN 90
 &n= bsp;  char  content_length_string[ CONTENT_LENGTH_STRING_MAXLEN +=20= 2 ];
 
    if ( mode =3D=3D AP_MODE_EATCRLF )
&= nbsp;     {
       /* N= ot something we are concerned with... */
 
   &nbs= p;   return ap_get_brigade( f->next, bb, mode, block, readbytes= );
      }
 
    if (= !ctx )
      {
     = ;  ctx =3D f->ctx =3D apr_pcalloc( f->c->pool, sizeof( *ctx )=20= );
 
       if ( ctx )
 &nb= sp;       {
     &= nbsp;    ctx->state =3D MOD_TRANSFORM_STATE_GET_REQUEST_LI= NE;
 
          ctx-= >content_length =3D 0;
        = ;  ctx->content_length_is_known =3D 0;
    &n= bsp;     ctx->content_data_buffer =3D 0;
 &nb= sp;        ctx->content_data_buffer_le= n =3D 0;
          ctx->c= ontent_data_buffer_ptr =3D 0;
       &= nbsp;  ctx->content_data_buffer_bytesleft =3D 0;
  &nbs= p;      }
       e= lse /* Whoops! We didn't get the memory we needed */
   &n= bsp;     {
       =    /* TODO: Log an error message */
 
   = ;       return( APR_EGENERAL ); /* Abort */         }
 
  = ;    }/* End 'if( !ctx )' */
 
   =20= for ( ;; ) /* Stay in the state handler until it's OK to exit... */
 = ;      {
      &nb= sp; bytes_read =3D 0;
        buf =3D=20= NULL;
 
        /* Process the= current state... */
 
       = switch( ctx->state )
        =   {
           cas= e MOD_TRANSFORM_STATE_IDLE:
 
      = ;          /* Do nothing... */<= /FONT>
 
      =           return( ap_get_brigad= e( f->next, bb, mode, block, readbytes ));
 
   = ;        case MOD_TRANSFORM_STATE_GET_REQ= UEST_LINE:
 
        &nbs= p;       ret =3D ap_get_brigade( f->next, b= b, mode, block, readbytes );
 
     &nbs= p;          if ( ret =3D=3D APR= _SUCCESS )
          &n= bsp;       {
     =             &nbs= p; b =3D APR_BRIGADE_FIRST(bb);
 
     &= nbsp;            = ; /* Call apr_bucket_read() and get the new request line */
 
&nb= sp;            &= nbsp;     status =3D (apr_status_t)
   = ;            &nb= sp;   apr_bucket_read(b, &buf, &bytes_read, APR_BLOCK_READ= );
 
          =          if ( status !=3D APR_SUCCES= S )
           &nb= sp;         {
   &= nbsp;            = ;      /* Something weird happened. */
 &nb= sp;            &= nbsp;       /* Just return to caller... */
=  
           =            return_to_calle= r =3D 1;
 
         =              bre= ak;
           &nb= sp;         }
 
 &nb= sp;            &= nbsp;    /* If we got some data... process it... */
 =
            =        if ( bytes_read > 0 )
  = ;            &nb= sp;      {
      &= nbsp;            = ;   /* We only check POST requests for now... */
 
&nbs= p;            &n= bsp;        if ( strnicmp( buf, "POST", 4= ) =3D=3D 0 )
          = ;            &nb= sp; {
           &= nbsp;            = ; if ( strstr( buf, trigger_string ) )
     &nbs= p;            &n= bsp;        {
    =             &nbs= p;           transform_thi= s_request =3D 1;
         &n= bsp;            =      }
 
      =             &nbs= p;     }/* End 'if( POST )' */
 
  =             &nbs= p;       if ( transform_this_request )
&nbs= p;            &n= bsp;          {
  =             &nbs= p;          /* Get all the requ= est headers now... */
 
       = ;            &nb= sp;     ctx->state =3D MOD_TRANSFORM_STATE_GET_REQUES= T_HEADERS;
 
        &nbs= p;            &n= bsp;   apr_bucket_delete( b ); /* Discard the bucket */
 &= nbsp;            = ;          }
  &nb= sp;            &= nbsp;      else /* Leave this one alone... */
&n= bsp;            =            {
 &nbs= p;            &n= bsp;          ctx->state=20= =3D MOD_TRANSFORM_STATE_IDLE;
 
     &nb= sp;            &= nbsp;      return_to_caller =3D 1;
  &= nbsp;            = ;         }
 
  = ;            &nb= sp;      }/* End 'if( bytes_read > 0 )' */
&n= bsp;
           &n= bsp;      }/* End 'if ( apr_get_brigade() call SUCC= EEDED )' */
 
        &nb= sp;       else /* ap_get_brigade() call FAILED= ... */
           =        {
     &nbs= p;             /= * TODO: Log an error */
 
      &nb= sp;            return= _to_caller =3D 1;
         &= nbsp;        }
 
  &= nbsp;            = ; break;
 
         =   case MOD_TRANSFORM_STATE_GET_REQUEST_HEADERS:
 
 &nbs= p;            &n= bsp; /* Stay in AP_MODE_GETLINE until "End Of Header" is seen */
             &n= bsp;   ret =3D ap_get_brigade( f->next, bb, mode, block, readby= tes );
 
         &n= bsp;      if ( ret =3D=3D APR_SUCCESS )
 &n= bsp;            =     {
        &nbs= p;          b =3D APR_BRIGADE_F= IRST(bb);
 
         = ;          /* Call apr_bucket_r= ead() and get some data... */
 
     &nb= sp;            =20= status =3D (apr_status_t)
        = ;           apr_bucket_rea= d(b, &buf, &bytes_read, APR_BLOCK_READ);
 
  &n= bsp;            =     if ( status !=3D APR_SUCCESS )
    = ;            &nb= sp;    {
        &= nbsp;            = ; return_to_caller =3D 1;
        = ;            &nb= sp; break;
          &n= bsp;          }
 
&n= bsp;            =       /* If we got some data... process it... */ 
           = ;        if ( bytes_read > 0 )
&nbs= p;            &n= bsp;       {
     =             &nbs= p;    bytes_left =3D bytes_read; /* Bytes left to process */<= BR> 
          &nb= sp;           if ( strnicm= p( buf, "Content-length:", 15 ) =3D=3D 0 )
     =             &nbs= p;      {
      &n= bsp;            =       /* Get the Content-Length value... */
<= /STRONG>

     &n= bsp;            =        p1      =20= =3D (char *) buf;
         &= nbsp;            = ;   p1      +=3D 15;
   = ;            &nb= sp;         p2   &nbs= p;   =3D &content_length_string[0];
    = ;            &nb= sp;        p2len    =3D 0;=
            =              p2m= axlen =3D CONTENT_LENGTH_STRING_MAXLEN;
 
    = ;            &nb= sp;        while( *p1!=3D0 && *p1= <33) p1++;
          = ;            &nb= sp;  while( *p1!=3D0 && *p1>32 && p2len<p2maxlen=20= ) {
           &nb= sp;            &= nbsp;       *p2++ =3D *p1++; p2len++; }
&nb= sp;
           &nb= sp;            =20= *p2 =3D 0; /* Terminate scratch buffer with NULL */
 
  = ;            &nb= sp;          /* Get the actual=20= byte count now... */
 
       =             &nbs= p;     ctx->content_length =3D (long)
  =             &nbs= p;          atol( content_lengt= h_string );
          &= nbsp;       
    &= nbsp;            = ;        ctx->content_length_is_known=20= =3D 1;
           =              }            &n= bsp;         else if ( buf[0]=3D=3D1= 3 || buf[0]=3D=3D10 )
        &nb= sp;            &= nbsp;  {
 
        &= nbsp;            = ;    /* Is there any content data coming? */
 
&nb= sp;            &= nbsp;           if ( !ctx-= >content_length_is_known )
       &= nbsp;            = ;       {
     &nb= sp;            &= nbsp;         /* TODO: Create a= brigade and read
         &= nbsp;            = ;       * into it until "Transfer-encoding"            &nb= sp;            &= nbsp;   * indicates "End of Data".
    &nbs= p;            &n= bsp;           */
 = ;            &nb= sp;            =20= }
            = ;             el= se if ( ctx->content_length > 0 )
     &nb= sp;            &= nbsp;        {
    = ;            &nb= sp;           /* There is=20= content data coming so record it */
 
    &nb= sp;            &= nbsp;          ctx->sta= te =3D MOD_TRANSFORM_STATE_GET_REQUEST_CONTENT;
 
  &nb= sp;            &= nbsp;            /* A= llocate a buffer to hold the content data */
 
   =             &nbs= p;            ctx->= ;content_data_buffer =3D malloc( (ctx->content_length+2) );
 
=             &nbs= p;            &n= bsp;  if ( ctx->content_data_buffer )
    &nb= sp;            &= nbsp;            {            &nb= sp;            &= nbsp;     /* Reset the memory to all NULLS... */
&nbs= p;
           &nbs= p;            &n= bsp;      memset( ctx->content_data_buffer, 0, (= ctx->content_length+2) );
 
     &nbs= p;            &n= bsp;            /* Re= set the content data work pointer to */
     &nb= sp;            &= nbsp;            /* t= he start of the allocated buffer... */
 
    =             &nbs= p;            &n= bsp; ctx->content_data_buffer_len      =20= =3D (long) 0L;
         &nbs= p;            &n= bsp;        ctx->content_data_buffer_b= ytesleft =3D (long) 0L;
        &= nbsp;            = ;          ctx->content_data= _buffer_ptr       =3D ctx->content_data_buf= fer;
 
         &nbs= p;            &n= bsp;       }/* End 'if( ctx->content_data_b= uffer )' */
 
        &nb= sp;            &= nbsp;      else /* Memory allocation FAILED... */            &n= bsp;            =      {
       &nbs= p;            &n= bsp;          /* We are not goi= ng to be able to */
         = ;            &nb= sp;         /* record the data. */ 
          &nbs= p;            &n= bsp;       /* Drop into IDLE mode... */
&nb= sp;
           &nb= sp;            &= nbsp;      ctx->state =3D MOD_TRANSFORM_STATE_ID= LE;
 
          = ;            &nb= sp;        /* TODO: Log an error */
&n= bsp;
           &n= bsp;            =        return APR_EGENERAL;
  &nb= sp;            &= nbsp;            = ;  }
 
         = ;            &nb= sp;     }/* End 'if( ctx->content_length > 0 )' */=
 
          &n= bsp;            = }/* End 'else if ( buf[0]=3D=3D13 || buf[0]=3D=3D10 )' */
 
&nbs= p;            &n= bsp;       }/* End 'if( bytes_read > 0 )' *= /
 
          &= nbsp;        apr_bucket_delete( b ); /* D= estroy the bucket */
 
       =            }/* End 'if ( a= pr_get_brigade() call SUCCEEDED )' */
 
    &= nbsp;           else /* ap= _get_brigade() call FAILED... */
      &nbs= p;           {
 &n= bsp;            =      /* TODO: Log an error */
 
  &= nbsp;            = ;    return_to_caller =3D 1;
     = ;             }<= BR> 
          &nb= sp;     break;
 
    &nbs= p;      case MOD_TRANSFORM_STATE_GET_REQUEST_CONTEN= T:
 
          =       bytes_to_read =3D
    =             ( ctx->= ;content_length - ctx->content_data_buffer_len );
  
&nbs= p;            &n= bsp;  ret =3D ap_get_brigade( f->next, bb, AP_MODE_READBYTES,
&nb= sp;            &= nbsp;            = ;            APR_BLOC= K_READ, bytes_to_read );
 
      &n= bsp;         if ( ret =3D=3D APR_SUC= CESS )
           =        {
     &nbs= p;             b=   =3D APR_BRIGADE_FIRST(bb);
 
     = ;            &nb= sp; /* Call apr_bucket_read() and get some data... */
 
 &nb= sp;            &= nbsp;    status =3D (apr_status_t)
    = ;            &nb= sp;  apr_bucket_read(b, &buf, &bytes_read, APR_BLOCK_READ);
=  
           =         if ( status !=3D APR_SUCCESS )            &nb= sp;        {
    &= nbsp;            = ;     /* Something weird happened. */
  &nb= sp;            &= nbsp;      /* Just return to caller. */
             &n= bsp;         return_to_caller =3D 1;=
            =           break;
  = ;            &nb= sp;      }
 
    &nb= sp;            &= nbsp; /* If we got some data... process it... */
 
  &n= bsp;            =     if ( bytes_read > 0 )
     = ;            &nb= sp;   {
         &= nbsp;            byte= s_left =3D bytes_read; /* Bytes left to process */
 
  =             &nbs= p;       p1 =3D (char *) buf;
 
&nb= sp;            &= nbsp;        /* Assume ALL of the bytes a= re needed... */
 
        = ;            &nb= sp; bytes_to_copy =3D bytes_left;
 
     = ;            &nb= sp;    /* Check for overflow. Adjust, if necessary... */
&= nbsp;
           &= nbsp;          if ( ( ctx->c= ontent_data_buffer_len + bytes_to_copy ) > ctx->content_length )
&n= bsp;            =            {
 &nbs= p;            &n= bsp;          /* Only copy as m= any bytes as we need to */
       &nbs= p;            &n= bsp;    /* reach the actual 'Content-Length:' value... */
=  
           =             &nbs= p; bytes_to_copy =3D ( ctx->content_length - ctx->content_data_buffer_= len );
           =              } 
          &nbs= p;           /* Copy the d= ata out of the bucket now... */
 
     &= nbsp;            = ;    memcpy( ctx->content_data_buffer_ptr, buf, bytes_to_c= opy );
 
         &n= bsp;            /* Ad= vance counters and pointers... */
 
     = ;            &nb= sp;    ctx->content_data_buffer_ptr    = ;   +=3D bytes_to_copy;
      &nb= sp;            &= nbsp;  ctx->content_data_buffer_len     &nb= sp; +=3D bytes_to_copy;
        &= nbsp;            = ; ctx->content_data_buffer_bytesleft +=3D bytes_to_copy;
 
&nb= sp;            &= nbsp;        /* Subtract what was copied=20= from the */
          &= nbsp;           /* 'bytes_= left' counter... */
 
       &= nbsp;            = ;  bytes_left -=3D bytes_to_copy;
 
    =             &nbs= p;     /* Are we done? */
 
   = ;            &nb= sp;      if ( ctx->content_data_buffer_len >= =3D
           &nb= sp;            &= nbsp;  ctx->content_length )
      =             &nbs= p;     {
       &n= bsp;            =      ctx->state =3D MOD_TRANSFORM_STATE_DO_THE_TRANSF= ORMATION;
 
         = ;            &nb= sp;  }/* End 'if ( All Content Data Received )' */
 
 &= nbsp;            = ;       }/* End 'if( bytes_read > 0 )' */ 
          &nbs= p;        apr_bucket_delete( b ); /* Dest= roy the bucket */
 
       &nb= sp;          }/* End 'if ( apr_= get_brigade() call SUCCEEDED )' */
 
    &nbs= p;           else /* ap_ge= t_brigade() call FAILED... */
       &= nbsp;          {
  = ;            &nb= sp;    /* TODO: Log an error */
 
  &nbs= p;            &n= bsp;   return_to_caller =3D 1;
     &n= bsp;            }
=  
           =      break;
 
     &= nbsp;     case MOD_TRANSFORM_STATE_DO_THE_TRANSFORMATION= :
 
 &nbs= p;            &n= bsp; /* YOUR CODE GOES HERE!
       &n= bsp;         * Transform the flat da= ta buffer as needed.
        &nbs= p;        *
    &n= bsp;            * Thi= s demo assumes that the payload data is
     &nb= sp;           * NOT encode= d and is already a fully formed
       = ;          * secondary request=20= so it just moves on.
        &nbs= p;        */
 
      =           /* Start the output p= hase now... */
 
        =         ctx->state =3D MOD_TRANSFORM_S= TATE_PUT_REQUEST_LINE;
 
      &nbs= p;         break;
 
 = ;          case MOD_TRANSFORM_S= TATE_PUT_REQUEST_LINE:
 
      &nbs= p;         /* Send the NEW request l= ine now... */
      =           ctx->content_data_= buffer_ptr =3D
         &nbs= p;      ctx->content_data_buffer;
 
&= nbsp;            = ;   p2    =3D ctx->content_data_buffer_ptr;
&= nbsp;            = ;   p2len =3D 0;
 
      =           /* Find the end of th= e new request line */
        &nb= sp;       /* in the transformed request buffer= ... */
 
         &n= bsp;      while( *p2!=3D0 && *p2!=3D10 ) {=20= p2len++; p2++; }
 
       &nbs= p;        if ( *p2 =3D=3D 10 ) p2len++; /= * Include LF */
 
        = ;        /* Create a heap bucket to hold=20= the new */
          &n= bsp;     /* request line... */
 
  =             &nbs= p; b2 =3D apr_bucket_heap_create(ctx->content_data_buffer_ptr, p2len, NUL= L, f->c->bucket_alloc);
 
     &nb= sp;          /* Add the new req= uest line to the brigade... */
 
     &n= bsp;          APR_BRIGADE_INSER= T_TAIL( bb, b2 );
 
       &nb= sp;        ctx->content_data_buffer_pt= r       +=3D p2len;
    = ;            ctx->= content_data_buffer_bytesleft -=3D p2len;
 
   &nb= sp;            /* Sta= rt sending the headers next... */
 
     = ;           ctx->state=20= =3D MOD_TRANSFORM_STATE_PUT_REQUEST_HEADERS;
 
   =              ret= urn_to_caller =3D 1;
 
       =          break;
 
 
      =      case MOD_TRANSFORM_STATE_PUT_REQUEST_HEADERS:
&n= bsp;
           &n= bsp;    p2    =3D ctx->content_data_buffer_= ptr;
           &n= bsp;    p2len =3D 0;
 
    &nb= sp;           /* Find the=20= next CRLF in our new data buffer... */
 
    =             while( *p= 2!=3D0 && *p2!=3D10 ) { p2len++; p2++; }
 
  &n= bsp;            = if ( *p2 =3D=3D 10 )
        &nb= sp;         {
   &= nbsp;            = ;   p2len++; /* Include LF in the data copy */
  &nbs= p;            &n= bsp;  }
          =       else /* Search terminated on NULL instead of=20= LF... */
          &nbs= p;       {
     &n= bsp;            = /* We do NOT increment 'p2len' and we keep the */
   &nbs= p;            &n= bsp;  /* character that ended the search. */
    = ;            &nb= sp; }
 
         &nb= sp;      /* Create a new HEAP bucket to hold the he= ader line... */
 
        = ;        b2 =3D apr_bucket_heap_create(ct= x->content_data_buffer_ptr, p2len, NULL, f->c->bucket_alloc);
&n= bsp;
           &n= bsp;    if ( b2 )
      &nbs= p;           {
 &n= bsp;            =      /* If the bucket was created OK then add it to */            &n= bsp;      /* the end of the brigade... */
 =
            =        APR_BRIGADE_INSERT_TAIL( bb, b2 );
&= nbsp;            = ;     }
       &nb= sp;        else /* apr_bucket_heap_create= () FAILED... */
         &nb= sp;        {
    &= nbsp;            = ;  /* TODO: Log an error */
      &nbs= p;           }
 &n= bsp;
           &n= bsp;    ctx->content_data_buffer_ptr   &nbs= p;   +=3D p2len; /* Advance */
     &n= bsp;          ctx->content_d= ata_buffer_bytesleft -=3D p2len; /* Subtract */
 
  &nb= sp;            =20= /* Are we done adding headers? */
 
     = ;           if ( p2len <= ; 3 ) /* We just added the EOH bucket */
     &n= bsp;            {
=             &nbs= p;      /* Advance to the next 'state'... */
&nb= sp;
           &nb= sp;       ctx->state =3D MOD_TRANSFORM_STAT= E_PUT_REQUEST_CONTENT;
        &n= bsp;         }
 
 &n= bsp;            =   return APR_SUCCESS; /* Just return to caller now... */
 
&= nbsp;          case MOD_TRANSFO= RM_STATE_PUT_REQUEST_CONTENT:
  
    &nb= sp;           p2 &nbs= p;  =3D ctx->content_data_buffer_ptr;
    &nb= sp;           p2len =3D ct= x->content_data_buffer_bytesleft;
 
    &n= bsp;           /* CHECK 'r= eadbytes' value against 'p2len' value...
     &n= bsp;           *
 =             &nbs= p;   * Make sure we don't 'give back' more than the specified
&= nbsp;            = ;    * number of 'readbytes'...
    &n= bsp;            */ 
           = ;     if ( readbytes > 0 ) /* A positive value was pa= ssed */
           = ;       {
     &nb= sp;            =20= if ( p2len > readbytes )
       &nb= sp;            =20= {
            = ;          p2len =3D (long) rea= dbytes; /* Equalize */
        &n= bsp;            }
=             &nbs= p;     }
 
     &nbs= p;          /* Create a new HEA= P bucket to hold the content data... */
 
    = ;            b2 =3D a= pr_bucket_heap_create(ctx->content_data_buffer_ptr, p2len, NULL, f->c-= >bucket_alloc);
 
       &n= bsp;        if ( b2 )
  &nbs= p;            &n= bsp;  {
          =          /* If the bucket was create= d OK then add it to */
        &n= bsp;          /* the end of the= brigade... */
 
        =            APR_BRIGADE_INS= ERT_TAIL( bb, b2 );
         = ;         }
   &nb= sp;            else /= * apr_bucket_heap_create() FAILED... */
     &nb= sp;            {
&= nbsp;            = ;      /* TODO: Log an error */
  &nbs= p;            &n= bsp;  }
 
        &n= bsp;       ctx->content_data_buffer_ptr&nbs= p;      +=3D p2len; /* Advance */
  &n= bsp;            = ctx->content_data_buffer_bytesleft -=3D p2len; /* Subtract */
 <= BR>            &= nbsp;   if ( ctx->content_data_buffer_bytesleft < 1 )
&nb= sp;            &= nbsp;    {
        = ;           if ( ctx->c= ontent_data_buffer )
        &nbs= p;            {
&n= bsp;            =          free( ctx->content_data_= buffer );       /* Free  memory */
&nb= sp;            &= nbsp;            = ;  ctx->content_data_buffer     =3D 0; /* Reset=20= pointer */
          &n= bsp;            =      ctx->content_data_buffer_ptr =3D 0; /* Reset poi= nter */
           = ;            &nb= sp;    ctx->content_data_buffer_len =3D 0; /* Reset length= */
 
          = ;           }/* End 'if( c= tx->content_data_buffer )' */
 
     =             &nbs= p; /* Reset the ctx->content_length value and flag(s)... */
 
=             &nbs= p;      ctx->content_length =3D 0;
 &nbs= p;            &n= bsp;    ctx->content_length_is_known =3D 0;
 
&= nbsp;            = ;      /* Drop into the IDLE state when done... */<= BR> 
          &nb= sp;        ctx->state =3D MOD_TRANSFOR= M_STATE_IDLE;
 
        &= nbsp;         }/* End 'if ( ctx->= content_data_buffer_bytesleft < 1 )' */
 
   &n= bsp;            /* We= can simply return to the caller at this point... */
 
 &nbs= p;            &n= bsp; return APR_SUCCESS;
        =   
          = ; default: /* Safety catch */
 
     &nb= sp;          /* TODO: We should= never hit here. Log an error. */
 
     = ;           return_to_call= er =3D 1; /* Just return to the caller */
 
   &nb= sp;            break;=
 
          }/* End= of switch( ctx->state ) */
 
     &n= bsp;  if ( return_to_caller )
      &n= bsp;   {
         =   break; /* Break out of 'for(;;)' loop and return to caller */
&nbs= p;         }
 
 &nbs= p;     }/* End 'for(;;)' loop that runs the state handle= r */
 
    return APR_SUCCESS;
}
 
s= tatic int transform_pre_conn(conn_rec *c, void *csd)
{
  &nb= sp; ap_add_input_filter("TRANSFORM_INPUT_FILTER", NULL, NULL, c);
 <= BR>    return OK;
}
 
static void transform_reg= ister_hooks(apr_pool_t *p)
{
 /* NOTE: SSL is CONNECTION +5 so us= e +3 */
 
  ap_register_input_filter("TRANSFORM_INPUT_FILTER= ", transform_input_filter,
        NUL= L, AP_FTYPE_CONNECTION + 3) ;
 
  ap_hook_pre_connection(tra= nsform_pre_conn, NULL, NULL, APR_HOOK_MIDDLE);
}
 
module AP_M= ODULE_DECLARE_DATA transform_module =3D {
     &= nbsp;  STANDARD20_MODULE_STUFF,
      =   NULL,
        NULL,
 &n= bsp;      NULL,
     &n= bsp;  NULL,
        NULL,
&nbs= p;       transform_register_hooks
};
&nb= sp;
/* END OF FILE */




Get a sneak peek of the all-new AO= L.com.
-------------------------------1187763800--