httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jeff Trawick <trawi...@bellsouth.net>
Subject 2nd pass at an output translation filter
Date Wed, 16 Aug 2000 14:04:08 GMT
This version of the filter is starting to take the shape of what I
think its final form should be.  I would appreciate any help amending
the "stuff that sucks" list as appropriate :)

Have fun,

Jeff

/* stuff that sucks that I know of:
 *
 * bucket handling:
 *  why create an eos bucket when we see it come down the stream?  just send the one
 *  passed as input
 *
 * translation mechanics:
 *  we don't handle overflow/underflow/errors yet
 */

#define XLATE_BUF_SIZE (32*1024) /* we try to send down brigades of this len, but... */
#define XLATE_MIN_BUFF_LEFT 128  /* flush once there is no more than this much
                                  * space is left in the translation buffer */

static int send_downstream(ap_filter_t *f, const char *tmp, apr_ssize_t len)
{
    ap_bucket_brigade *bb;
    apr_ssize_t written;

    bb = ap_brigade_create(f->r->pool);
    ap_brigade_append_buckets(bb, ap_bucket_transient_create(tmp, len, &written));
    ap_assert(written == len); /* You BETTER accept all my data! */
    return ap_pass_brigade(f->next, bb);
}

static void send_eos(ap_filter_t *f)
{
    ap_bucket_brigade *bb;

    bb = ap_brigade_create(f->r->pool);
    ap_brigade_append_buckets(bb, ap_bucket_eos_create());
    ap_pass_brigade(f->next, bb);
}

static void update_bb_links(ap_bucket_brigade *bb, ap_bucket *b)
{
    if (bb->head == b) {
        bb->head = b->next;
    }
    if (bb->tail == b) {
        bb->tail = b->prev;
    }
}

static int xlate_output_filter(ap_filter_t *f, ap_bucket_brigade *bb)
{
    charset_dir_t *dc = ap_get_module_config(f->r->per_dir_config, &charset_lite_module);
    int debug = dc->debug == DEBUG;
    ap_bucket *dptr, *consumed_bucket;
    const char *cur_str;
    apr_ssize_t cur_len, cur_avail;
    char tmp[XLATE_BUF_SIZE];
    apr_ssize_t space_avail;
    int done;
    int bytes_sent_downstream = 0;
    int written;
    apr_status_t rv;

    if (debug) {
        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, f->r->server,
                     "xlate_output_filter() - "
                     "dc: %X charset_source: %s charset_default: %s",
                     (unsigned)dc,
                     dc && dc->charset_source ? dc->charset_source : "(none)",
                     dc && dc->charset_default ? dc->charset_default : "(none)");
    }

    dptr = bb->head;
    done = 0;
    cur_len = 0;
    space_avail = sizeof(tmp);
    consumed_bucket = NULL;
    while (!done) {
        if (!cur_len) { /* no bytes left to process in the current bucket... */
            if (consumed_bucket) {
                update_bb_links(bb, consumed_bucket);
                ap_bucket_destroy(consumed_bucket);
                consumed_bucket = NULL;
            }
            if (!dptr ||
                dptr->read(dptr, &cur_str, &cur_len, 0) == AP_END_OF_BRIGADE) {
                done = 1;
                break;
            }
            consumed_bucket = dptr; /* for axing when we're done reading it */
            dptr = dptr->next; /* get ready for when we access the next bucket */
        }
        /* Try to fill up our tmp buffer with translated data. */
        cur_avail = cur_len;
        rv = apr_xlate_conv_buffer(dc->xlate_output,
                                   cur_str, &cur_avail,
                                   tmp + sizeof(tmp) - space_avail, &space_avail);

        /* Update input ptr and len after consuming some bytes */
        cur_str += cur_len - cur_avail;
        cur_len = cur_avail;

        /* TODO: handle overflows, underflows, and translation failures */
        ap_assert(!rv); 

        if (space_avail < XLATE_MIN_BUFF_LEFT) {
            /* It is time to flush, as there is not enough space left in the
             * current output buffer to bother with converting more data.
             */
            /* TODO: handle errors from this operation */
            written = send_downstream(f, tmp, sizeof(tmp) - space_avail);
            
            /* The filters (or ap_r* routines) upstream apparently want 
             * to know how many bytes were written, not how many of their 
             * bytes were accepted.
             */
            bytes_sent_downstream += written;

            /* tmp is now empty */
            space_avail = sizeof(tmp);
        }
    }

    if (space_avail < sizeof(tmp)) { /* gotta write out what we converted */
        written = send_downstream(f, tmp, sizeof(tmp) - space_avail);
        bytes_sent_downstream += written;
    }

    if (cur_len == AP_END_OF_BRIGADE) {
        send_eos(f);
    }

    return bytes_sent_downstream;
}


-- 
Jeff Trawick | trawick@ibm.net | PGP public key at web site:
     http://www.geocities.com/SiliconValley/Park/9289/
          Born in Roswell... married an alien...

Mime
View raw message