diff --git a/AUTHORS b/AUTHORS index 866f0d70..9a0711c4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -457,6 +457,8 @@ Peder Stray Fix handling of key presses turning up as key prefixes Peter Collingbourne + Allows relicensing under GPLv2-or-later and linking with OpenSSL + 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 diff --git a/NEWS b/NEWS index 3b4b5c57..589a1bec 100644 --- a/NEWS +++ b/NEWS @@ -75,6 +75,8 @@ ELinks 0.12pre2.GIT now: To be released as 0.12pre3, 0.12rc1, or even 0.12.0. This branch also includes the changes listed under ``ELinks 0.11.5.GIT'' below. +* Preserve newlines in hidden input fields, and submit them as CRLF. + Previously, they could turn into spaces or disappear entirely. * Perl scripts can use modules that dynamically load C libraries, like XML::LibXML::SAX does. * enhancement: Updated ISO 8859-7, ISO 8859-16, KOI8-R, and MacRoman. diff --git a/src/document/html/parser/forms.c b/src/document/html/parser/forms.c index c34459a1..5f9dc475 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 128485eb..399c4e6d 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 4eaa1546..9498e43c 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 f2b7b9de..e64ae88c 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 74a99915..79757bac 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 60a0c60a..7749f7ba 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 00000000..33d61a2d --- /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 00000000..84b49fd1 --- /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 " " + if ch == C_LF: + if encoding == E_Raw: + return "\n" + if encoding == E_JavaScript: + return "\\n" + if encoding == E_Entity: + return " " + +def get_form(ch, encoding, field): + text = "foo" + encode(ch, encoding) + "bar" + if encoding == E_JavaScript: + text_initial = "" + else: + text_initial = text + + s = """ + +Form Test + + +
+""" + if field == F_Hidden: + s += '' + elif field == F_TextArea: + s += '' + s += "\n
" + if encoding == E_JavaScript: + s += """ +""" % (text) + + s += "" + 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()