Module: sip-router Branch: master Commit: da2a085760f30c8b0afb72555871465e551f0060 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=da2a0857...
Author: Andrei Pelinescu-Onciul andrei@iptel.org Committer: Andrei Pelinescu-Onciul andrei@iptel.org Date: Wed Sep 23 14:12:50 2009 +0200
xmlrpc(s): option for replacing double lf with crlf
Added "double_lf_to_crlf" config parameter. When set double LFs in the input xmlrpc strings are replaced with CR LF. This is needed to work around some xmlrpc buggy clients that don't escape CR ('\r' should be escaped to 
 ). When using one of those buggy clients, use double LF as an escape for CR LF and turn this option on.Turning this option on makes it also more compatible with kamailio tools (kamailio mi xmlrpc always converts double LF to CR LF). Note that when double_lf_to_crlf is on it's not possible to send a double lf.
Here is what the xmlrpc modules sees for various combinations of CR and LF in the input, when CR is _not_ escaped: 0 1 (double_lf_to_crlf) \n -> \r \r \r -> \r \r \r\r -> \n\n \r\n \n\n -> \n\n \r\n \r\n -> \n !!! \n !!! \n\r -> \n\n \r\n
Note that when double_lf_to_crlf is 0, the xmlrpc module behaves correctly according to the xml specs.
---
modules_s/xmlrpc/xmlrpc.c | 37 ++++++++++++++++++++++++++++++------- 1 files changed, 30 insertions(+), 7 deletions(-)
diff --git a/modules_s/xmlrpc/xmlrpc.c b/modules_s/xmlrpc/xmlrpc.c index 34106bc..0823a20 100644 --- a/modules_s/xmlrpc/xmlrpc.c +++ b/modules_s/xmlrpc/xmlrpc.c @@ -394,6 +394,9 @@ static int xmlrpc_route_no=DEFAULT_RT; static int autoconvert=0; /* in replies, escape CR to 
 (according to the xml specs) */ static int escape_cr=1; /* default on */ +/* convert double LF to CR LF (when on, LFLF becomes an escape for CRLF, needed + with some xmlrpc clients that are not escaping CR to 
 )*/ +static int lflf2crlf=0; /* default off */
/* @@ -413,6 +416,7 @@ static param_export_t params[] = { {"route", PARAM_STRING, &xmlrpc_route}, {"autoconversion", PARAM_INT, &autoconvert}, {"escape_cr", PARAM_INT, &escape_cr}, + {"double_lf_to_crlf", PARAM_INT, &lflf2crlf}, {0, 0, 0} };
@@ -1080,6 +1084,7 @@ static time_t xmlrpc2time(const char* str) /* get_* flags: */ #define GET_X_AUTOCONV 1 #define GET_X_NOREPLY 2 +#define GET_X_LFLF2CRLF 4 /* replace "\n\n" with "\r\n" */
/* xml value types */ enum xmlrpc_val_type{ @@ -1294,14 +1299,16 @@ static int get_double(double* val, struct xmlrpc_reply* reply,
/** Convert a parameter encoded in XML-RPC to a zero terminated string. * - * @param val A pointer to an integer variable where the result will be - stored. + * @param val A pointer to a char* variable where the result will be + * stored (the result is dynamically allocated, but it's garbage + * collected, so it doesn't have to be freed) * @param reply A pointer to XML-RPC reply being constructed (used to indicate * conversion errors). * @param doc A pointer to the XML-RPC request document. * @param value A pointer to the element containing the parameter to be * converted within the document. * @param flags : GET_X_AUTOCONV - try autoconverting + * GET_X_LFLF2CRLF - replace double '\n' with `\r\n' * GET_X_NOREPLY - do not reply * @return <0 on error, 0 on success */ @@ -1360,6 +1367,18 @@ static int get_string(char** val, struct xmlrpc_reply* reply, ret=0; switch(type){ case XML_T_STR: + if (flags & GET_X_LFLF2CRLF){ + p=val_str; + while(*p){ + if (*p=='\n' && *(p+1)=='\n'){ + *p='\r'; + p+=2; + continue; + } + p++; + } + } + /* no break */ case XML_T_DATE: /* no special conversion */ case XML_T_DOUBLE: /* no special conversion */ if (add_garbage(JUNK_XMLCHAR, val_str, reply) < 0){ @@ -1428,7 +1447,8 @@ static int rpc_scan(rpc_ctx_t* ctx, char* fmt, ...) va_start(ap, fmt); modifiers=0; read = 0; - f=autoconvert?GET_X_AUTOCONV:0; + f=(autoconvert?GET_X_AUTOCONV:0) | + (lflf2crlf?GET_X_LFLF2CRLF:0); while(*fmt) { if (!ctx->act_param) goto error; value = ctx->act_param->xmlChildrenNode; @@ -1737,8 +1757,11 @@ static int rpc_struct_scan(struct rpc_struct* s, char* fmt, ...) char* member_name; struct xmlrpc_reply* reply; int ret; + int f;
read = 0; + f=(autoconvert?GET_X_AUTOCONV:0) | + (lflf2crlf?GET_X_LFLF2CRLF:0); va_start(ap, fmt); while(*fmt) { member_name = va_arg(ap, char*); @@ -1751,23 +1774,23 @@ static int rpc_struct_scan(struct rpc_struct* s, char* fmt, ...) case 't': /* Date and time */ case 'd': /* Integer */ int_ptr = va_arg(ap, int*); - if (get_int(int_ptr, reply, s->doc, value, 0) < 0) goto error; + if (get_int(int_ptr, reply, s->doc, value, f) < 0) goto error; break;
case 'f': /* double */ double_ptr = va_arg(ap, double*); - if (get_double(double_ptr, reply, s->doc, value, 0) < 0) + if (get_double(double_ptr, reply, s->doc, value, f) < 0) goto error; break;
case 's': /* zero terminated string */ char_ptr = va_arg(ap, char**); - if (get_string(char_ptr, reply, s->doc, value, 0) < 0) goto error; + if (get_string(char_ptr, reply, s->doc, value, f) < 0) goto error; break;
case 'S': /* str structure */ str_ptr = va_arg(ap, str*); - if (get_string(&str_ptr->s, reply, s->doc, value, 0) < 0) + if (get_string(&str_ptr->s, reply, s->doc, value, f) < 0) goto error; str_ptr->len = strlen(str_ptr->s); break;
Andrei Pelinescu-Onciul writes:
Added "double_lf_to_crlf" config parameter. When set double LFs in the input xmlrpc strings are replaced with CR LF. This is needed to work around some xmlrpc buggy clients that don't escape CR ('\r' should be escaped to 
 ). When using one of those buggy clients, use double LF as an escape for CR LF and turn this option on.Turning this option on makes it also more compatible with kamailio tools (kamailio mi xmlrpc always converts double LF to CR LF).
andrei,
that you very much for adding support for those "buggy clients". if the clients really are buggy is controversial. xmlrpc spec has this:
What characters are allowed in strings? Non-printable characters? Null characters? Can a "string" be used to hold an arbitrary chunk of binary data?
Any characters are allowed in a string except < and &, which are encoded as < and &. A string can be used to encode binary data.
many client vendors have interpreted this to mean that \r is a perfectly valid character in xmlrpc string and need not to be escaped.
-- juha
/* get_* flags: */ #define GET_X_AUTOCONV 1 #define GET_X_NOREPLY 2 +#define GET_X_LFLF2CRLF 4 /* replace "\n\n" with "\r\n" */
/* xml value types */ enum xmlrpc_val_type{ @@ -1294,14 +1299,16 @@ static int get_double(double* val, struct xmlrpc_reply* reply,
/** Convert a parameter encoded in XML-RPC to a zero terminated string.
- @param val A pointer to an integer variable where the result will be
stored.
- @param val A pointer to a char* variable where the result will be
stored (the result is dynamically allocated, but it's garbage
collected, so it doesn't have to be freed)
- @param reply A pointer to XML-RPC reply being constructed (used to indicate
conversion errors).
- @param doc A pointer to the XML-RPC request document.
- @param value A pointer to the element containing the parameter to be
converted within the document.
- @param flags : GET_X_AUTOCONV - try autoconverting
*/
GET_X_LFLF2CRLF - replace double '\n' with `\r\n'
GET_X_NOREPLY - do not reply
- @return <0 on error, 0 on success
@@ -1360,6 +1367,18 @@ static int get_string(char** val, struct xmlrpc_reply* reply, ret=0; switch(type){ case XML_T_STR:
if (flags & GET_X_LFLF2CRLF){
p=val_str;
while(*p){
if (*p=='\n' && *(p+1)=='\n'){
*p='\r';
p+=2;
continue;
}
p++;
}
}
case XML_T_DATE: /* no special conversion */ case XML_T_DOUBLE: /* no special conversion */ if (add_garbage(JUNK_XMLCHAR, val_str, reply) < 0){/* no break */
@@ -1428,7 +1447,8 @@ static int rpc_scan(rpc_ctx_t* ctx, char* fmt, ...) va_start(ap, fmt); modifiers=0; read = 0;
- f=autoconvert?GET_X_AUTOCONV:0;
- f=(autoconvert?GET_X_AUTOCONV:0) |
while(*fmt) { if (!ctx->act_param) goto error; value = ctx->act_param->xmlChildrenNode;(lflf2crlf?GET_X_LFLF2CRLF:0);
@@ -1737,8 +1757,11 @@ static int rpc_struct_scan(struct rpc_struct* s, char* fmt, ...) char* member_name; struct xmlrpc_reply* reply; int ret;
int f;
read = 0;
f=(autoconvert?GET_X_AUTOCONV:0) |
(lflf2crlf?GET_X_LFLF2CRLF:0);
va_start(ap, fmt); while(*fmt) { member_name = va_arg(ap, char*);
@@ -1751,23 +1774,23 @@ static int rpc_struct_scan(struct rpc_struct* s, char* fmt, ...) case 't': /* Date and time */ case 'd': /* Integer */ int_ptr = va_arg(ap, int*);
if (get_int(int_ptr, reply, s->doc, value, 0) < 0) goto error;
if (get_int(int_ptr, reply, s->doc, value, f) < 0) goto error; break;
case 'f': /* double */ double_ptr = va_arg(ap, double*);
if (get_double(double_ptr, reply, s->doc, value, 0) < 0)
if (get_double(double_ptr, reply, s->doc, value, f) < 0) goto error; break;
case 's': /* zero terminated string */ char_ptr = va_arg(ap, char**);
if (get_string(char_ptr, reply, s->doc, value, 0) < 0) goto error;
if (get_string(char_ptr, reply, s->doc, value, f) < 0) goto error; break;
case 'S': /* str structure */ str_ptr = va_arg(ap, str*);
if (get_string(&str_ptr->s, reply, s->doc, value, 0) < 0)
if (get_string(&str_ptr->s, reply, s->doc, value, f) < 0) goto error; str_ptr->len = strlen(str_ptr->s); break;
sr-dev mailing list sr-dev@lists.sip-router.org http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
On Sep 23, 2009 at 15:37, Juha Heinanen jh@tutpro.com wrote:
Andrei Pelinescu-Onciul writes:
Added "double_lf_to_crlf" config parameter. When set double LFs in the input xmlrpc strings are replaced with CR LF. This is needed to work around some xmlrpc buggy clients that don't escape CR ('\r' should be escaped to 
 ). When using one of those buggy clients, use double LF as an escape for CR LF and turn this option on.Turning this option on makes it also more compatible with kamailio tools (kamailio mi xmlrpc always converts double LF to CR LF).
andrei,
that you very much for adding support for those "buggy clients". if the clients really are buggy is controversial. xmlrpc spec has this:
What characters are allowed in strings? Non-printable characters? Null characters? Can a "string" be used to hold an arbitrary chunk of binary data?
Any characters are allowed in a string except < and &, which are encoded as < and &. A string can be used to encode binary data.
The xml spec has: http://www.w3.org/TR/REC-xml/#sec-line-ends : To simplify the tasks of applications, the XML processor MUST behave as if it normalized all line breaks in external parsed entities (including the document entity) on input, before parsing, by translating both the two-character sequence #xD #xA and any #xD that is not followed by #xA to a single #xA character.
Also in http://www.w3.org/TR/REC-xml/#sec-common-syn : [...] S ::= (#x20 | #x9 | #xD | #xA)+
Note:
The presence of #xD in the above production is maintained purely for backward compatibility with the First Edition. As explained in 2.11 End-of-Line Handling, all #xD characters literally present in an XML document are either removed or replaced by #xA characters before any other processing is done. The only way to get a #xD character to match this production is to use a character reference in an entity value literal.
many client vendors have interpreted this to mean that \r is a perfectly valid character in xmlrpc string and need not to be escaped.
It's valid, but if it's not escaped then it won't be seen, because of the normalizing line breaks requirement for xml parsers.
Andrei