Index: subversion/include/svn_xml.h =================================================================== --- subversion/include/svn_xml.h (revision 4679) +++ subversion/include/svn_xml.h (working copy) @@ -61,27 +61,53 @@ /** Create or append in @a *outstr an xml-escaped version of @a string. * * Create or append in @a *outstr an xml-escaped version of @a string, - * suitable for output as character data or as an attribute value. + * suitable for output as character data. * If @a *outstr is @c NULL, store a new stringbuf, else append to the * existing stringbuf there. */ -void svn_xml_escape_stringbuf (svn_stringbuf_t **outstr, - const svn_stringbuf_t *string, - apr_pool_t *pool); - -/** Same as @c svn_xml_escape_stringbuf, but @a string is an @c svn_string_t. - */ -void svn_xml_escape_string (svn_stringbuf_t **outstr, - const svn_string_t *string, - apr_pool_t *pool); - -/** Same as @c svn_xml_escape_stringbuf, but @a string is a null-terminated - * C string. - */ -void svn_xml_escape_cstring (svn_stringbuf_t **outstr, - const char *string, - apr_pool_t *pool); +void svn_xml_escape_cdata_stringbuf (svn_stringbuf_t **outstr, + const svn_stringbuf_t *string, + apr_pool_t *pool); + +/** Same as @c svn_xml_escape_cdata_stringbuf, but @a string is an + * @c svn_string_t. + */ +void svn_xml_escape_cdata_string (svn_stringbuf_t **outstr, + const svn_string_t *string, + apr_pool_t *pool); +/** Same as @c svn_xml_escape_cdata_stringbuf, but @a string is a + * null-terminated C string. + */ +void svn_xml_escape_cdata_cstring (svn_stringbuf_t **outstr, + const char *string, + apr_pool_t *pool); + + +/** Create or append in @a *outstr an xml-escaped version of @a string. + * + * Create or append in @a *outstr an xml-escaped version of @a string, + * suitable for output as an attribute value. + * If @a *outstr is @c NULL, store a new stringbuf, else append to the + * existing stringbuf there. + */ +void svn_xml_escape_attr_stringbuf (svn_stringbuf_t **outstr, + const svn_stringbuf_t *string, + apr_pool_t *pool); + +/** Same as @c svn_xml_escape_attr_stringbuf, but @a string is an + * @c svn_string_t. + */ +void svn_xml_escape_attr_string (svn_stringbuf_t **outstr, + const svn_string_t *string, + apr_pool_t *pool); + +/** Same as @c svn_xml_escape_attr_stringbuf, but @a string is a + * null-terminated C string. + */ +void svn_xml_escape_attr_cstring (svn_stringbuf_t **outstr, + const char *string, + apr_pool_t *pool); /*---------------------------------------------------------------*/ Index: subversion/libsvn_subr/xml.c =================================================================== --- subversion/libsvn_subr/xml.c (revision 4679) +++ subversion/libsvn_subr/xml.c (working copy) @@ -29,10 +29,10 @@ /*** XML escaping. ***/ static void -xml_escape (svn_stringbuf_t **outstr, - const char *data, - apr_size_t len, - apr_pool_t *pool) +xml_escape_cdata (svn_stringbuf_t **outstr, + const char *data, + apr_size_t len, + apr_pool_t *pool) { const char *end = data + len; const char *p = data, *q; @@ -47,8 +47,48 @@ quoted if it follows "]]", but it's easier to quote it all the time. */ q = p; + while (q < end && *q != '&' && *q != '<' && *q != '>') + q++; + svn_stringbuf_appendbytes (*outstr, p, q - p); + + /* We may already be a winner. */ + if (q == end) + break; + + /* Append the entity reference for the character. */ + if (*q == '&') + svn_stringbuf_appendcstr (*outstr, "&"); + else if (*q == '<') + svn_stringbuf_appendcstr (*outstr, "<"); + else if (*q == '>') + svn_stringbuf_appendcstr (*outstr, ">"); + + p = q + 1; + } +} + +/* Essentially the same as xml_escape_cdata, with the addition of + whitespace and quote characters. */ +static void +xml_escape_attr (svn_stringbuf_t **outstr, + const char *data, + apr_size_t len, + apr_pool_t *pool) +{ + const char *end = data + len; + const char *p = data, *q; + + if (*outstr == NULL) + *outstr = svn_stringbuf_create ("", pool); + + while (1) + { + /* Find a character which needs to be quoted and append bytes up + to that point. */ + q = p; while (q < end && *q != '&' && *q != '<' && *q != '>' - && *q != '"' && *q != '\'') + && *q != '"' && *q != '\'' && *q != '\r' + && *q != '\n' && *q != '\t') q++; svn_stringbuf_appendbytes (*outstr, p, q - p); @@ -67,6 +107,12 @@ svn_stringbuf_appendcstr (*outstr, """); else if (*q == '\'') svn_stringbuf_appendcstr (*outstr, "'"); + else if (*q == '\r') + svn_stringbuf_appendcstr (*outstr, " "); + else if (*q == '\n') + svn_stringbuf_appendcstr (*outstr, " "); + else if (*q == '\t') + svn_stringbuf_appendcstr (*outstr, " "); p = q + 1; } @@ -74,29 +120,56 @@ void -svn_xml_escape_stringbuf (svn_stringbuf_t **outstr, - const svn_stringbuf_t *string, - apr_pool_t *pool) +svn_xml_escape_cdata_stringbuf (svn_stringbuf_t **outstr, + const svn_stringbuf_t *string, + apr_pool_t *pool) +{ + xml_escape_cdata (outstr, string->data, string->len, pool); +} + + +void +svn_xml_escape_cdata_string (svn_stringbuf_t **outstr, + const svn_string_t *string, + apr_pool_t *pool) +{ + xml_escape_cdata (outstr, string->data, string->len, pool); +} + + +void +svn_xml_escape_cdata_cstring (svn_stringbuf_t **outstr, + const char *string, + apr_pool_t *pool) +{ + xml_escape_cdata (outstr, string, (apr_size_t) strlen (string), pool); +} + + +void +svn_xml_escape_attr_stringbuf (svn_stringbuf_t **outstr, + const svn_stringbuf_t *string, + apr_pool_t *pool) { - xml_escape (outstr, string->data, string->len, pool); + xml_escape_attr (outstr, string->data, string->len, pool); } void -svn_xml_escape_string (svn_stringbuf_t **outstr, - const svn_string_t *string, - apr_pool_t *pool) +svn_xml_escape_attr_string (svn_stringbuf_t **outstr, + const svn_string_t *string, + apr_pool_t *pool) { - xml_escape (outstr, string->data, string->len, pool); + xml_escape_attr (outstr, string->data, string->len, pool); } void -svn_xml_escape_cstring (svn_stringbuf_t **outstr, - const char *string, - apr_pool_t *pool) +svn_xml_escape_attr_cstring (svn_stringbuf_t **outstr, + const char *string, + apr_pool_t *pool) { - xml_escape (outstr, string, (apr_size_t) strlen (string), pool); + xml_escape_attr (outstr, string, (apr_size_t) strlen (string), pool); } @@ -339,7 +412,7 @@ svn_stringbuf_appendcstr (*str, "\n "); svn_stringbuf_appendcstr (*str, key); svn_stringbuf_appendcstr (*str, "=\""); - svn_xml_escape_cstring (str, val, pool); + svn_xml_escape_attr_cstring (str, val, pool); svn_stringbuf_appendcstr (*str, "\""); } Index: subversion/mod_dav_svn/deadprops.c =================================================================== --- subversion/mod_dav_svn/deadprops.c (revision 4679) +++ subversion/mod_dav_svn/deadprops.c (working copy) @@ -261,7 +261,7 @@ return NULL; /* XML-escape our properties before sending them across the wire. */ - svn_xml_escape_string(&xmlsafe, propval, db->resource->pool); + svn_xml_escape_cdata_string(&xmlsafe, propval, db->resource->pool); #ifdef SVN_DAV_FEATURE_USE_OLD_NAMESPACES if (strcmp(name->ns, SVN_PROP_CUSTOM_PREFIX) == 0) Index: subversion/clients/cmdline/log-cmd.c =================================================================== --- subversion/clients/cmdline/log-cmd.c (revision 4679) +++ subversion/clients/cmdline/log-cmd.c (working copy) @@ -345,7 +345,7 @@ /* xxx */ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "author", NULL); - svn_xml_escape_cstring (&sb, author, pool); + svn_xml_escape_cdata_cstring (&sb, author, pool); svn_xml_make_close_tag (&sb, pool, "author"); if (date == NULL) @@ -355,7 +355,7 @@ /* xxx */ svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "date", NULL); - svn_xml_escape_cstring (&sb, date, pool); + svn_xml_escape_cdata_cstring (&sb, date, pool); svn_xml_make_close_tag (&sb, pool, "date"); if (changed_paths) @@ -385,7 +385,8 @@ { /* copyfrom_path, pool); + svn_xml_escape_attr_cstring (&escpath, + log_item->copyfrom_path, pool); revstr = apr_psprintf (pool, "%" SVN_REVNUM_T_FMT, log_item->copyfrom_rev); svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, "path", @@ -400,7 +401,7 @@ "action", action, NULL); } /* xxx */ - svn_xml_escape_cstring (&sb, path, pool); + svn_xml_escape_cdata_cstring (&sb, path, pool); svn_xml_make_close_tag (&sb, pool, "path"); } @@ -419,7 +420,7 @@ NULL, /* no keywords */ FALSE, /* no expansion */ pool)); - svn_xml_escape_cstring (&sb, msg_native_eol, pool); + svn_xml_escape_cdata_cstring (&sb, msg_native_eol, pool); svn_xml_make_close_tag (&sb, pool, "msg"); /* */ Index: subversion/libsvn_ra_dav/commit.c =================================================================== --- subversion/libsvn_ra_dav/commit.c (revision 4679) +++ subversion/libsvn_ra_dav/commit.c (working copy) @@ -515,7 +515,7 @@ if (r->prop_changes == NULL) r->prop_changes = apr_table_make(pool, 5); - svn_xml_escape_string(&escaped, value, pool); + svn_xml_escape_cdata_string(&escaped, value, pool); apr_table_set(r->prop_changes, name, escaped->data); } else @@ -1257,7 +1257,7 @@ /* XML-Escape the log message. */ xml_data = NULL; /* Required by svn_xml_escape_*. */ - svn_xml_escape_cstring(&xml_data, log_msg, cc->ras->pool); + svn_xml_escape_cdata_cstring(&xml_data, log_msg, cc->ras->pool); po[0].name = &log_message_prop; po[0].type = ne_propset; Index: subversion/libsvn_ra_dav/fetch.c =================================================================== --- subversion/libsvn_ra_dav/fetch.c (revision 4679) +++ subversion/libsvn_ra_dav/fetch.c (working copy) @@ -2232,7 +2232,7 @@ const char *entry; svn_stringbuf_t *qpath = NULL; - svn_xml_escape_cstring (&qpath, path, pool); + svn_xml_escape_cdata_cstring (&qpath, path, pool); entry = apr_psprintf(pool, "%s" DEBUG_CR, @@ -2302,7 +2302,7 @@ const char *s; svn_stringbuf_t *qpath = NULL; - svn_xml_escape_cstring (&qpath, path, pool); + svn_xml_escape_cdata_cstring (&qpath, path, pool); s = apr_psprintf(pool, "%s" DEBUG_CR, qpath->data); @@ -2504,7 +2504,7 @@ if (dst_path) { svn_stringbuf_t *dst_path_str = NULL; - svn_xml_escape_cstring (&dst_path_str, dst_path, ras->pool); + svn_xml_escape_cdata_cstring (&dst_path_str, dst_path, ras->pool); s = apr_psprintf(ras->pool, "%s", dst_path_str->data);