joes 2004/09/10 16:54:08
Modified: . CHANGES STATUS
src apreq_params.h apreq_parsers.c
t parsers.c
Log:
Add multipart/related support to mfd parser, completing basic XForms support.
Reimplement the apr_xml parser as a hook + a generic parser.
Revision Changes Path
1.66 +6 -2 httpd-apreq-2/CHANGES
Index: CHANGES
===================================================================
RCS file: /home/cvs/httpd-apreq-2/CHANGES,v
retrieving revision 1.65
retrieving revision 1.66
diff -u -r1.65 -r1.66
--- CHANGES 6 Sep 2004 21:21:06 -0000 1.65
+++ CHANGES 10 Sep 2004 23:54:08 -0000 1.66
@@ -6,9 +6,13 @@
- C API [joes]
- Add apreq_parse_xml parser, which is a simple wrapper
- around APR's expat-based apr_xml_parser.
+ Support XForms' "multipart/related" enctype.
+- C API [joes]
+ Add apreq_hook_apr_xml_parser(), which is a simple wrapper
+ hook around APR's expat-based apr_xml_parser. Add a generic
+ parser apreq_parse_generic() to parse arbitrary enctypes using
+ the hook API.
@section v2_04_dev Changes with libapreq2-2.04-dev (released August 30, 2004)
1.83 +1 -3 httpd-apreq-2/STATUS
Index: STATUS
===================================================================
RCS file: /home/cvs/httpd-apreq-2/STATUS,v
retrieving revision 1.82
retrieving revision 1.83
diff -u -r1.82 -r1.83
--- STATUS 30 Aug 2004 16:25:56 -0000 1.82
+++ STATUS 10 Sep 2004 23:54:08 -0000 1.83
@@ -62,8 +62,6 @@
- Write parser/hook API documentation, and add perl glue for the API.
- - Add XForms logic to the mfd parser.
-
- symbol exports files:
-# aix needs .exp files
1.39 +17 -11 httpd-apreq-2/src/apreq_params.h
Index: apreq_params.h
===================================================================
RCS file: /home/cvs/httpd-apreq-2/src/apreq_params.h,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -r1.38 -r1.39
--- apreq_params.h 6 Sep 2004 21:21:06 -0000 1.38
+++ apreq_params.h 10 Sep 2004 23:54:08 -0000 1.39
@@ -320,25 +320,31 @@
APREQ_DECLARE_PARSER(apreq_parse_urlencoded);
/**
- * Rfc2388 multipart/form-data parser. It will reject
- * any buckets representing preamble and postamble text
- * (this is normal behavior, not an error condition).
+ * Rfc2388 multipart/form-data (and XForms 1.0 multipart/related)
+ * parser. It will reject any buckets representing preamble and
+ * postamble text (this is normal behavior, not an error condition).
* See #APREQ_RUN_PARSER for more info on rejected data.
*/
APREQ_DECLARE_PARSER(apreq_parse_multipart);
-
+/**
+ * Generic parser. No table entries will be added to
+ * the req->body table by this parser. The parser creates
+ * a dummy apreq_param_t to pass to any configured hooks. If
+ * no hooks are configured, the dummy param's bb slot will
+ * contain a copy of the request body. It can be retrieved
+ * by casting the parser's ctx pointer to (apreq_param_t **).
+ */
+APREQ_DECLARE_PARSER(apreq_parse_generic);
/**
- * application/xml expat-based parser. It will reject
- * metabuckets, and it will parse until EOS appears.
+ * apr_xml_parser hook. It will parse until EOS appears.
* The parsed document isn't available until parsing has
- * completed successfully. The parser's ctx pointer may
- * be cast as (const apr_xml_doc **) to retrieve the
- * parsed document. No table entries will be added to
- * req->body by this parser.
+ * completed successfully. The hook's ctx pointer may
+ * be cast as (apr_xml_doc **) to retrieve the
+ * parsed document.
*/
-APREQ_DECLARE_PARSER(apreq_parse_xml);
+APREQ_DECLARE_HOOK(apreq_hook_apr_xml_parser);
/**
* Construct a parser.
1.63 +95 -28 httpd-apreq-2/src/apreq_parsers.c
Index: apreq_parsers.c
===================================================================
RCS file: /home/cvs/httpd-apreq-2/src/apreq_parsers.c,v
retrieving revision 1.62
retrieving revision 1.63
diff -u -r1.62 -r1.63
--- apreq_parsers.c 6 Sep 2004 21:21:06 -0000 1.62
+++ apreq_parsers.c 10 Sep 2004 23:54:08 -0000 1.63
@@ -95,7 +95,9 @@
return apreq_make_parser(pool, type,
apreq_parse_urlencoded, hook, NULL);
- else if (!strncasecmp(type,APREQ_MFD_ENCTYPE,strlen(APREQ_MFD_ENCTYPE)))
+ else if (!strncasecmp(type,APREQ_MFD_ENCTYPE,strlen(APREQ_MFD_ENCTYPE))
+ || strncasecmp(type, "multipart/related",
+ strlen("multipart/related")))
return apreq_make_parser(pool, type,
apreq_parse_multipart, hook, NULL);
@@ -847,6 +849,7 @@
ctx->bb = apr_brigade_create(pool, bucket_alloc);
ctx->in = apr_brigade_create(pool, bucket_alloc);
ctx->eos = apr_bucket_eos_create(bucket_alloc);
+
}
else if (ctx->status == MFD_COMPLETE) {
apreq_log(APREQ_DEBUG APR_SUCCESS, env,
@@ -961,19 +964,28 @@
cd = apr_table_get(ctx->info, "Content-Disposition");
- if (cd == NULL) {
- ctx->status = MFD_ERROR;
- return APR_EGENERAL;
- }
+ if (cd != NULL) {
+ s = apreq_header_attribute(cd, "name", 4, &name, &nlen);
- s = apreq_header_attribute(cd, "name", 4, &name, &nlen);
+ if (s != APR_SUCCESS) {
+ ctx->status = MFD_ERROR;
+ return APR_EGENERAL;
+ }
- if (s != APR_SUCCESS) {
- ctx->status = MFD_ERROR;
- return APR_EGENERAL;
+ s = apreq_header_attribute(cd, "filename", 8, &filename,
&flen);
+ }
+ else {
+ cd = apr_table_get(ctx->info, "Content-ID");
+ if (cd == NULL) {
+ ctx->status = MFD_ERROR;
+ return APR_EGENERAL;
+ }
+ name = cd;
+ nlen = strlen(name);
+ filename = "";
+ flen = 0;
+ s = APR_SUCCESS;
}
-
- s = apreq_header_attribute(cd, "filename", 8, &filename, &flen);
if (s != APR_SUCCESS) {
name = apr_pstrmemdup(pool, name, nlen);
@@ -1110,7 +1122,71 @@
}
-/* XML parser */
+/* generic parser */
+
+struct gen_ctx {
+ apreq_param_t *param;
+ enum {
+ GEN_INCOMPLETE,
+ GEN_COMPLETE,
+ GEN_ERROR
+ } status;
+};
+
+
+APREQ_DECLARE_PARSER(apreq_parse_generic)
+{
+ struct gen_ctx *ctx = parser->ctx;
+ apr_pool_t *pool = apreq_env_pool(env);
+ apr_status_t s = APR_SUCCESS;
+ apr_bucket *e = APR_BRIGADE_LAST(bb);
+ unsigned saw_eos = 0;
+
+ if (ctx == NULL) {
+ parser->ctx = ctx = apr_palloc(pool, sizeof *ctx);
+ ctx->status = GEN_INCOMPLETE;
+ ctx->param = apreq_make_param(pool,
+ "_dummy_", strlen("_dummy_"), "", 0);
+ ctx->param->bb = apr_brigade_create(pool,
+ apr_bucket_alloc_create(pool));
+ ctx->param->info = apr_table_make(pool, APREQ_NELTS);
+ }
+
+
+ PARSER_STATUS_CHECK(GEN);
+
+ while (e != APR_BRIGADE_SENTINEL(bb)) {
+ if (APR_BUCKET_IS_EOS(e)) {
+ saw_eos = 1;
+ break;
+ }
+ e = APR_BUCKET_PREV(e);
+ }
+
+ if (parser->hook) {
+ s = APREQ_RUN_HOOK(parser->hook, env, ctx->param, bb);
+ if (s != APR_SUCCESS) {
+ ctx->status = GEN_ERROR;
+ return s;
+ }
+ }
+
+ APREQ_BRIGADE_SETASIDE(bb, pool);
+ s = apreq_brigade_concat(bb, ctx->param->bb, bb);
+
+ if (s != APR_SUCCESS) {
+ ctx->status = GEN_ERROR;
+ return s;
+ }
+
+ if (saw_eos) {
+ ctx->status = GEN_COMPLETE;
+ return APR_SUCCESS;
+ }
+ else
+ return APR_INCOMPLETE;
+}
+
struct xml_ctx {
apr_xml_doc *doc;
@@ -1123,24 +1199,24 @@
};
-APREQ_DECLARE_PARSER(apreq_parse_xml)
+APREQ_DECLARE_HOOK(apreq_hook_apr_xml_parser)
{
apr_pool_t *pool = apreq_env_pool(env);
- struct xml_ctx *ctx = parser->ctx;
+ struct xml_ctx *ctx = hook->ctx;
apr_status_t s = APR_SUCCESS;
- apr_bucket *e = APR_BRIGADE_FIRST(bb);
+ apr_bucket *e;
if (ctx == NULL) {
- parser->ctx = ctx = apr_palloc(pool, sizeof *ctx);
+ hook->ctx = ctx = apr_palloc(pool, sizeof *ctx);
ctx->doc = NULL;
ctx->xml_parser = apr_xml_parser_create(pool);
ctx->status = XML_INCOMPLETE;
}
-
PARSER_STATUS_CHECK(XML);
- while (e != APR_BRIGADE_SENTINEL(bb))
+ for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb);
+ e = APR_BUCKET_NEXT(e))
{
const char *data;
apr_size_t dlen;
@@ -1149,7 +1225,6 @@
s = apr_xml_parser_done(ctx->xml_parser, &ctx->doc);
if (s == APR_SUCCESS) {
ctx->status = XML_COMPLETE;
- apr_bucket_delete(e);
}
else {
ctx->status = XML_ERROR;
@@ -1159,7 +1234,6 @@
return s;
}
else if (APR_BUCKET_IS_METADATA(e)) {
- e = APR_BUCKET_NEXT(e);
continue;
}
@@ -1174,13 +1248,7 @@
s = apr_xml_parser_feed(ctx->xml_parser, data, dlen);
- if (s == APR_SUCCESS) {
- apr_bucket *f = e;
- e = APR_BUCKET_NEXT(e);
- apr_bucket_delete(f);
- continue;
- }
- else {
+ if (s != APR_SUCCESS) {
ctx->status = XML_ERROR;
apreq_log(APREQ_ERROR s, env, "apreq_parse_xml: "
"apr_xml_parser_feed failed");
@@ -1190,5 +1258,4 @@
}
return APR_INCOMPLETE;
-
}
1.22 +105 -11 httpd-apreq-2/t/parsers.c
Index: parsers.c
===================================================================
RCS file: /home/cvs/httpd-apreq-2/t/parsers.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -r1.21 -r1.22
--- parsers.c 6 Sep 2004 21:21:06 -0000 1.21
+++ parsers.c 10 Sep 2004 23:54:08 -0000 1.22
@@ -38,7 +38,7 @@
"--AaB03x--" CRLF;
static char xml_data[] =
-"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" /* length == 42 */
+"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>"
"<methodCall>"
" <methodName>foo.bar</methodName>"
" <params>"
@@ -46,6 +46,35 @@
" </params>"
"</methodCall>";
+static char rel_data[] = /*offsets: 122, 522, */
+"--f93dcbA3" CRLF
+"Content-Type: application/xml; charset=UTF-8" CRLF
+"Content-Length: 400" CRLF
+"Content-ID: <[EMAIL PROTECTED]>" CRLF CRLF /*122*/
+"<?xml version=\"1.0\"?>" CRLF
+"<uploadDocument>"
+" <title>My Proposal</title>"
+" <author>E. X. Ample</author>"
+" <summary>A proposal for a new project.</summary>"
+" <notes image=\"cid:[EMAIL PROTECTED]">(see handwritten region)</notes>"
+" <keywords>project proposal funding</keywords>"
+" <readonly>false</readonly>"
+" <filename>image.png</filename>"
+" <content>cid:[EMAIL PROTECTED]</content>"
+"</uploadDocument>" /*400*/ CRLF
+"--f93dcbA3" CRLF /*14*/
+"Content-Type: image/png" CRLF
+"Content-Transfer-Encoding: binary" CRLF
+"Content-ID: <[EMAIL PROTECTED]>" CRLF CRLF /*103*/
+"...Binary data here..." /*22*/ CRLF
+"--f93dcbA3" CRLF /*14*/
+"Content-Type: image/png" CRLF
+"Content-Transfer-Encoding: binary" CRLF
+"Content-ID: <[EMAIL PROTECTED]>" CRLF CRLF
+"...Binary data here..." CRLF
+"--f93dcbA3--" CRLF;
+
+
extern apr_bucket_brigade *bb;
extern apr_table_t *table;
@@ -201,13 +230,12 @@
CuAssertPtrEquals(tc, NULL, val);
}
-static void parse_xml(CuTest *tc)
+static void parse_generic(CuTest *tc)
{
const char *val;
apr_size_t vlen;
apr_status_t rv;
- int ns_map = 0;
- apr_xml_doc *doc;
+ apreq_param_t *dummy;
apreq_request_t *req = apreq_request(APREQ_XML_ENCTYPE, "");
apr_bucket_brigade *bb = apr_brigade_create(p,
apr_bucket_alloc_create(p));
@@ -221,25 +249,91 @@
req->body = NULL;
req->parser = apreq_make_parser(p, APREQ_XML_ENCTYPE,
- apreq_parse_xml, NULL, NULL);
+ apreq_parse_generic, NULL, NULL);
+ rv = apreq_parse_request(req,bb);
+ CuAssertIntEquals(tc, APR_SUCCESS, rv);
+ dummy = *(apreq_param_t **)req->parser->ctx;
+ CuAssertPtrNotNull(tc, dummy);
+ apr_brigade_pflatten(dummy->bb, (char **)&val, &vlen, p);
+
+ CuAssertIntEquals(tc, strlen(xml_data), vlen);
+ CuAssertStrNEquals(tc, xml_data, val, vlen);
+}
+
+
+static void parse_related(CuTest *tc)
+{
+ char ct[] = "multipart/related; boundary=f93dcbA3; "
+ "type=application/xml; start=\"<[EMAIL PROTECTED]>\"";
+ char data[] = "...Binary data here...";
+ int dlen = strlen(data);
+ const char *val;
+ apr_size_t vlen;
+ apr_status_t rv;
+ int ns_map = 0;
+ apr_xml_doc *doc;
+ apreq_hook_t *xml_hook;
+ apreq_param_t *param;
+ apreq_request_t *req = apreq_request(ct, "");
+ apr_bucket_brigade *bb = apr_brigade_create(p,
+ apr_bucket_alloc_create(p));
+ apr_bucket *e = apr_bucket_immortal_create(rel_data,
+ strlen(rel_data),
+ bb->bucket_alloc);
+
+ CuAssertPtrNotNull(tc, req);
+ APR_BRIGADE_INSERT_HEAD(bb, e);
+ APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_eos_create(bb->bucket_alloc));
+ xml_hook = apreq_make_hook(p, apreq_hook_apr_xml_parser, NULL, NULL);
+
+ req->body = NULL;
+ req->parser = apreq_make_parser(p, ct,
+ apreq_parse_multipart, xml_hook, NULL);
rv = apreq_parse_request(req,bb);
CuAssertIntEquals(tc, APR_SUCCESS, rv);
- doc = *(apr_xml_doc **)req->parser->ctx;
- CuAssertPtrNotNull(tc, doc);
- apr_xml_to_text(p, doc->root, APR_XML_X2T_FULL,
+ CuAssertPtrNotNull(tc, req->body);
+
+ param = apreq_param(req, "<[EMAIL PROTECTED]>");
+ CuAssertPtrNotNull(tc, param);
+ CuAssertPtrNotNull(tc, param->info);
+ val = apr_table_get(param->info, "Content-Length");
+ CuAssertStrEquals(tc, "400", val);
+ CuAssertPtrNotNull(tc, param->bb);
+ apr_brigade_pflatten(param->bb, (char **)&val, &vlen, p);
+ CuAssertIntEquals(tc, 400, vlen);
+ CuAssertStrNEquals(tc,rel_data + 122, val, 400);
+
+ doc = *(apr_xml_doc **)xml_hook->ctx;
+ apr_xml_to_text(p, doc->root, APR_XML_X2T_FULL,
doc->namespaces, &ns_map, &val, &vlen);
- CuAssertIntEquals(tc, strlen(xml_data), vlen + 42);
- CuAssertStrEquals(tc, xml_data + 43, val);
+ CuAssertIntEquals(tc, 400 - 22, vlen);
+ CuAssertStrNEquals(tc, rel_data + 122 + 23, val, 400 - 23);
+ param = apreq_param(req, "<[EMAIL PROTECTED]>");
+ CuAssertPtrNotNull(tc, param);
+ CuAssertPtrNotNull(tc, param->bb);
+ apr_brigade_pflatten(param->bb, (char **)&val, &vlen, p);
+ CuAssertIntEquals(tc, dlen, vlen);
+ CuAssertStrNEquals(tc, data, val, vlen);
+
+ param = apreq_param(req, "<[EMAIL PROTECTED]>");
+ CuAssertPtrNotNull(tc, param);
+ CuAssertPtrNotNull(tc, param->bb);
+ apr_brigade_pflatten(param->bb, (char **)&val, &vlen, p);
+ CuAssertIntEquals(tc, dlen, vlen);
+ CuAssertStrNEquals(tc, data, val, vlen);
}
+
+
CuSuite *testparser(void)
{
CuSuite *suite = CuSuiteNew("Parsers");
SUITE_ADD_TEST(suite, parse_urlencoded);
SUITE_ADD_TEST(suite, parse_multipart);
SUITE_ADD_TEST(suite, parse_disable_uploads);
- SUITE_ADD_TEST(suite, parse_xml);
+ SUITE_ADD_TEST(suite, parse_generic);
+ SUITE_ADD_TEST(suite, parse_related);
return suite;
}