/* Copyright 2006 Joachim Zobel . * * 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * 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 #include #include #include #include #include #include #include APU_DECLARE_DATA const apr_bucket_type_t bucket_type_sax ; #include "frag_buffer.h" #include "buckets_sax.h" /***************************************************************************** * Helpers for sax event handling *****************************************************************************/ // Aligned sizes #define SAX_BUCKET_SIZE APR_ALIGN_DEFAULT(sizeof(bucket_sax)) #define SAX_EVENT_SIZE(x) APR_ALIGN_DEFAULT(sizeof(x)) #define SAX_BASE_SIZE(x) (SAX_BUCKET_SIZE + SAX_EVENT_SIZE(x)) /** * Convert an event type to a string * @param which - The event type * @return The associated string */ static const char *sax_event_which_to_str(sax_event_e which) { #define TO_STR(x) case x: return #x; switch (which) { TO_STR(START_ELT) TO_STR(END_ELT) TO_STR(START_NS) TO_STR(END_NS) TO_STR(PROC_INSTR) TO_STR(START_CD) TO_STR(END_CD) TO_STR(CHARACTER) TO_STR(DEFAULT) TO_STR(WHITE) TO_STR(COMMENT) TO_STR(XML_DECL) default: return "UNKNOWN"; } } /** * Write a debug message to the error log * @param bs - The sax bucket (whose request will be used) * @param msg - will be logged (usual printf format) */ static void sax_event_debug_log(const char *file, int line, bucket_sax *bs, const char *msg, ...) { va_list args; va_start(args, msg); request_rec *r = bs->bctx->r_log ; if (r) ap_log_rerror(file, line, APLOG_DEBUG, 0, r, apr_pvsprintf(bs->bctx->p_tmp, msg, args)) ; va_end(args); } /* * sax_hr_size */ double sax_hr_size(apr_size_t sz, const char **punit) { const double lsz = log2(sz) ; if ( lsz < 10 ) { *punit = "B" ; return sz ; } else if ( lsz < 20 ) { *punit = "k" ; return (double)sz/1024 ; } else if ( lsz < 30 ) { *punit = "M" ; return (double)sz/(1024*1024) ; } else { *punit = "G" ; return (double)sz/(1024*1024*1024) ; } } /* * Memory debugging */ /* * From apr_bucket_alloc.c */ typedef struct node_header_t { apr_size_t size; apr_bucket_alloc_t *alloc; apr_memnode_t *memnode; struct node_header_t *next; } node_header_t; #define SIZEOF_NODE_HEADER_T APR_ALIGN_DEFAULT(sizeof(node_header_t)) /* * sax_get_bucket_mem_size */ apr_size_t sax_get_bucket_mem_size(bucket_sax *bs) { node_header_t *node = (node_header_t *)((char *)bs - SIZEOF_NODE_HEADER_T); return node->size ; } /** * Create a unique id for start/end tags * @return The unique id */ static se_id_t sax_event_get_unique_id(void) { static volatile se_id_t se_id ; if (++se_id < 0) { se_id = 1 ; } return se_id ; } typedef struct { se_id_t se_id ; } se_tag_t ; /* * sax_event_set_start_id */ void sax_event_set_start_id(sax_ctx *ctx, void *event) { se_tag_t *tag = event ; se_id_t *se_id = apr_array_push(ctx->starts) ; tag->se_id = *se_id = sax_event_get_unique_id() ; } /* * sax_event_set_end_id */ void sax_event_set_end_id(sax_ctx *ctx, void *event) { se_tag_t *tag = event ; se_id_t *se_id = apr_array_pop(ctx->starts) ; tag->se_id = -*se_id; } /* * sax_unify_name */ const xml_char_t *sax_unify_name(apr_pool_t *p, unq_set_t *set, const xml_char_t *name) { const xml_char_t *rv = NULL ; if (!name) { /* NULL is already unified */ return rv ; } rv = apr_table_get(set, name) ; if (!rv) { /* Not found, we need to create a new entry */ rv = apr_pstrdup(p, name) ; /* We add the new entry to the set */ apr_table_setn(set, rv, rv) ; } return rv ; } const xml_char_t SEP_NS = ' '; /** * Parse expat names to extract the namespace * @param c - The parsing context. This is needed for name unification. * @param name - The name as passed from expat (with do_nst = 1) * @param pname - The struct to hold the parsed name. */ static void sax_parse_name(sax_ctx *sc, const xml_char_t *name, ns_name_t *pname) { bucket_ctx *c = &sc->bctx ; apr_pool_t *pool = sc->pool ; const xml_char_t *pos = name; char* p_sep = strchr(pos, SEP_NS) ; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, c->r_log, "sax_parse_name will parse %s.", name); if (p_sep) { *p_sep = '\0' ; pname->uri = sax_unify_name(pool, c->unq.uri, pos) ; /* restore seperator */ *p_sep = SEP_NS ; pos = p_sep + 1 ; p_sep = strchr(pos, SEP_NS) ; if (p_sep) { *p_sep = '\0' ; pname->name = sax_unify_name(pool, c->unq.name, pos) ; /* restore seperator */ *p_sep = SEP_NS ; pos = p_sep + 1 ; pname->prefix = sax_unify_name(pool, c->unq.prefix, pos) ; } else { pname->name = sax_unify_name(pool, c->unq.name, pos) ; /* Not found */ pname->prefix = NULL ; } } else { pname->name = sax_unify_name(pool, c->unq.name, pos) ; /* Not found */ pname->uri = NULL ; pname->prefix = NULL ; } #define NVL(x, y) (x?x:y) ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, c->r_log, "sax_parse_name parse %#x:%s|%#x:%s|%#x:%s.", pname->uri, NVL(pname->uri,"-"), pname->name, NVL(pname->name,"-"), pname->prefix, NVL(pname->prefix,"-") ); } /* * sax_ctx_init */ void sax_ctx_init(sax_ctx *ctx, apr_bucket_brigade *bb, ap_filter_t *f, abort_fn abort) { request_rec *r = f->r ; apr_pool_t *rp = r->pool ; ctx->bctx.unq.uri = apr_table_make(rp, 5) ; ctx->bctx.unq.name = apr_table_make(rp, 20) ; ctx->bctx.unq.prefix = apr_table_make(rp, 5) ; ctx->bctx.r_log = r ; apr_pool_create(&ctx->bctx.p_tmp, rp) ; ctx->bctx.sum_mem = 0 ; ctx->mctx = apr_palloc(rp, sizeof(morph_ctx)) ; ctx->mctx->frag_buf = frag_create(rp) ; ctx->mctx->newns = apr_array_make(rp, 5, SAX_EVENT_SIZE(start_ns_t)) ; // ctx->mctx->r = r ; ctx->is_cdata = 0 ; ctx->starts = apr_array_make(rp, 20, sizeof(se_id_t)) ; ctx->pool = r->pool ; ctx->bb = bb ; ctx->list = bb->bucket_alloc ; ctx->f = f ; ctx->r = r ; ctx->abort = abort ; ctx->rv = APR_SUCCESS ; } /* forward decl. */ static void sax_event_frag_write_NOT_IMPL(void *ignored, morph_ctx *mctx) ; /** * Initializes a given sax bucket. * @param bs - The bucket. * @param which - The sax event type of the bucket. * @param event - The event data. * @param bctx - The bucket context. * @param mctx - The morph context. */ static void sax_bucket_init(bucket_sax *bs, sax_event_e which, void *event, bucket_ctx *bctx, morph_ctx *mctx) { sax_bucket_set_which(bs, which) ; bs->event = event ; bs->bctx = bctx ; bs->mctx = mctx ; } /***************************************************************************** * Create sax events *****************************************************************************/ /* * sax_bucket_create_ns */ bucket_sax *sax_bucket_create_ns(sax_ctx *c, const xml_char_t *prefix, const xml_char_t *uri) { /* buf is needed for byte computations */ char *buf = NULL ; bucket_sax *bs = NULL ; start_ns_t *sn = NULL ; /* We allocate it all at once */ buf = apr_bucket_alloc(SAX_BASE_SIZE(start_ns_t), c->list) ; bs = (void *)buf ; buf += SAX_BUCKET_SIZE ; sn = (void *)buf ; sn->prefix = sax_unify_name(c->pool, c->bctx.unq.prefix, prefix) ; sn->uri = sax_unify_name(c->pool, c->bctx.unq.uri, uri) ; sax_bucket_init(bs, START_NS, sn, &c->bctx, c->mctx) ; return bs ; } const char XMLNS[] = "xmlns" ; const char XMLNS_URI[] = "http://www.w3.org/2000/xmlns/" ; /* * sax_bucket_recreate_elt */ bucket_sax *sax_bucket_recreate_elt(bucket_sax *bso, apr_bucket_alloc_t *list) { start_elt_t *old = bso->event ; // char * is needed for byte computations char *buf = NULL ; char *val = NULL ; apr_size_t len_val = 0 ; apr_size_t len_att = 0 ; bucket_sax *bsn ; start_elt_t *new ; // We count the attributes while (old->atts[len_att].name.name) { len_val+=strlen(old->atts[len_att].value)+1; len_att++ ; } // We allocate it all at once buf = apr_bucket_alloc(SAX_BASE_SIZE(start_elt_t) +(len_att+1)*sizeof(attr_t) +len_val, list) ; // We copy the "static" part bsn = (void *)buf ; *bsn = *bso ; buf += SAX_BUCKET_SIZE ; bsn->event = new = (void *)buf ; *new = *old ; buf += SAX_EVENT_SIZE(start_elt_t) ; new->atts = (void *)buf ; memcpy(new->atts, old->atts, (len_att+1)*sizeof(attr_t)) ; val = buf + (len_att+1)*sizeof(attr_t) ; int i = 0 ; while (old->atts[i].name.name) { strcpy(val, old->atts[i].value) ; new->atts[i].value = val ; val += strlen(new->atts[i].value) + 1 ; i++ ; } return bsn ; } /* * sax_bucket_create_elt */ bucket_sax *sax_bucket_create_elt(sax_ctx *c, const xml_char_t* name, const xml_char_t** atts) { // The bucket is created on the stack bucket_sax bs ; start_elt_t se ; apr_size_t len_att = 0 ; while (atts[len_att]) {len_att++;} len_att = len_att/2 ; sax_bucket_init(&bs, START_ELT, &se, &c->bctx, c->mctx) ; sax_parse_name(c, name, &se.name) ; se.atts = apr_bucket_alloc(sizeof(attr_t)*(len_att+1), c->list) ; int i = 0 ; int j = 0 ; while (atts[i]) { sax_parse_name(c, atts[i], &se.atts[j].name) ; i++ ; // We assign the attribute value se.atts[j].value = atts[i] ; i++ ; j++ ; } // terminatig attribute se.atts[j].name.uri = NULL ; se.atts[j].name.name = NULL ; se.atts[j].name.prefix = NULL ; se.atts[j].value = NULL ; // and then recreated in bucket memory. bucket_sax *rv = sax_bucket_recreate_elt(&bs, c->list) ; // This avoids duplication of the code that knows about // the buckets memory layout. apr_bucket_free(se.atts) ; return rv ; } /* * sax_bucket_create_empty */ bucket_sax *sax_bucket_create_empty(sax_ctx *c, sax_event_e which) { bucket_sax *bs = apr_bucket_alloc(SAX_BUCKET_SIZE, c->list) ; sax_bucket_init(bs, which, NULL, &c->bctx, c->mctx) ; return bs ; } /* * sax_bucket_create_char */ bucket_sax *sax_bucket_create_char(sax_ctx *c, const xml_char_t* ebuf, int len, int encode) { char *buf = apr_bucket_alloc(SAX_BASE_SIZE(character_t) +len+1, c->list) ; character_t *chr = NULL ; bucket_sax *bs = (void *)buf ; request_rec *r_log = c->bctx.r_log ; buf += SAX_BUCKET_SIZE ; chr = (void *)buf ; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r_log, "sax_bucket_create_char called with \"%s\".", apr_pstrmemdup(c->bctx.p_tmp, ebuf, len)) ; sax_bucket_init(bs, CHARACTER, chr, &c->bctx, c->mctx) ; chr->len = len ; chr->encode = encode ; memcpy(chr->text, ebuf, len) ; /* text is \0 terminated in addition to the length */ chr->text[len]= '\0' ; ap_assert(bs->which == CHARACTER) ; return bs ; } /* * sax_bucket_create_xml_decl */ bucket_sax *sax_bucket_create_xml_decl(sax_ctx *c, const xml_char_t* version, const xml_char_t* encoding, int standalone) { char *buf = apr_bucket_alloc(SAX_BASE_SIZE(xml_decl_t), c->list) ; xml_decl_t *xd = NULL ; bucket_sax *bs = (void *)buf ; buf += SAX_BUCKET_SIZE ; xd = (void *)buf ; xd->version = apr_pstrdup(c->pool, version) ; xd->encoding = apr_pstrdup(c->pool, encoding) ; xd->standalone = standalone ; sax_bucket_init(bs, XML_DECL, xd, &c->bctx, c->mctx) ; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, c->bctx.r_log, "xml_decl sax bucket with \"%s\", \"%s\", %d created", xd->version, xd->encoding, xd->standalone) ; return bs ; } /* * sax_bucket_create_proc_instr */ bucket_sax *sax_bucket_create_proc_instr(sax_ctx *c, const xml_char_t *target, const xml_char_t *data) { const int len_tg = strlen(target) ; const int len_d = strlen(data) ; char *buf = apr_bucket_alloc(SAX_BASE_SIZE(proc_instr_t) +len_tg+1+len_d+1, c->list) ; proc_instr_t *pi = NULL ; bucket_sax *bs = (void *)buf ; buf += SAX_BUCKET_SIZE ; pi = (void *)buf ; buf += SAX_EVENT_SIZE(proc_instr_t) ; strcpy(buf, target) ; pi->target = buf ; buf += len_tg + 1; strcpy(buf, data) ; pi->data = buf ; sax_bucket_init(bs, PROC_INSTR, pi, &c->bctx, c->mctx) ; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, c->bctx.r_log, "proc_instr sax bucket with \"%s\", \"%s\" created", pi->target, pi->data) ; return bs ; } /***************************************************************************** * SAX event helpers *****************************************************************************/ /** * Writes a ns name to a frag buffer. * @param ns - The ns name. * @param frag_buf - The buffer. */ static void sax_event_frag_write_ns_name(const ns_name_t *ns, frag_buffer_t *frag_buf) { const int len_pfx = ns->prefix?strlen(ns->prefix):0 ; // An xmlns default namespaces yields an attribute that has // a prefix and an uri, but no name. const int len_nm = ns->name?strlen(ns->name):0 ; if (len_pfx > 0) { frag_write(frag_buf, ns->prefix, len_pfx) ; } if (len_pfx > 0 && len_nm > 0) { frag_write(frag_buf, ":", 1) ; } if (len_nm > 0) { frag_write(frag_buf, ns->name, len_nm) ; } } /** * Writes an attribute to a frag buffer. * @param attr - The attribute. * @param frag_buf - The buffer. */ static void sax_event_frag_write_attr(const attr_t *attr, frag_buffer_t *frag_buf) { sax_event_frag_write_ns_name(&attr->name, frag_buf) ; frag_write(frag_buf, "=\"", 2) ; frag_write_enc(frag_buf, attr->value) ; frag_write(frag_buf, "\"", 1) ; } /***************************************************************************** * Parser Helpers *****************************************************************************/ /* * sax_pass_buckets */ apr_status_t sax_pass_buckets(sax_ctx *sctx, int do_abort) { // we pass the current brigade sctx->rv = ap_pass_brigade(sctx->f->next, sctx->bb) ; // clean up the tmp pool apr_pool_clear(sctx->bctx.p_tmp) ; // and clear the brigade for reuse apr_brigade_cleanup(sctx->bb) ; if (do_abort && ( sctx->rv != APR_SUCCESS || sctx->f->c->aborted ) ) { sctx->abort(sctx->f) ; } return sctx->rv ; } static const apr_size_t SZ_PASS_LIMIT = 4*1024*1024 ; /* * sax_bucket_append */ apr_bucket *sax_bucket_append(sax_ctx *c, bucket_sax *e) { apr_bucket_brigade *bb = c->bb ; apr_bucket *b = apr_bucket_alloc(sizeof(*b), bb->bucket_alloc); APR_BUCKET_INIT(b); /* make does not assign this */ b->list = bb->bucket_alloc ; b->free = apr_bucket_free; b = apr_bucket_shared_make(b, e, -1, -1) ; b->type = &bucket_type_sax ; APR_BRIGADE_INSERT_TAIL(bb, b) ; bucket_ctx *bctx = e->bctx ; bctx->sum_mem += sax_get_bucket_mem_size(e) ; const char *unit; double sz = sax_hr_size(sax_get_bucket_mem_size(e)-SIZEOF_NODE_HEADER_T, &unit); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, bctx->r_log, "SAX %s bucket with %.4g %s bytes usable mem. appended.", sax_event_which_to_str(e->which), sz, unit) ; if (bctx->sum_mem > SZ_PASS_LIMIT) { sz = sax_hr_size(bctx->sum_mem, &unit) ; ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, bctx->r_log, "%.4g %s bytes in use. Passing buckets.", sz, unit); sax_pass_buckets(c, 1) ; } return b ; } /* * sax_log_req_create */ request_rec *sax_log_req_create(request_rec *r) { apr_pool_t *rp = r->pool ; // We copy the request rec request_rec *rv = apr_pmemdup(rp, rp, sizeof(request_rec)) ; // and change the copies pool apr_pool_create(&rv->pool, rp) ; return rv ; } /* * sax_log_req_clear */ void sax_log_req_clear(request_rec *r) { apr_pool_clear(r->pool) ; } /***************************************************************************** * SAX event methods *****************************************************************************/ /** * Writes a start element to a frag buffer. * @param se - The start element. * @param mctx - The context holding the frag_buffer. */ static void sax_event_frag_write_START_ELT(void *event, morph_ctx *mctx) { start_elt_t *se = event ; const attr_t *attr = se->atts; frag_write(mctx->frag_buf, "<", 1) ; /* tag */ sax_event_frag_write_ns_name(&se->name, mctx->frag_buf) ; /* add namespace attributes */ start_ns_t *pns = NULL ; while (pns = apr_array_pop(mctx->newns)) { attr_t ns_attr; ns_attr.name.uri = XMLNS_URI ; /* note that this name is a prefix */ ns_attr.name.name = pns->prefix ; ns_attr.name.prefix = XMLNS ; ns_attr.value = pns->uri ; frag_write(mctx->frag_buf, " ", 1) ; sax_event_frag_write_attr(&ns_attr, mctx->frag_buf) ; } /* add other attributes */ for (; attr->value; attr++) { frag_write(mctx->frag_buf, " ", 1) ; sax_event_frag_write_attr(attr, mctx->frag_buf) ; } frag_write(mctx->frag_buf, ">", 1) ; } /** * Writes an end element to a frag buffer. * @param ee - The end element. * @param mctx - The context holding the frag_buffer. */ static void sax_event_frag_write_END_ELT(void *event, morph_ctx *mctx) { end_elt_t *ee = event ; frag_write(mctx->frag_buf, "name, mctx->frag_buf) ; frag_write(mctx->frag_buf, ">", 1) ; } /** * Writes a character event to a frag buffer. * @param c - The characterelement. * @param mctx - The context holding the frag_buffer. */ static void sax_event_frag_write_CHARACTER(void *event, morph_ctx *mctx) { character_t *c = event ; if (c->encode) { frag_write_enc(mctx->frag_buf, c->text) ; } else { frag_write(mctx->frag_buf, c->text, c->len) ; } } /** * Writes a start cd event to a frag buffer. * @param ignored - ignored. * @param mctx - The context holding the frag_buffer. */ static void sax_event_frag_write_START_CD(void *ignored, morph_ctx *mctx) { frag_write(mctx->frag_buf, "frag_buf, "]]>", 3) ; } /** * Writes a comment event to a frag buffer. * @param c - The character element. * @param mctx - The context holding the frag_buffer. */ static void sax_event_frag_write_COMMENT(void *event, morph_ctx *mctx) { character_t *c = event ; frag_write(mctx->frag_buf, "", 3) ; } /** * Writes an XML declaration to a frag buffer. * @param se - The start element. * @param mctx - The context holding the frag_buffer. */ static void sax_event_frag_write_XML_DECL(void *event, morph_ctx *mctx) { xml_decl_t *xd = event ; frag_write(mctx->frag_buf, "frag_buf, xd->version, strlen(xd->version)) ; frag_write(mctx->frag_buf, "\" encoding=\"", 12) ; frag_write(mctx->frag_buf, xd->encoding, strlen(xd->encoding)) ; frag_write(mctx->frag_buf, "\"", 1) ; if (xd->standalone == 1) { frag_write(mctx->frag_buf, " standalone=\"yes\"", 17) ; } else if (xd->standalone == 0) { frag_write(mctx->frag_buf, " standalone=\"no\"", 16) ; } frag_write(mctx->frag_buf, "?>", 2) ; } /** * Writes a processing instruction to a frag buffer. * @param event - The proc. instr. event. * @param mctx - The context holding the frag_buffer. */ static void sax_event_frag_write_PROC_INSTR(void *event, morph_ctx *mctx) { proc_instr_t *pi = event ; frag_write(mctx->frag_buf, "frag_buf, pi->target, strlen(pi->target)) ; frag_write(mctx->frag_buf, " ", 1) ; frag_write(mctx->frag_buf, pi->data, strlen(pi->data)) ; frag_write(mctx->frag_buf, "?>", 2) ; } /** * Writes a "not implemented" frag buffer. * @param ignored - The character element. * @param mctx - The context holding the frag_buffer. */ static void sax_event_frag_write_NOT_IMPL(void *ignored, morph_ctx *mctx) { frag_write(mctx->frag_buf, "[frag_write NOT IMPLEMENTED]", 28) ; } /** * Writes nothing. * @param ignored - The character element. * @param mctx - The context holding the frag_buffer. */ static void sax_event_frag_write_START_NS(void *event, morph_ctx *mctx) { start_ns_t *sn = event ; /* Push the ns event on the newns stack */ start_ns_t *psn = apr_array_push(mctx->newns) ; /* We copy the event. This way we do not have * to care about the bucket beeing destroyed. */ *psn = *sn; } /** * Writes nothing. * @param ignored - The character element. * @param mctx - The context holding the frag_buffer. */ static void sax_event_frag_write_NO_OP(void *ignored, morph_ctx *mctx) { } /** * Writes a sax bucket to a frag buffer. * @param sb - The sax bucket. * @param mctx - The context holding the buffer. */ static void sax_event_frag_write(bucket_sax *sb, morph_ctx *mctx) { frag_write_f frag_write = sb->frag_write ; frag_write(sb->event, mctx) ; } /* * sax_bucket_set_which */ void sax_bucket_set_which(bucket_sax *bs, sax_event_e which) { #define CASE_WHICH(x) case x: bs->frag_write= sax_event_frag_write_##x ; break ; bs->which = which ; switch (which) { CASE_WHICH(START_ELT) CASE_WHICH(END_ELT) CASE_WHICH(PROC_INSTR) CASE_WHICH(START_CD) CASE_WHICH(END_CD) CASE_WHICH(CHARACTER) // CASE_WHICH(WHITE) CASE_WHICH(COMMENT) CASE_WHICH(XML_DECL) CASE_WHICH(START_NS) case END_NS: bs->frag_write= sax_event_frag_write_NO_OP ; break ; case DEFAULT: bs->frag_write= sax_event_frag_write_CHARACTER ; break ; default: bs->frag_write= sax_event_frag_write_NOT_IMPL ; break; } } /***************************************************************************** * SAX bucket methods *****************************************************************************/ static void sax_bucket_destroy(void *data) { bucket_sax *bs = data ; if (apr_bucket_shared_destroy(data)) { bs->bctx->sum_mem -= sax_get_bucket_mem_size(bs) ; /* All create functions only allocate one block */ apr_bucket_free(data) ; } else { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, bs->bctx->r_log, "SAX bucket with %d bytes not destroyed.", sax_get_bucket_mem_size(bs)) ; } } /* * sax_bucket_read */ static apr_status_t sax_bucket_read(apr_bucket *e, const char **str, apr_size_t *len, apr_read_type_e block) { bucket_sax *bs = e->data ; frag_buffer_t *frag_buf = bs->mctx->frag_buf ; sax_event_debug_log(APLOG_MARK, bs, "sax_bucket_read called for type %s.", sax_event_which_to_str(bs->which)) ; if (bs->which == START_ELT) { start_elt_t *se = bs->event ; sax_event_debug_log(APLOG_MARK, bs, "start_elt has name %s.", se->name.name ) ; } if (bs->which == END_ELT) { end_elt_t *ee = bs->event ; sax_event_debug_log(APLOG_MARK, bs, "end_elt has name %s.", ee->name.name ) ; } if (bs->which == XML_DECL) { xml_decl_t *xd = bs->event ; sax_event_debug_log(APLOG_MARK, bs, "About to write xml_decl sax bucket with \"%s\", \"%s\", %d.", xd->version, xd->encoding, xd->standalone) ; } /* write the sax event to the frag buffer */ frag_clean(frag_buf) ; sax_event_frag_write(bs, bs->mctx) ; /* write the frag buffer to a linear buffer */ const apr_size_t len_loc = frag_length(frag_buf) ; char *buf_loc = apr_bucket_alloc(len_loc, e->list) ; frag_to_buffer(frag_buf, 0, buf_loc, len_loc) ; frag_clean(frag_buf) ; /* Put the linear buffer in the e bucket morphed to a heap bucket */ apr_bucket_heap_make(e, buf_loc, len_loc, apr_bucket_free); /* return the heap bucket buffer */ apr_bucket_heap *h = e->data ; *str = h->base + e->start; *len = e->length ; apr_pool_clear(bs->bctx->p_tmp) ; /* clean up the sax bucket */ sax_bucket_destroy(bs) ; return APR_SUCCESS; } APU_DECLARE_DATA const apr_bucket_type_t bucket_type_sax = { "SAX", 5, APR_BUCKET_DATA, sax_bucket_destroy, sax_bucket_read, apr_bucket_setaside_noop, apr_bucket_split_notimpl, apr_bucket_shared_copy };