Improve the XML formatting of responses coming from web interface.
authorLuigi Rizzo <rizzo@icir.org>
Tue, 17 Oct 2006 17:51:34 +0000 (17:51 +0000)
committerLuigi Rizzo <rizzo@icir.org>
Tue, 17 Oct 2006 17:51:34 +0000 (17:51 +0000)
Normal responses are sequences of lines of the form "Name: value",
with \r\n as line terminators and an empty line as a response
terminator.

Generi CLI commands, however, do not have such a clean formatting,
and the existing code failed to generate valid XML for them.
Obviously we can only use heuristics here, and we do the following:
- accept either \r or \n as a line terminator, trimming trailing whitespace;
- if a line does not have a ":" in it, assume that from this point on
  we have unformatted data, and use "Opaque-data:" as a name;
- if a line does have a ":" in it, the Name field is not always
  a legal identifier, so replace non-alphanum characters with underscores;

All the above is to be refined as we improve the formatting of
responses from the CLI.

And, all the above ought to go as a comment in the code rather than
just in a commit message...

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@45334 65c4cc65-6c06-0410-ace0-fbb531ad65f3

main/manager.c

index 85210cc..5e50d09 100644 (file)
@@ -296,7 +296,7 @@ static char *xml_translate(char *in, struct ast_variable *vars)
        int colons = 0;
        int breaks = 0;
        size_t len;
-       int count = 1;
+       int in_data = 0;        /* parsing data */
        int escaped = 0;
        int inobj = 0;
        int x;
@@ -311,6 +311,11 @@ static char *xml_translate(char *in, struct ast_variable *vars)
                dest = "unknown";
        if (!objtype)
                objtype = "generic";
+
+       /* determine how large is the response.
+        * This is a heuristic - counting colons (for headers),
+        * newlines (for extra arguments), and escaped chars.
+        */
        for (x = 0; in[x]; x++) {
                if (in[x] == ':')
                        colons++;
@@ -322,39 +327,52 @@ static char *xml_translate(char *in, struct ast_variable *vars)
        len = (size_t) (strlen(in) + colons * 5 + breaks * (40 + strlen(dest) + strlen(objtype)) + escaped * 10); /* foo="bar", "<response type=\"object\" id=\"dest\"", "&amp;" */
        out = ast_malloc(len);
        if (!out)
-               return 0;
+               return NULL;
        tmp = out;
-       while (*in) {
-               var = in;
-               while (*in && (*in >= 32))
-                       in++;
-               if (*in) {
-                       if ((count > 3) && inobj) {
-                               ast_build_string(&tmp, &len, " /></response>\n");
-                               inobj = 0;
+       /* we want to stop when we find an empty line */
+       while (in && *in) {
+               in = ast_skip_blanks(in);       /* trailing \n from before */
+               val = strsep(&in, "\r\n");      /* mark start and end of line */
+               ast_trim_blanks(val);
+               ast_verbose("inobj %d in_data %d line <%s>\n", inobj, in_data, val);
+               if (ast_strlen_zero(val)) {
+                       if (in_data) { /* close data */
+                               ast_build_string(&tmp, &len, "'");
+                               in_data = 0;
                        }
-                       count = 0;
-                       while (*in && (*in < 32)) {
-                               *in = '\0';
-                               in++;
-                               count++;
+                       ast_build_string(&tmp, &len, " /></response>\n");
+                       inobj = 0;
+                       continue;
+               }
+               /* we expect Name: value lines */
+               if (in_data) {
+                       var = NULL;
+               } else {
+                       var = strsep(&val, ":");
+                       if (val) {      /* found the field name */
+                               val = ast_skip_blanks(val);
+                               ast_trim_blanks(var);
+                       } else {                /* field name not found, move to opaque mode */
+                               val = var;
+                               var = "Opaque-data";
                        }
-                       val = strchr(var, ':');
-                       if (val) {
-                               *val = '\0';
-                               val++;
-                               if (*val == ' ')
-                                       val++;
-                               if (!inobj) {
-                                       ast_build_string(&tmp, &len, "<response type='object' id='%s'><%s", dest, objtype);
-                                       inobj = 1;
-                               }
-                               ast_build_string(&tmp, &len, " ");                              
-                               xml_copy_escape(&tmp, &len, var, 1);
-                               ast_build_string(&tmp, &len, "='");
-                               xml_copy_escape(&tmp, &len, val, 0);
+               }
+               if (!inobj) {
+                       ast_build_string(&tmp, &len, "<response type='object' id='%s'><%s", dest, objtype);
+                       inobj = 1;
+               }
+               if (!in_data) {
+                       ast_build_string(&tmp, &len, " ");                              
+                       xml_copy_escape(&tmp, &len, var, 1 | 2);
+                       ast_build_string(&tmp, &len, "='");
+                       xml_copy_escape(&tmp, &len, val, 0);
+                       if (!strcmp(var, "Opaque-data")) {
+                               in_data = 1;
+                       } else {
                                ast_build_string(&tmp, &len, "'");
                        }
+               } else {
+                       xml_copy_escape(&tmp, &len, val, 0);
                }
        }
        if (inobj)