This patch fixes an issue whereby a newline character appearing within
a hidden input field is incorrectly reinterpreted as a space character.
The patch handles almost all cases, and includes a test case.
15/18 tests pass, but the remainder currently fail due to the fact
that ELinks does not currently support textarea scripting.
---
 AUTHORS                          |    1 +
 src/document/html/parser/forms.c |    4 +-
 src/document/html/parser/parse.c |    6 +-
 src/document/html/parser/parse.h |    5 ++
 src/viewer/text/form.c           |   30 +++++++++
 src/viewer/text/form.h           |    1 +
 src/viewer/text/textarea.c       |   13 +----
 test/server/crlf.conf            |    2 +
 test/server/crlf.py              |  121 ++++++++++++++++++++++++++++++++++++++
 9 files changed, 168 insertions(+), 15 deletions(-)
 create mode 100644 test/server/crlf.conf
 create mode 100755 test/server/crlf.py

diff --git a/AUTHORS b/AUTHORS
index 866f0d7..18e8641 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -457,6 +457,7 @@ Peder Stray <[EMAIL PROTECTED]>
        Fix handling of key presses turning up as key prefixes
 
 Peter Collingbourne <[EMAIL PROTECTED]>
+       Fixed bug relating to newlines in hidden input fields
        Fixed compiler errors and warnings in src/util/random.c where 
CONFIG_SSL undefined
 
 Peter Gervai <[EMAIL PROTECTED]>
diff --git a/src/document/html/parser/forms.c b/src/document/html/parser/forms.c
index c34459a..5f9dc47 100644
--- a/src/document/html/parser/forms.c
+++ b/src/document/html/parser/forms.c
@@ -287,7 +287,9 @@ html_input(struct html_context *html_context, unsigned char 
*a,
                mem_free(al);
        }
 
-       if (fc->type != FC_FILE)
+       if (fc->type == FC_HIDDEN)
+               fc->default_value = get_lit_attr_val(a, "value", cp);
+       else if (fc->type != FC_FILE)
                fc->default_value = get_attr_val(a, "value", cp);
        if (!fc->default_value) {
                if (fc->type == FC_CHECKBOX)
diff --git a/src/document/html/parser/parse.c b/src/document/html/parser/parse.c
index 128485e..399c4e6 100644
--- a/src/document/html/parser/parse.c
+++ b/src/document/html/parser/parse.c
@@ -179,9 +179,11 @@ next_attr:
 
 /* parse_quoted_value: */
                        while (*(++e) != quote) {
-                               if (*e == ASCII_CR) continue;
                                if (!*e) goto parse_error;
-                               if (*e != ASCII_TAB && *e != ASCII_LF)
+                               if (flags & HTML_ATTR_LITERAL_NL)
+                                       add_chr(attr, attrlen, *e);
+                               else if (*e == ASCII_CR) continue;
+                               else if (*e != ASCII_TAB && *e != ASCII_LF)
                                        add_chr(attr, attrlen, *e);
                                else if (!(flags & HTML_ATTR_EAT_NL))
                                        add_chr(attr, attrlen, ' ');
diff --git a/src/document/html/parser/parse.h b/src/document/html/parser/parse.h
index 4eaa154..9498e43 100644
--- a/src/document/html/parser/parse.h
+++ b/src/document/html/parser/parse.h
@@ -25,6 +25,10 @@ enum html_attr_flags {
        /* If HTML_ATTR_NO_CONV is set, then convert_string() is not called
         * on value. Unused for now. */
        /* HTML_ATTR_NO_CONV = 4, */
+
+       /* If HTML_ATTR_LITERAL_NL is set, carriage return, newline and tab
+        * characters are returned literally. */
+       HTML_ATTR_LITERAL_NL = 8,
 };
 
 /* Parses html element attributes.
@@ -37,6 +41,7 @@ unsigned char *get_attr_value(register unsigned char *e, 
unsigned char *name, in
 
 /* Wrappers for get_attr_value(). */
 #define get_attr_val(e, name, cp) get_attr_value(e, name, cp, HTML_ATTR_NONE)
+#define get_lit_attr_val(e, name, cp) get_attr_value(e, name, cp, 
HTML_ATTR_LITERAL_NL)
 #define get_url_val(e, name, cp) get_attr_value(e, name, cp, HTML_ATTR_EAT_NL)
 #define has_attr(e, name, cp) (!!get_attr_value(e, name, cp, HTML_ATTR_TEST))
 
diff --git a/src/viewer/text/form.c b/src/viewer/text/form.c
index f2b7b9d..e64ae88 100644
--- a/src/viewer/text/form.c
+++ b/src/viewer/text/form.c
@@ -807,6 +807,30 @@ get_successful_controls(struct document_view *doc_view,
        sort_submitted_values(list);
 }
 
+unsigned char *
+encode_crlf(struct submitted_value *sv)
+{
+       struct string newtext;
+       int i;
+
+       assert(sv && sv->value);
+       if_assert_failed return NULL;
+
+       if (!init_string(&newtext)) return NULL;
+
+       for (i = 0; sv->value[i]; i++) {
+               if (sv->value[i] == '\r') {
+                       if (sv->value[i+1] != '\n')
+                               add_crlf_to_string(&newtext);
+               } else if (sv->value[i] == '\n')
+                       add_crlf_to_string(&newtext);
+               else
+                       add_char_to_string(&newtext, sv->value[i]);
+       }
+
+       return newtext.source;
+}
+
 static void
 encode_controls(LIST_OF(struct submitted_value) *l, struct string *data,
                int cp_from, int cp_to)
@@ -850,6 +874,8 @@ encode_controls(LIST_OF(struct submitted_value) *l, struct 
string *data,
 
                        p2 = convert_string(convert_table, sv->value,
                                            strlen(sv->value), -1, CSM_FORM, 
NULL, NULL, NULL);
+               } else if (sv->type == FC_HIDDEN) {
+                       p2 = encode_crlf(sv);
                } else {
                        p2 = stracpy(sv->value);
                }
@@ -1120,6 +1146,10 @@ encode_text_plain(LIST_OF(struct submitted_value) *l, 
struct string *data,
                        value = area51 = encode_textarea(sv);
                        if (!area51) break;
                        /* Fall through */
+               case FC_HIDDEN:
+                       if (!area51) value = area51 = encode_crlf(sv);
+                       if (!area51) break;
+                       /* Fall through */
                case FC_TEXT:
                case FC_PASSWORD:
                        /* Convert back to original encoding (see
diff --git a/src/viewer/text/form.h b/src/viewer/text/form.h
index 74a9991..79757ba 100644
--- a/src/viewer/text/form.h
+++ b/src/viewer/text/form.h
@@ -99,6 +99,7 @@ struct submitted_value {
 struct submitted_value *init_submitted_value(unsigned char *name, unsigned 
char *value, enum form_type type, struct form_control *fc, int position);
 void done_submitted_value(struct submitted_value *sv);
 void done_submitted_value_list(LIST_OF(struct submitted_value) *list);
+unsigned char *encode_crlf(struct submitted_value *sv);
 
 struct uri *get_form_uri(struct session *ses, struct document_view *doc_view, 
struct form_control *fc);
 
diff --git a/src/viewer/text/textarea.c b/src/viewer/text/textarea.c
index 60a0c60..7749f7b 100644
--- a/src/viewer/text/textarea.c
+++ b/src/viewer/text/textarea.c
@@ -488,9 +488,7 @@ unsigned char *
 encode_textarea(struct submitted_value *sv)
 {
        struct form_control *fc;
-       struct string newtext;
        void *blabla;
-       int i;
 
        assert(sv && sv->value);
        if_assert_failed return NULL;
@@ -503,16 +501,7 @@ encode_textarea(struct submitted_value *sv)
        blabla = format_text(sv->value, fc->cols, fc->wrap, 1);
        mem_free_if(blabla);
 
-       if (!init_string(&newtext)) return NULL;
-
-       for (i = 0; sv->value[i]; i++) {
-               if (sv->value[i] != '\n')
-                       add_char_to_string(&newtext, sv->value[i]);
-               else
-                       add_crlf_to_string(&newtext);
-       }
-
-       return newtext.source;
+       return encode_crlf(sv);
 }
 
 
diff --git a/test/server/crlf.conf b/test/server/crlf.conf
new file mode 100644
index 0000000..33d61a2
--- /dev/null
+++ b/test/server/crlf.conf
@@ -0,0 +1,2 @@
+set document.browse.forms.confirm_submit = 0
+set ecmascript.enable = 1
diff --git a/test/server/crlf.py b/test/server/crlf.py
new file mode 100755
index 0000000..84b49fd
--- /dev/null
+++ b/test/server/crlf.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+
+import os
+from BaseHTTPServer import *
+import tempfile
+import signal
+
+r, w = os.pipe()
+
+C_CR = 0
+C_LF = 1
+C_CRLF = 2
+
+E_Raw = 0
+E_Entity = 1
+E_JavaScript = 2
+
+F_Hidden = 0
+F_TextArea = 1
+
+def encode(ch, encoding):
+       if ch == C_CRLF:
+               return encode(C_CR, encoding) + encode(C_LF, encoding)
+       if ch == C_CR:
+               if encoding == E_Raw:
+                       return "\r"
+               if encoding == E_JavaScript:
+                       return "\\r"
+               if encoding == E_Entity:
+                       return "&#013;"
+       if ch == C_LF:
+               if encoding == E_Raw:
+                       return "\n"
+               if encoding == E_JavaScript:
+                       return "\\n"
+               if encoding == E_Entity:
+                       return "&#010;"
+
+def get_form(ch, encoding, field):
+       text = "foo" + encode(ch, encoding) + "bar"
+       if encoding == E_JavaScript:
+               text_initial = ""
+       else:
+               text_initial = text
+
+       s = """<html>
+<head>
+<title>Form Test</title>
+</head>
+<body>
+<form id="form1" name="form1" action="http://127.0.0.1:8090/";>
+"""
+       if field == F_Hidden:
+               s += '<input type="hidden" id="field1" name="field1" value="' + 
text_initial + '">'
+       elif field == F_TextArea:
+               s += '<textarea id="field1" name="field1">' + text_initial + 
'</textarea>'
+       s += "\n</form>"
+       if encoding == E_JavaScript:
+               s += """
+<script>
+document.form1.field1.value = '%s';
+</script>""" % (text)
+
+       s += "</body></html>"
+       return s
+
+class forwarder(BaseHTTPRequestHandler):
+       def do_GET(self):
+               w.write(self.path + "\n")
+               w.flush()
+               self.send_response(200)
+               self.send_header("Content-Type", "text/plain")
+               self.end_headers()
+               self.wfile.write("Dummy response")
+
+def runtest(r, *args):
+       form = get_form(*args)
+
+       tmpfile, tmpname = tempfile.mkstemp(".html")
+       tmpfile = os.fdopen(tmpfile, 'w')
+       tmpfile.write(form)
+       tmpfile.close()
+
+       linkspid = os.spawnlp(os.P_NOWAIT, 'elinks', 'elinks',
+               '-config-dir', os.getcwd(),
+               '-config-file', 'crlf.conf',
+               '-no-connect', '1',
+               '-auto-submit', '1',
+               tmpname)
+       path = r.readline()
+       os.kill(linkspid, signal.SIGINT)
+       os.waitpid(linkspid, 0)
+
+       os.unlink(tmpname)
+
+       return path
+
+pid = os.fork()
+
+if pid:
+       os.close(w)
+       r = os.fdopen(r)
+
+       paths = []
+
+       for c in [C_CR, C_LF, C_CRLF]:
+               for e in [E_Raw, E_Entity, E_JavaScript]:
+                       for f in [F_Hidden, F_TextArea]:
+                               paths.append(("%d %d %d " % (c, e, f)) + 
runtest(r, c, e, f))
+
+       for path in paths:
+               print path,
+
+       os.kill(pid, signal.SIGTERM)
+       os.waitpid(pid, 0)
+else:
+       os.close(r)
+       w = os.fdopen(w, 'w')
+       server_address = ('127.0.0.1', 8090)
+       httpd = HTTPServer(server_address, forwarder)
+       httpd.serve_forever()
-- 
1.5.6.5


-- 
Peter

Attachment: signature.asc
Description: Digital signature

_______________________________________________
elinks-dev mailing list
[email protected]
http://linuxfromscratch.org/mailman/listinfo/elinks-dev

Reply via email to