/*
* Copyright (c) 2005, 2008 Sun Microsystems, Inc. All Rights Reserved.
* Use is subject to license terms.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "httpd.h"
#include "http_config.h"
#include "http_log.h"
#include "apr_strings.h"
#include "apr_general.h"
#include "util_filter.h"
#include "apr_buckets.h"
#include "http_request.h"
#include "libsed.h"
typedef struct sed_expr_config
{
const char *last_error;
typedef struct sed_config
{
} sed_config;
/* Context for filter invocation for single HTTP request */
typedef struct sed_filter_ctxt
{
ap_filter_t *f;
request_rec *r;
char *outbuf;
char *curoutbuf;
int bufsize;
int numbuckets;
/* This function will be call back from libsed functions if there is any error
* happend during execution of sed scripts
*/
{
return APR_SUCCESS;
}
/* This function will be call back from libsed functions if there is any
* compilation error.
*/
{
return APR_SUCCESS;
}
/* clear the temporary pool (used for transient buckets)
*/
{
ctx->numbuckets = 0;
}
/* alloc_outbuf
* allocate output buffer
*/
{
}
/* append_bucket
* Allocate a new bucket from buf and sz and append to ctx->bb
*/
{
apr_bucket *b;
/* We are not using transient bucket */
}
else {
/* We are using transient bucket */
ctx->numbuckets++;
}
}
return status;
}
/*
* flush_output_buffer
* Flush the output data (stored in ctx->outbuf)
*/
{
char *out;
return status;
return status;
}
/* This is a call back function. When libsed wants to generate the output,
* this function will be invoked.
*/
{
/* dummy is basically filter context. Context is passed during invocation
* of sed_eval_buffer
*/
int remainbytes = 0;
}
if (sz >= remainbytes) {
if (remainbytes > 0) {
buf += remainbytes;
sz -= remainbytes;
}
/* buffer is now full */
/* old buffer is now used so allocate new buffer */
/* if size is bigger than the allocated buffer directly add to output
* brigade */
/* pool might get clear after append_bucket */
}
}
else {
}
}
else {
}
return status;
}
/* Compile a sed expression. Compiled context is saved in sed_cfg->sed_cmds.
* Memory required for compilation context is allocated from cmd->pool.
*/
const char *expr)
{
if (status != APR_SUCCESS) {
return status;
}
}
if (status != APR_SUCCESS) {
}
return status;
}
/* sed eval cleanup function */
{
return APR_SUCCESS;
}
/* Initialize sed filter context. If successful then context is set in f->ctx
*/
{
request_rec *r = f->r;
/* Create the context. Call sed_init_eval. libsed will generated
* output by calling sed_write_output and generates any error by
* invoking log_sed_errf.
*/
ctx->r = r;
ctx->numbuckets = 0;
ctx->f = f;
r, &sed_write_output, r->pool);
if (status != APR_SUCCESS) {
return status;
}
if (usetpool) {
}
else {
}
return APR_SUCCESS;
}
/* Entry function for Sed output filter */
{
apr_bucket *b;
&sed_module);
/* No sed expressions */
}
/* no need to run sed filter for Head requests */
}
if (status != APR_SUCCESS)
return status;
}
/* Here is the main logic. Iterate through all the buckets, read the
* content of the bucket, call sed_eval_buffer on the data.
* sed_eval_buffer will read the data line by line, run filters on each
* line. sed_eval_buffer will generates the output by calling
* sed_write_output which will add the output to ctx->bb. At the end of
* the loop, ctx->bb is passed to the next filter in chain. At the end of
* the data, if new line is not found then sed_eval_buffer will store the
* data in its own buffer.
*
* Once eos bucket is found then sed_finalize_eval will flush the rest of
* the data. If there is no new line in last line of data, new line is
* appended (that is a solaris sed behavior). libsed's internal memory for
* evaluation is allocated on request's pool so it will be cleared once
* request is over.
*
* If flush bucket is found then append the the flush bucket to ctx->bb
* and pass it to next filter. There may be some data which will still be
* in sed's internal buffer which can't be flushed until new line
* character is arrived.
*/
while (!APR_BRIGADE_EMPTY(bb)) {
b = APR_BRIGADE_FIRST(bb);
if (APR_BUCKET_IS_EOS(b)) {
/* Now clean up the internal sed buffer */
if (status != APR_SUCCESS) {
break;
}
/* Move the eos bucket to ctx->bb brigade */
}
else if (APR_BUCKET_IS_FLUSH(b)) {
if (status != APR_SUCCESS) {
break;
}
/* Move the flush bucket to ctx->bb brigade */
}
else {
if (!APR_BUCKET_IS_METADATA(b)) {
if (status == APR_SUCCESS) {
}
if (status != APR_SUCCESS) {
break;
}
}
}
}
if (status == APR_SUCCESS) {
}
if (status == APR_SUCCESS) {
}
}
return status;
}
/* Entry function for Sed input filter */
{
&sed_module);
if (mode != AP_MODE_READBYTES) {
}
/* No sed expression */
}
if (!ctx) {
if (!ap_is_initial_req(f->r)) {
/* XXX : Should we filter the sub requests too */
}
if (status != APR_SUCCESS)
return status;
}
/* Here is the logic :
* Read the readbytes data from next level fiter into bbinp. Loop through
* the buckets in bbinp and read the data from buckets and invoke
* sed_eval_buffer on the data. libsed will generate its output using
* sed_write_output which will add data in ctx->bb. Do it until it have
* atleast one bucket bucket in ctx->bb. At the end of data eos bucket
* should be there.
*
* Once eos bucket is seen, then invoke sed_finalize_eval to clear the
* output. If the last byte of data is not a new line character then sed
* will add a new line to the data that is default sed behaviour. Note
* that using this filter with POST data, caller may not expect this
* behaviour.
*
* If next level fiter generate the flush bucket, we can't do much about
* it. If we want to return the flush bucket in brigade bb (to the caller)
* the question is where to add it?
*/
apr_bucket *b;
/* read the bytes from next level filter */
if (status != APR_SUCCESS) {
return status;
}
b = APR_BUCKET_NEXT(b)) {
if (APR_BUCKET_IS_EOS(b)) {
/* eos bucket. Clear the internal sed buffers */
break;
}
else if (APR_BUCKET_IS_FLUSH(b)) {
/* What should we do with flush bucket */
continue;
}
== APR_SUCCESS) {
if (status != APR_SUCCESS)
return status;
}
}
}
apr_bucket *b = NULL;
}
else {
}
}
return APR_SUCCESS;
}
{
"Failed to compile sed expression. %s",
}
return NULL;
}
{
return cfg;
}
"Sed regular expression for Response"),
"Sed regular expression for Request"),
{NULL}
};
{
}
create_sed_dir_config, /* dir config creater */
NULL, /* dir merger --- default is to override */
NULL, /* server config */
NULL, /* merge server config */
sed_filter_cmds, /* command table */
register_hooks /* register hooks */
};