Merge pull request #32 from ittner/fix-xml-escaping
Fix escaping of XML text and attributes
This commit is contained in:
71
src/stanza.c
71
src/stanza.c
@@ -206,6 +206,64 @@ int xmpp_stanza_is_tag(xmpp_stanza_t * const stanza)
|
|||||||
return (stanza && stanza->type == XMPP_STANZA_TAG);
|
return (stanza && stanza->type == XMPP_STANZA_TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Escape a string with for use in a XML text node or attribute. Assumes that
|
||||||
|
* the input string is encoded in UTF-8. On sucess, returns a pointer to a
|
||||||
|
* buffer with the resulting data which must be xmpp_free()'d by the caller.
|
||||||
|
* On failure, returns NULL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static char *_escape_xml(xmpp_ctx_t * const ctx, char *text)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
char *src;
|
||||||
|
char *dst;
|
||||||
|
char *buf;
|
||||||
|
for (src = text; *src != '\0'; src++) {
|
||||||
|
switch (*src) {
|
||||||
|
case '<': /* "<" */
|
||||||
|
case '>': /* ">" */
|
||||||
|
len += 4;
|
||||||
|
break;
|
||||||
|
case '&': /* "&" */
|
||||||
|
len += 5;
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
len += 6; /*""" */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((buf = xmpp_alloc(ctx, (len+1) * sizeof(char))) == NULL)
|
||||||
|
return NULL; /* Error */
|
||||||
|
dst = buf;
|
||||||
|
for (src = text; *src != '\0'; src++) {
|
||||||
|
switch (*src) {
|
||||||
|
case '<':
|
||||||
|
strcpy(dst, "<");
|
||||||
|
dst += 4;
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
strcpy(dst, ">");
|
||||||
|
dst += 4;
|
||||||
|
break;
|
||||||
|
case '&':
|
||||||
|
strcpy(dst, "&");
|
||||||
|
dst += 5;
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
strcpy(dst, """);
|
||||||
|
dst += 6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*dst = *src;
|
||||||
|
dst++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*dst = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
/* small helper function */
|
/* small helper function */
|
||||||
static inline void _render_update(int *written, const int length,
|
static inline void _render_update(int *written, const int length,
|
||||||
const int lastwrite,
|
const int lastwrite,
|
||||||
@@ -236,6 +294,7 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
|||||||
xmpp_stanza_t *child;
|
xmpp_stanza_t *child;
|
||||||
hash_iterator_t *iter;
|
hash_iterator_t *iter;
|
||||||
const char *key;
|
const char *key;
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
written = 0;
|
written = 0;
|
||||||
|
|
||||||
@@ -244,7 +303,10 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
|||||||
if (stanza->type == XMPP_STANZA_TEXT) {
|
if (stanza->type == XMPP_STANZA_TEXT) {
|
||||||
if (!stanza->data) return XMPP_EINVOP;
|
if (!stanza->data) return XMPP_EINVOP;
|
||||||
|
|
||||||
ret = xmpp_snprintf(ptr, left, "%s", stanza->data);
|
tmp = _escape_xml(stanza->ctx, stanza->data);
|
||||||
|
if (tmp == NULL) return XMPP_EMEM;
|
||||||
|
ret = xmpp_snprintf(ptr, left, "%s", tmp);
|
||||||
|
xmpp_free(stanza->ctx, tmp);
|
||||||
if (ret < 0) return XMPP_EMEM;
|
if (ret < 0) return XMPP_EMEM;
|
||||||
_render_update(&written, buflen, ret, &left, &ptr);
|
_render_update(&written, buflen, ret, &left, &ptr);
|
||||||
} else { /* stanza->type == XMPP_STANZA_TAG */
|
} else { /* stanza->type == XMPP_STANZA_TAG */
|
||||||
@@ -258,8 +320,11 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
|
|||||||
if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) {
|
if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) {
|
||||||
iter = hash_iter_new(stanza->attributes);
|
iter = hash_iter_new(stanza->attributes);
|
||||||
while ((key = hash_iter_next(iter))) {
|
while ((key = hash_iter_next(iter))) {
|
||||||
ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key,
|
tmp = _escape_xml(stanza->ctx,
|
||||||
(char *)hash_get(stanza->attributes, key));
|
(char *)hash_get(stanza->attributes, key));
|
||||||
|
if (tmp == NULL) return XMPP_EMEM;
|
||||||
|
ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key, tmp);
|
||||||
|
xmpp_free(stanza->ctx, tmp);
|
||||||
if (ret < 0) return XMPP_EMEM;
|
if (ret < 0) return XMPP_EMEM;
|
||||||
_render_update(&written, buflen, ret, &left, &ptr);
|
_render_update(&written, buflen, ret, &left, &ptr);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user