gstein 01/02/18 04:30:42
Modified: include apr_xml.h
xml apr_xml.c
Log:
create the apr_xml_parser abstraction to handle XML parsing. this implements
the base functionality for the ap_xml_parse_input() function.
Revision Changes Path
1.9 +45 -11 apr-util/include/apr_xml.h
Index: apr_xml.h
===================================================================
RCS file: /home/cvs/apr-util/include/apr_xml.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -u -r1.8 -r1.9
--- apr_xml.h 2001/02/18 10:21:25 1.8
+++ apr_xml.h 2001/02/18 12:30:41 1.9
@@ -52,8 +52,8 @@
* <http://www.apache.org/>.
*/
-#ifndef UTIL_XML_H
-#define UTIL_XML_H
+#ifndef APR_XML_H
+#define APR_XML_H
#include "apr_pools.h"
#include "apr_tables.h"
@@ -234,16 +234,50 @@
apr_array_header_t *namespaces;
};
-#if 0
+
+typedef struct apr_xml_parser apr_xml_parser;
+
/**
- * Get XML post data and parse it
- * @param r The current request
- * @param pdoc The XML post data
- * @return HTTP status code
- * @deffunc int ap_xml_parse_input(request_rec *r, apr_xml_doc **pdoc)
+ * Create an XML parser
+ * @param pool The pool for allocating the parser and the parse results.
+ * @return The new parser.
*/
-APU_DECLARE(int) ap_xml_parse_input(request_rec *r, apr_xml_doc **pdoc);
-#endif
+APU_DECLARE(apr_xml_parser *) apr_xml_parser_create(apr_pool_t *pool);
+
+/**
+ * Feed input into the parser
+ * @param parser The XML parser for parsing this data.
+ * @param data The data to parse.
+ * @param len The length of the data.
+ * @return Any errors found during parsing.
+ * @tip Use apr_xml_parser_geterror() to get more error information.
+ */
+APU_DECLARE(apr_status_t) apr_xml_parser_feed(apr_xml_parser *parser,
+ const char *data,
+ apr_size_t len);
+
+/**
+ * Terminate the parsing and return the result
+ * @param parser The XML parser for parsing this data.
+ * @param pdoc The resulting parse information. May be NULL to simply
+ * terminate the parsing without fetching the info.
+ * @return Any errors found during the final stage of parsing.
+ * @tip Use apr_xml_parser_geterror() to get more error information.
+ */
+APU_DECLARE(apr_status_t) apr_xml_parser_done(apr_xml_parser *parser,
+ apr_xml_doc **pdoc);
+
+/**
+ * Fetch additional error information from the parser.
+ * @param parser The XML parser to query for errors.
+ * @param errbuf A buffer for storing error text.
+ * @param errbufsize The length of the error text buffer.
+ * @return The error buffer
+ */
+APU_DECLARE(char *) apr_xml_parser_geterror(apr_xml_parser *parser,
+ char *errbuf,
+ apr_size_t errbufsize);
+
/**
* Converts an XML element tree to flat text
@@ -320,4 +354,4 @@
}
#endif
-#endif /* UTIL_XML_H */
+#endif /* APR_XML_H */
1.17 +142 -146 apr-util/xml/apr_xml.c
Index: apr_xml.c
===================================================================
RCS file: /home/cvs/apr-util/xml/apr_xml.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -u -r1.16 -r1.17
--- apr_xml.c 2001/02/18 10:21:26 1.16
+++ apr_xml.c 2001/02/18 12:30:42 1.17
@@ -52,18 +52,13 @@
* <http://www.apache.org/>.
*/
-/*
-** DAV extension module for Apache 2.0.*
-** - XML parser for the body of a request
-*/
-
/* James Clark's Expat parser */
#include "xmlparse.h"
#include "apr.h"
#include "apr_strings.h"
-#define APR_WANT_STDIO /* for fprintf(), sprintf() */
+#define APR_WANT_STDIO /* for sprintf() */
#define APR_WANT_STRFUNC
#include "apr_want.h"
@@ -72,10 +67,8 @@
#define DEBUG_CR "\r\n"
-#define APR_XML_READ_BLOCKSIZE 2048 /* used for reading input
blocks */
-
/* errors related to namespace processing */
-#define APR_XML_NS_ERROR_UNKNOWN_PREFIX (APR_XML_NS_ERROR_BASE)
+#define APR_XML_NS_ERROR_UNKNOWN_PREFIX (-1000)
/* test for a namespace prefix that begins with [Xx][Mm][Ll] */
#define APR_XML_NS_IS_RESERVED(name) \
@@ -84,18 +77,21 @@
(name[2] == 'L' || name[2] == 'l') )
-/* content for parsing */
-typedef struct apr_xml_ctx {
+/* the real (internal) definition of the parser context */
+struct apr_xml_parser {
apr_xml_doc *doc; /* the doc we're parsing */
apr_pool_t *p; /* the pool we allocate from */
apr_xml_elem *cur_elem; /* current element */
int error; /* an error has occurred */
- /* errors may be APR_XML_NS_ERROR_* or other private errors which will
- be defined here (none yet) */
+#define APR_XML_ERROR_EXPAT 1
+#define APR_XML_ERROR_PARSE_DONE 2
+/* also: public APR_XML_NS_ERROR_* values (if any) */
+
+ XML_Parser xp; /* the actual (Expat) XML parser */
+ enum XML_Error xp_err; /* stored Expat error code */
+};
-} apr_xml_ctx;
-
/* struct for scoping namespace declarations */
typedef struct apr_xml_ns_scope {
const char *prefix; /* prefix used for this ns */
@@ -106,9 +102,9 @@
/* return namespace table index for a given prefix */
-static int find_prefix(apr_xml_ctx *ctx, const char *prefix)
+static int find_prefix(apr_xml_parser *parser, const char *prefix)
{
- apr_xml_elem *elem = ctx->cur_elem;
+ apr_xml_elem *elem = parser->cur_elem;
/*
** Walk up the tree, looking for a namespace scope that defines this
@@ -151,7 +147,7 @@
static void start_handler(void *userdata, const char *name, const char
**attrs)
{
- apr_xml_ctx *ctx = userdata;
+ apr_xml_parser *parser = userdata;
apr_xml_elem *elem;
apr_xml_attr *attr;
apr_xml_attr *prev;
@@ -160,31 +156,31 @@
char *elem_name;
/* punt once we find an error */
- if (ctx->error)
+ if (parser->error)
return;
- elem = apr_pcalloc(ctx->p, sizeof(*elem));
+ elem = apr_pcalloc(parser->p, sizeof(*elem));
/* prep the element */
- elem->name = elem_name = apr_pstrdup(ctx->p, name);
+ elem->name = elem_name = apr_pstrdup(parser->p, name);
/* fill in the attributes (note: ends up in reverse order) */
while (*attrs) {
- attr = apr_palloc(ctx->p, sizeof(*attr));
- attr->name = apr_pstrdup(ctx->p, *attrs++);
- attr->value = apr_pstrdup(ctx->p, *attrs++);
+ attr = apr_palloc(parser->p, sizeof(*attr));
+ attr->name = apr_pstrdup(parser->p, *attrs++);
+ attr->value = apr_pstrdup(parser->p, *attrs++);
attr->next = elem->attr;
elem->attr = attr;
}
/* hook the element into the tree */
- if (ctx->cur_elem == NULL) {
+ if (parser->cur_elem == NULL) {
/* no current element; this also becomes the root */
- ctx->cur_elem = ctx->doc->root = elem;
+ parser->cur_elem = parser->doc->root = elem;
}
else {
/* this element appeared within the current elem */
- elem->parent = ctx->cur_elem;
+ elem->parent = parser->cur_elem;
/* set up the child/sibling links */
if (elem->parent->last_child == NULL) {
@@ -198,7 +194,7 @@
}
/* this element is now the current element */
- ctx->cur_elem = elem;
+ parser->cur_elem = elem;
}
/* scan the attributes for namespace declarations */
@@ -219,12 +215,12 @@
}
/* quote the URI before we ever start working with it */
- quoted = apr_xml_quote_string(ctx->p, attr->value, 1);
+ quoted = apr_xml_quote_string(parser->p, attr->value, 1);
/* build and insert the new scope */
- ns_scope = apr_pcalloc(ctx->p, sizeof(*ns_scope));
+ ns_scope = apr_pcalloc(parser->p, sizeof(*ns_scope));
ns_scope->prefix = prefix;
- ns_scope->ns = apr_xml_insert_uri(ctx->doc->namespaces, quoted);
+ ns_scope->ns = apr_xml_insert_uri(parser->doc->namespaces, quoted);
ns_scope->emptyURI = *quoted == '\0';
ns_scope->next = elem->ns_scope;
elem->ns_scope = ns_scope;
@@ -239,7 +235,7 @@
}
else if (strcmp(attr->name, "xml:lang") == 0) {
/* save away the language (in quoted form) */
- elem->lang = apr_xml_quote_string(ctx->p, attr->value, 1);
+ elem->lang = apr_xml_quote_string(parser->p, attr->value, 1);
/* remove this attribute from the element */
if (prev == NULL)
@@ -272,18 +268,18 @@
* be found. Either it will be "no namespace", or a default
* namespace URI has been specified at some point.
*/
- elem->ns = find_prefix(ctx, "");
+ elem->ns = find_prefix(parser, "");
}
else if (APR_XML_NS_IS_RESERVED(elem->name)) {
elem->ns = APR_XML_NS_NONE;
}
else {
*colon = '\0';
- elem->ns = find_prefix(ctx, elem->name);
+ elem->ns = find_prefix(parser, elem->name);
elem->name = colon + 1;
if (APR_XML_NS_IS_ERROR(elem->ns)) {
- ctx->error = elem->ns;
+ parser->error = elem->ns;
return;
}
}
@@ -310,11 +306,11 @@
}
else {
*colon = '\0';
- attr->ns = find_prefix(ctx, attr->name);
+ attr->ns = find_prefix(parser, attr->name);
attr->name = colon + 1;
if (APR_XML_NS_IS_ERROR(attr->ns)) {
- ctx->error = attr->ns;
+ parser->error = attr->ns;
return;
}
}
@@ -323,29 +319,29 @@
static void end_handler(void *userdata, const char *name)
{
- apr_xml_ctx *ctx = userdata;
+ apr_xml_parser *parser = userdata;
/* punt once we find an error */
- if (ctx->error)
+ if (parser->error)
return;
/* pop up one level */
- ctx->cur_elem = ctx->cur_elem->parent;
+ parser->cur_elem = parser->cur_elem->parent;
}
static void cdata_handler(void *userdata, const char *data, int len)
{
- apr_xml_ctx *ctx = userdata;
+ apr_xml_parser *parser = userdata;
apr_xml_elem *elem;
apr_text_header *hdr;
const char *s;
/* punt once we find an error */
- if (ctx->error)
+ if (parser->error)
return;
- elem = ctx->cur_elem;
- s = apr_pstrndup(ctx->p, data, len);
+ elem = parser->cur_elem;
+ s = apr_pstrndup(parser->p, data, len);
if (elem->last_child == NULL) {
/* no children yet. this cdata follows the start tag */
@@ -356,128 +352,128 @@
hdr = &elem->last_child->following_cdata;
}
- apr_text_append(ctx->p, hdr, s);
+ apr_text_append(parser->p, hdr, s);
}
+static apr_status_t cleanup_parser(void *ctx)
+{
+ apr_xml_parser *parser = ctx;
+
+ XML_ParserFree(parser->xp);
+ parser->xp = NULL;
-#if 0
+ return APR_SUCCESS;
+}
-APU_DECLARE(int) apr_xml_parse_input(request_rec * r, apr_xml_doc **pdoc)
+APU_DECLARE(apr_xml_parser *) apr_xml_parser_create(apr_pool_t *pool)
{
- int result;
- apr_xml_ctx ctx = { 0 };
- XML_Parser parser;
-
- if ((result = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != OK)
- return result;
-
- if (r->remaining == 0) {
- *pdoc = NULL;
- return OK;
- }
-
- ctx.p = r->pool;
- ctx.doc = apr_pcalloc(ctx.p, sizeof(*ctx.doc));
-
- ctx.doc->namespaces = apr_array_make(ctx.p, 5, sizeof(const char *));
- apr_xml_insert_uri(ctx.doc->namespaces, "DAV:");
-
- /* ### we should get the encoding from Content-Encoding */
- parser = XML_ParserCreate(NULL);
- if (parser == NULL) {
- /* ### anything better to do? */
- fprintf(stderr, "Ouch! XML_ParserCreate() failed!\n");
- exit(1);
- }
-
- XML_SetUserData(parser, (void *) &ctx);
- XML_SetElementHandler(parser, start_handler, end_handler);
- XML_SetCharacterDataHandler(parser, cdata_handler);
-
- if (ap_should_client_block(r)) {
- long len;
- char *buffer;
- char end;
- int rv;
- apr_size_t total_read = 0;
- apr_size_t limit_xml_body = ap_get_limit_xml_body(r);
-
- /* allocate our working buffer */
- buffer = apr_palloc(r->pool, APR_XML_READ_BLOCKSIZE);
-
- /* read the body, stuffing it into the parser */
- while ((len = ap_get_client_block(r, buffer, APR_XML_READ_BLOCKSIZE)) >
0) {
- total_read += len;
- if (limit_xml_body && total_read > limit_xml_body) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
- "XML request body is larger than the configured "
- "limit of %lu", (unsigned long)limit_xml_body);
- goto read_error;
- }
+ apr_xml_parser *parser = apr_pcalloc(pool, sizeof(*parser));
- rv = XML_Parse(parser, buffer, len, 0);
- if (rv == 0)
- goto parser_error;
- }
- if (len == -1) {
- /* ap_get_client_block() has logged an error */
- goto read_error;
- }
+ parser->p = pool;
+ parser->doc = apr_pcalloc(pool, sizeof(*parser->doc));
- /* tell the parser that we're done */
- rv = XML_Parse(parser, &end, 0, 1);
- if (rv == 0)
- goto parser_error;
- }
-
- XML_ParserFree(parser);
-
- if (ctx.error) {
- switch (ctx.error) {
- case APR_XML_NS_ERROR_UNKNOWN_PREFIX:
- ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
- "An undefined namespace prefix was used.");
- break;
-
- default:
- ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
- "There was an error within the XML request body.");
- break;
- }
+ parser->doc->namespaces = apr_array_make(pool, 5, sizeof(const char *));
- /* Apache will supply a default error, plus the error log above. */
- return HTTP_BAD_REQUEST;
+ /* ### is there a way to avoid hard-coding this? */
+ apr_xml_insert_uri(parser->doc->namespaces, "DAV:");
+
+ parser->xp = XML_ParserCreate(NULL);
+ if (parser->xp == NULL) {
+ (void) (*pool->apr_abort)(APR_ENOMEM);
+ return NULL;
}
- /* ### assert: ctx.cur_elem == NULL */
+ apr_pool_cleanup_register(pool, parser, cleanup_parser,
+ apr_pool_cleanup_null);
- *pdoc = ctx.doc;
+ XML_SetUserData(parser->xp, parser);
+ XML_SetElementHandler(parser->xp, start_handler, end_handler);
+ XML_SetCharacterDataHandler(parser->xp, cdata_handler);
- return OK;
+ return parser;
+}
- parser_error:
- {
- enum XML_Error err = XML_GetErrorCode(parser);
+static apr_status_t do_parse(apr_xml_parser *parser,
+ const char *data, apr_size_t len,
+ int is_final)
+{
+ if (parser->xp == NULL) {
+ parser->error = APR_XML_ERROR_PARSE_DONE;
+ }
+ else {
+ int rv = XML_Parse(parser->xp, data, len, is_final);
- /* ### fix this error message (default vs special) */
- ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
- "XML parser error code: %s (%d).",
- XML_ErrorString(err), err);
+ if (rv == 0) {
+ parser->error = APR_XML_ERROR_EXPAT;
+ parser->xp_err = XML_GetErrorCode(parser->xp);
+ }
+ }
- XML_ParserFree(parser);
+ /* ### better error code? */
+ return parser->error ? APR_EGENERAL : APR_SUCCESS;
+}
- /* Apache will supply a default error, plus the error log above. */
- return HTTP_BAD_REQUEST;
- }
+APU_DECLARE(apr_status_t) apr_xml_parser_feed(apr_xml_parser *parser,
+ const char *data,
+ apr_size_t len)
+{
+ return do_parse(parser, data, len, 0 /* is_final */);
+}
+
+APU_DECLARE(apr_status_t) apr_xml_parser_done(apr_xml_parser *parser,
+ apr_xml_doc **pdoc)
+{
+ char end;
+ apr_status_t status = do_parse(parser, &end, 0, 1 /* is_final */);
- read_error:
- XML_ParserFree(parser);
+ /* get rid of the parser */
+ (void) apr_pool_cleanup_run(parser->p, parser, cleanup_parser);
- /* Apache will supply a default error, plus whatever was logged. */
- return HTTP_BAD_REQUEST;
+ if (status)
+ return status;
+
+ if (pdoc != NULL)
+ *pdoc = parser->doc;
+ return APR_SUCCESS;
}
+
+APU_DECLARE(char *) apr_xml_parser_geterror(apr_xml_parser *parser,
+ char *errbuf,
+ apr_size_t errbufsize)
+{
+ int error = parser->error;
+ const char *msg;
+
+ /* clear our record of an error */
+ parser->error = 0;
-#endif /* 0 */
+ switch (error) {
+ case 0:
+ msg = "No error.";
+ break;
+
+ case APR_XML_NS_ERROR_UNKNOWN_PREFIX:
+ msg = "An undefined namespace prefix was used.";
+ break;
+
+ case APR_XML_ERROR_EXPAT:
+ (void) apr_snprintf(errbuf, errbufsize,
+ "XML parser error code: %s (%d)",
+ XML_ErrorString(parser->xp_err), parser->xp_err);
+ return errbuf;
+
+ case APR_XML_ERROR_PARSE_DONE:
+ msg = "The parser is not active.";
+ break;
+
+ default:
+ msg = "There was an unknown error within the XML body.";
+ break;
+ }
+
+ (void) apr_cpystrn(errbuf, msg, errbufsize);
+ return errbuf;
+}
APU_DECLARE(void) apr_text_append(apr_pool_t * p, apr_text_header *hdr,