* 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 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_TRANSF |