AP_DECLARE(int) ap_xml_parse_input(request_rec * r, apr_xml_doc **pdoc) { apr_xml_parser *parser; apr_bucket_brigade *brigade; int seen_eos; apr_status_t status; char errbuf[200]; apr_size_t total_read = 0; apr_size_t limit_xml_body = ap_get_limit_xml_body(r); int result = HTTP_BAD_REQUEST; parser = apr_xml_parser_create(r->pool); brigade = apr_brigade_create(r->pool, r->connection->bucket_alloc); seen_eos = 0; total_read = 0; do { apr_bucket *bucket; /* read the body, stuffing it into the parser */ status = ap_get_brigade(r->input_filters, brigade, AP_MODE_READBYTES, APR_BLOCK_READ, READ_BLOCKSIZE); if (status != APR_SUCCESS) { goto read_error; } for (bucket = APR_BRIGADE_FIRST(brigade); bucket != APR_BRIGADE_SENTINEL(brigade); bucket = APR_BUCKET_NEXT(bucket)) { const char *data; apr_size_t len; if (APR_BUCKET_IS_EOS(bucket)) { seen_eos = 1; break; } if (APR_BUCKET_IS_METADATA(bucket)) { continue; } status = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ); if (status != APR_SUCCESS) { goto read_error; } total_read += len; if (limit_xml_body && total_read > limit_xml_body) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00539) "XML request body is larger than the configured " "limit of %lu", (unsigned long)limit_xml_body); result = HTTP_REQUEST_ENTITY_TOO_LARGE; goto read_error; } status = apr_xml_parser_feed(parser, data, len); if (status) { goto parser_error; } } apr_brigade_cleanup(brigade); } while (!seen_eos); apr_brigade_destroy(brigade); /* tell the parser that we're done */ status = apr_xml_parser_done(parser, pdoc); if (status) { /* Some parsers are stupid and return an error on blank documents. */ if (!total_read) { *pdoc = NULL; return OK; } ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00540) "XML parser error (at end). status=%d", status); return HTTP_BAD_REQUEST; } #if APR_CHARSET_EBCDIC apr_xml_parser_convert_doc(r->pool, *pdoc, ap_hdrs_from_ascii); #endif return OK; parser_error: (void) apr_xml_parser_geterror(parser, errbuf, sizeof(errbuf)); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00541) "XML Parser Error: %s", errbuf); /* FALLTHRU */ read_error: /* make sure the parser is terminated */ (void) apr_xml_parser_done(parser, NULL); apr_brigade_destroy(brigade); /* Apache will supply a default error, plus the error log above. */ return result; }
static apr_status_t merge_xml_in_filter(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { apr_status_t rv; request_rec *r = f->r; merge_ctx_t *ctx = f->ctx; apr_bucket *bucket; int seen_eos = 0; /* We shouldn't be added if we're not a MERGE/DELETE, but double check. */ if ((r->method_number != M_MERGE) && (r->method_number != M_DELETE)) { ap_remove_input_filter(f); return ap_get_brigade(f->next, bb, mode, block, readbytes); } if (!ctx) { f->ctx = ctx = apr_palloc(r->pool, sizeof(*ctx)); ctx->parser = apr_xml_parser_create(r->pool); ctx->bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); apr_pool_create(&ctx->pool, r->pool); } rv = ap_get_brigade(f->next, ctx->bb, mode, block, readbytes); if (rv != APR_SUCCESS) return rv; for (bucket = APR_BRIGADE_FIRST(ctx->bb); bucket != APR_BRIGADE_SENTINEL(ctx->bb); bucket = APR_BUCKET_NEXT(bucket)) { const char *data; apr_size_t len; if (APR_BUCKET_IS_EOS(bucket)) { seen_eos = 1; break; } if (APR_BUCKET_IS_METADATA(bucket)) continue; rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ); if (rv != APR_SUCCESS) return rv; rv = apr_xml_parser_feed(ctx->parser, data, len); if (rv != APR_SUCCESS) { /* Clean up the parser. */ (void) apr_xml_parser_done(ctx->parser, NULL); break; } } /* This will clear-out the ctx->bb as well. */ APR_BRIGADE_CONCAT(bb, ctx->bb); if (seen_eos) { apr_xml_doc *pdoc; /* Remove ourselves now. */ ap_remove_input_filter(f); /* tell the parser that we're done */ rv = apr_xml_parser_done(ctx->parser, &pdoc); if (rv == APR_SUCCESS) { #if APR_CHARSET_EBCDIC apr_xml_parser_convert_doc(r->pool, pdoc, ap_hdrs_from_ascii); #endif /* stash the doc away for mod_dav_svn's later use. */ rv = apr_pool_userdata_set(pdoc, "svn-request-body", NULL, r->pool); if (rv != APR_SUCCESS) return rv; } } return APR_SUCCESS; }