From 8337acfc7839cde431d4761bbe693f0faa17b741 Mon Sep 17 00:00:00 2001 From: James Bursa Date: Sun, 8 Aug 2004 19:13:40 +0000 Subject: [project @ 2004-08-08 19:13:40 by bursa] Fix form submitting with an empty file upload. Update form_textarea_value(). Purge xcalloc() etc from form.c and handle memory exhaustion. svn path=/import/netsurf/; revision=1195 --- desktop/browser.c | 15 +++- render/form.c | 232 +++++++++++++++++++++++++++++++++++------------------- render/form.h | 5 +- 3 files changed, 166 insertions(+), 86 deletions(-) diff --git a/desktop/browser.c b/desktop/browser.c index ca23c1438..6e797a97e 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -1638,12 +1638,20 @@ void browser_form_submit(struct browser_window *bw, struct form *form, assert(form); assert(bw->current_content->type == CONTENT_HTML); - success = form_successful_controls(form, submit_button); + if (!form_successful_controls(form, submit_button, &success)) { + warn_user("NoMemory", 0); + return; + } base = bw->current_content->data.html.base_url; switch (form->method) { case method_GET: data = form_url_encode(success); + if (!data) { + form_free_successful(success); + warn_user("NoMemory", 0); + return; + } url = xcalloc(1, strlen(form->action) + strlen(data) + 2); if(form->action[strlen(form->action)-1] == '?') { sprintf(url, "%s%s", form->action, data); @@ -1659,6 +1667,11 @@ void browser_form_submit(struct browser_window *bw, struct form *form, case method_POST_URLENC: data = form_url_encode(success); + if (!data) { + form_free_successful(success); + warn_user("NoMemory", 0); + return; + } url = url_join(form->action, base); if (!url) break; diff --git a/render/form.c b/render/form.c index 3713071e9..f2424849b 100644 --- a/render/form.c +++ b/render/form.c @@ -2,7 +2,7 @@ * This file is part of NetSurf, http://netsurf.sourceforge.net/ * Licensed under the GNU General Public License, * http://www.opensource.org/licenses/gpl-license - * Copyright 2003 James Bursa + * Copyright 2004 James Bursa * Copyright 2003 Phil Mellor */ @@ -100,23 +100,28 @@ void form_free_control(struct form_control *control) /** * Identify 'successful' controls. * + * \param form form to search for successful controls + * \param submit_button control used to submit the form, if any + * \parma successful_controls updated to point to linked list of + * form_successful_control, 0 if no controls + * \return true on success, false on memory exhaustion + * * See HTML 4.01 section 17.13.2. */ -struct form_successful_control *form_successful_controls(struct form *form, - struct form_control *submit_button) +bool form_successful_controls(struct form *form, + struct form_control *submit_button, + struct form_successful_control **successful_controls) { struct form_control *control; struct form_option *option; - struct form_successful_control sentinel, *last_success; + struct form_successful_control sentinel, *last_success, *success_new; + char *value; last_success = &sentinel; sentinel.next = 0; for (control = form->controls; control; control = control->next) { - struct form_successful_control *success_new; - bool add_val; - /* ignore disabled controls */ if (control->disabled) continue; @@ -129,15 +134,20 @@ struct form_successful_control *form_successful_controls(struct form *form, case GADGET_HIDDEN: case GADGET_TEXTBOX: case GADGET_PASSWORD: - add_val = true; + value = strdup(control->value); + if (!value) + goto no_memory; break; case GADGET_RADIO: case GADGET_CHECKBOX: /* ignore checkboxes and radio buttons which - * aren't selected - */ - add_val = control->selected; + * aren't selected */ + if (!control->selected) + continue; + value = strdup(control->value); + if (!value) + goto no_memory; break; case GADGET_SELECT: @@ -145,31 +155,34 @@ struct form_successful_control *form_successful_controls(struct form *form, for (option = control->data.select.items; option != NULL; option = option->next) { - if (option->selected) { - success_new = xcalloc(1, sizeof(*success_new)); - success_new->file = false; - success_new->name = cnv_str_local_enc(control->name); - success_new->value = cnv_str_local_enc(option->value); - success_new->next = NULL; - last_success->next = success_new; - last_success = success_new; - } + if (!option->selected) + continue; + success_new = malloc(sizeof(*success_new)); + if (!success_new) + goto no_memory; + success_new->file = false; + success_new->name = strdup(control->name); + success_new->value = strdup(option->value); + success_new->next = NULL; + last_success->next = success_new; + last_success = success_new; + if (!success_new->name || + !success_new->value) + goto no_memory; } - add_val = false; + continue; break; case GADGET_TEXTAREA: /* textarea */ - success_new = xcalloc(1, sizeof(*success_new)); - success_new->file = false; - success_new->name = cnv_str_local_enc(control->name); - success_new->value = form_textarea_value(control); - success_new->next = 0; - last_success->next = success_new; - last_success = success_new; - - add_val = false; + value = form_textarea_value(control); + if (!value) + goto no_memory; + if (value[0] == 0) { + free(value); + continue; + } break; case GADGET_IMAGE: { @@ -177,54 +190,85 @@ struct form_successful_control *form_successful_controls(struct form *form, const size_t len = strlen(control->name) + 3; /* x */ - success_new = xcalloc(1, sizeof(*success_new)); + success_new = malloc(sizeof(*success_new)); + if (!success_new) + goto no_memory; success_new->file = false; - success_new->name = xcalloc(1, len); - sprintf(success_new->name, "%s.x", control->name); - success_new->value = xcalloc(1, 20); - sprintf(success_new->value, "%i", control->data.image.mx); + success_new->name = malloc(len); + success_new->value = malloc(20); + if (!success_new->name || + !success_new->value) { + free(success_new->name); + free(success_new->value); + free(success_new); + goto no_memory; + } + sprintf(success_new->name, "%s.x", + control->name); + sprintf(success_new->value, "%i", + control->data.image.mx); success_new->next = 0; last_success->next = success_new; last_success = success_new; /* y */ - success_new = xcalloc(1, sizeof(*success_new)); + success_new = malloc(sizeof(*success_new)); + if (!success_new) + goto no_memory; success_new->file = false; - success_new->name = xcalloc(1, len); - sprintf(success_new->name, "%s.y", control->name); - success_new->value = xcalloc(1, 20); - sprintf(success_new->value, "%i", control->data.image.my); + success_new->name = malloc(len); + success_new->value = malloc(20); + if (!success_new->name || + !success_new->value) { + free(success_new->name); + free(success_new->value); + free(success_new); + goto no_memory; + } + sprintf(success_new->name, "%s.y", + control->name); + sprintf(success_new->value, "%i", + control->data.image.my); success_new->next = 0; last_success->next = success_new; last_success = success_new; - add_val = false; + continue; break; } case GADGET_SUBMIT: /* only the activated submit button is - * successful - */ - add_val = (control != submit_button) ? false : true; + * successful */ + if (control != submit_button) + continue; + value = strdup(control->value); + if (!value) + goto no_memory; break; case GADGET_RESET: /* ignore reset */ - add_val = false; + continue; break; case GADGET_FILE: /* file */ - success_new = xcalloc(1, sizeof(*success_new)); + if (!control->value) + continue; + success_new = malloc(sizeof(*success_new)); + if (!success_new) + goto no_memory; success_new->file = true; - success_new->name = cnv_str_local_enc(control->name); - success_new->value = cnv_str_local_enc(control->value); + success_new->name = strdup(control->name); + success_new->value = strdup(control->value); success_new->next = 0; last_success->next = success_new; last_success = success_new; + if (!success_new->name || !success_new->value) + goto no_memory; - add_val = false; + continue; break; default: @@ -232,58 +276,65 @@ struct form_successful_control *form_successful_controls(struct form *form, break; } - /* all others added if they have a value */ - if (add_val && control->value != NULL) { - success_new = xcalloc(1, sizeof(*success_new)); - success_new->file = false; - success_new->name = cnv_str_local_enc(control->name); - success_new->value = cnv_str_local_enc(control->value); - success_new->next = NULL; - last_success->next = success_new; - last_success = success_new; - } + success_new = malloc(sizeof(*success_new)); + if (!success_new) + goto no_memory; + success_new->file = false; + success_new->name = strdup(control->name); + success_new->value = value; + success_new->next = NULL; + last_success->next = success_new; + last_success = success_new; + if (!success_new->name) + goto no_memory; } - return sentinel.next; + *successful_controls = sentinel.next; + return true; + +no_memory: + warn_user("NoMemory", 0); + form_free_successful(sentinel.next); + return false; } /** * Find the value for a textarea control. + * + * \param textarea control of type GADGET_TEXTAREA + * \return the value as a UTF-8 string on heap, or 0 on memory exhaustion */ char *form_textarea_value(struct form_control *textarea) { - unsigned int len = 1; + unsigned int len = 0; char *value, *s; - struct box *inline_container, *text_box; + struct box *text_box; /* find required length */ - for (inline_container = textarea->box->children; - inline_container != NULL; - inline_container = inline_container->next) { - for (text_box = inline_container->children; - text_box != NULL; - text_box = text_box->next) { + for (text_box = textarea->box->children->children; text_box; + text_box = text_box->next) { + if (text_box->type == BOX_INLINE) len += text_box->length + 1; - } - len += 2; + else /* BOX_BR */ + len += 2; } /* construct value */ - s = value = xcalloc(1, len); - for (inline_container = textarea->box->children; - inline_container != NULL; - inline_container = inline_container->next) { - for (text_box = inline_container->children; - text_box != NULL; - text_box = text_box->next) { + s = value = malloc(len + 1); + if (!s) + return 0; + for (text_box = textarea->box->children->children; text_box; + text_box = text_box->next) { + if (text_box->type == BOX_INLINE) { strncpy(s, text_box->text, text_box->length); s += text_box->length; *s++ = ' '; + } else { /* BOX_BR */ + *s++ = '\r'; + *s++ = '\n'; } - *s++ = '\r'; - *s++ = '\n'; } *s = 0; @@ -293,18 +344,33 @@ char *form_textarea_value(struct form_control *textarea) /** * Encode controls using application/x-www-form-urlencoded. + * + * \param control linked list of form_successful_control + * \return URL-encoded form, or 0 on memory exhaustion + * + * \todo encoding conversion */ char *form_url_encode(struct form_successful_control *control) { - char *s = xcalloc(1, 0); + char *name, *value; + char *s = malloc(1), *s2; unsigned int len = 0, len1; + if (!s) + return 0; + s[0] = 0; + for (; control; control = control->next) { - const char *name = curl_escape(control->name, 0); - const char *value = curl_escape(control->value, 0); + name = curl_escape(control->name, 0); + value = curl_escape(control->value, 0); len1 = len + strlen(name) + strlen(value) + 2; - s = xrealloc(s, len1 + 1); + s2 = realloc(s, len1 + 1); + if (!s2) { + free(s); + return 0; + } + s = s2; sprintf(s + len, "%s=%s&", name, value); len = len1; curl_free(name); diff --git a/render/form.h b/render/form.h index e6f77aaa7..d0abd8e86 100644 --- a/render/form.h +++ b/render/form.h @@ -100,8 +100,9 @@ struct form_successful_control { struct form_control *form_new_control(form_control_type type); void form_add_control(struct form *form, struct form_control *control); void form_free_control(struct form_control *control); -struct form_successful_control *form_successful_controls(struct form *form, - struct form_control *submit_button); +bool form_successful_controls(struct form *form, + struct form_control *submit_button, + struct form_successful_control **successful_controls); char *form_url_encode(struct form_successful_control *control); void form_free_successful(struct form_successful_control *control); -- cgit v1.2.3