[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
This commit is contained in:
James Bursa 2004-08-08 19:13:40 +00:00
parent 94103b8c96
commit 8337acfc78
3 changed files with 166 additions and 86 deletions

View File

@ -1638,12 +1638,20 @@ void browser_form_submit(struct browser_window *bw, struct form *form,
assert(form); assert(form);
assert(bw->current_content->type == CONTENT_HTML); 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; base = bw->current_content->data.html.base_url;
switch (form->method) { switch (form->method) {
case method_GET: case method_GET:
data = form_url_encode(success); 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); url = xcalloc(1, strlen(form->action) + strlen(data) + 2);
if(form->action[strlen(form->action)-1] == '?') { if(form->action[strlen(form->action)-1] == '?') {
sprintf(url, "%s%s", form->action, data); 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: case method_POST_URLENC:
data = form_url_encode(success); data = form_url_encode(success);
if (!data) {
form_free_successful(success);
warn_user("NoMemory", 0);
return;
}
url = url_join(form->action, base); url = url_join(form->action, base);
if (!url) if (!url)
break; break;

View File

@ -2,7 +2,7 @@
* This file is part of NetSurf, http://netsurf.sourceforge.net/ * This file is part of NetSurf, http://netsurf.sourceforge.net/
* Licensed under the GNU General Public License, * Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license * http://www.opensource.org/licenses/gpl-license
* Copyright 2003 James Bursa <bursa@users.sourceforge.net> * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net> * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
*/ */
@ -100,23 +100,28 @@ void form_free_control(struct form_control *control)
/** /**
* Identify 'successful' controls. * 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. * See HTML 4.01 section 17.13.2.
*/ */
struct form_successful_control *form_successful_controls(struct form *form, bool form_successful_controls(struct form *form,
struct form_control *submit_button) struct form_control *submit_button,
struct form_successful_control **successful_controls)
{ {
struct form_control *control; struct form_control *control;
struct form_option *option; 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; last_success = &sentinel;
sentinel.next = 0; sentinel.next = 0;
for (control = form->controls; control; control = control->next) { for (control = form->controls; control; control = control->next) {
struct form_successful_control *success_new;
bool add_val;
/* ignore disabled controls */ /* ignore disabled controls */
if (control->disabled) if (control->disabled)
continue; continue;
@ -129,15 +134,20 @@ struct form_successful_control *form_successful_controls(struct form *form,
case GADGET_HIDDEN: case GADGET_HIDDEN:
case GADGET_TEXTBOX: case GADGET_TEXTBOX:
case GADGET_PASSWORD: case GADGET_PASSWORD:
add_val = true; value = strdup(control->value);
if (!value)
goto no_memory;
break; break;
case GADGET_RADIO: case GADGET_RADIO:
case GADGET_CHECKBOX: case GADGET_CHECKBOX:
/* ignore checkboxes and radio buttons which /* ignore checkboxes and radio buttons which
* aren't selected * aren't selected */
*/ if (!control->selected)
add_val = control->selected; continue;
value = strdup(control->value);
if (!value)
goto no_memory;
break; break;
case GADGET_SELECT: case GADGET_SELECT:
@ -145,31 +155,34 @@ struct form_successful_control *form_successful_controls(struct form *form,
for (option = control->data.select.items; for (option = control->data.select.items;
option != NULL; option != NULL;
option = option->next) { option = option->next) {
if (option->selected) { if (!option->selected)
success_new = xcalloc(1, sizeof(*success_new)); continue;
success_new->file = false; success_new = malloc(sizeof(*success_new));
success_new->name = cnv_str_local_enc(control->name); if (!success_new)
success_new->value = cnv_str_local_enc(option->value); goto no_memory;
success_new->next = NULL; success_new->file = false;
last_success->next = success_new; success_new->name = strdup(control->name);
last_success = success_new; 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; break;
case GADGET_TEXTAREA: case GADGET_TEXTAREA:
/* textarea */ /* textarea */
success_new = xcalloc(1, sizeof(*success_new)); value = form_textarea_value(control);
success_new->file = false; if (!value)
success_new->name = cnv_str_local_enc(control->name); goto no_memory;
success_new->value = form_textarea_value(control); if (value[0] == 0) {
success_new->next = 0; free(value);
last_success->next = success_new; continue;
last_success = success_new; }
add_val = false;
break; break;
case GADGET_IMAGE: { 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; const size_t len = strlen(control->name) + 3;
/* x */ /* 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->file = false;
success_new->name = xcalloc(1, len); success_new->name = malloc(len);
sprintf(success_new->name, "%s.x", control->name); success_new->value = malloc(20);
success_new->value = xcalloc(1, 20); if (!success_new->name ||
sprintf(success_new->value, "%i", control->data.image.mx); !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; success_new->next = 0;
last_success->next = success_new; last_success->next = success_new;
last_success = success_new; last_success = success_new;
/* y */ /* 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->file = false;
success_new->name = xcalloc(1, len); success_new->name = malloc(len);
sprintf(success_new->name, "%s.y", control->name); success_new->value = malloc(20);
success_new->value = xcalloc(1, 20); if (!success_new->name ||
sprintf(success_new->value, "%i", control->data.image.my); !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; success_new->next = 0;
last_success->next = success_new; last_success->next = success_new;
last_success = success_new; last_success = success_new;
add_val = false; continue;
break; break;
} }
case GADGET_SUBMIT: case GADGET_SUBMIT:
/* only the activated submit button is /* only the activated submit button is
* successful * successful */
*/ if (control != submit_button)
add_val = (control != submit_button) ? false : true; continue;
value = strdup(control->value);
if (!value)
goto no_memory;
break; break;
case GADGET_RESET: case GADGET_RESET:
/* ignore reset */ /* ignore reset */
add_val = false; continue;
break; break;
case GADGET_FILE: case GADGET_FILE:
/* 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->file = true;
success_new->name = cnv_str_local_enc(control->name); success_new->name = strdup(control->name);
success_new->value = cnv_str_local_enc(control->value); success_new->value = strdup(control->value);
success_new->next = 0; success_new->next = 0;
last_success->next = success_new; last_success->next = success_new;
last_success = success_new; last_success = success_new;
if (!success_new->name || !success_new->value)
goto no_memory;
add_val = false; continue;
break; break;
default: default:
@ -232,58 +276,65 @@ struct form_successful_control *form_successful_controls(struct form *form,
break; break;
} }
/* all others added if they have a value */ success_new = malloc(sizeof(*success_new));
if (add_val && control->value != NULL) { if (!success_new)
success_new = xcalloc(1, sizeof(*success_new)); goto no_memory;
success_new->file = false; success_new->file = false;
success_new->name = cnv_str_local_enc(control->name); success_new->name = strdup(control->name);
success_new->value = cnv_str_local_enc(control->value); success_new->value = value;
success_new->next = NULL; success_new->next = NULL;
last_success->next = success_new; last_success->next = success_new;
last_success = 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. * 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) char *form_textarea_value(struct form_control *textarea)
{ {
unsigned int len = 1; unsigned int len = 0;
char *value, *s; char *value, *s;
struct box *inline_container, *text_box; struct box *text_box;
/* find required length */ /* find required length */
for (inline_container = textarea->box->children; for (text_box = textarea->box->children->children; text_box;
inline_container != NULL; text_box = text_box->next) {
inline_container = inline_container->next) { if (text_box->type == BOX_INLINE)
for (text_box = inline_container->children;
text_box != NULL;
text_box = text_box->next) {
len += text_box->length + 1; len += text_box->length + 1;
} else /* BOX_BR */
len += 2; len += 2;
} }
/* construct value */ /* construct value */
s = value = xcalloc(1, len); s = value = malloc(len + 1);
for (inline_container = textarea->box->children; if (!s)
inline_container != NULL; return 0;
inline_container = inline_container->next) { for (text_box = textarea->box->children->children; text_box;
for (text_box = inline_container->children; text_box = text_box->next) {
text_box != NULL; if (text_box->type == BOX_INLINE) {
text_box = text_box->next) {
strncpy(s, text_box->text, text_box->length); strncpy(s, text_box->text, text_box->length);
s += text_box->length; s += text_box->length;
*s++ = ' '; *s++ = ' ';
} else { /* BOX_BR */
*s++ = '\r';
*s++ = '\n';
} }
*s++ = '\r';
*s++ = '\n';
} }
*s = 0; *s = 0;
@ -293,18 +344,33 @@ char *form_textarea_value(struct form_control *textarea)
/** /**
* Encode controls using application/x-www-form-urlencoded. * 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 *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; unsigned int len = 0, len1;
if (!s)
return 0;
s[0] = 0;
for (; control; control = control->next) { for (; control; control = control->next) {
const char *name = curl_escape(control->name, 0); name = curl_escape(control->name, 0);
const char *value = curl_escape(control->value, 0); value = curl_escape(control->value, 0);
len1 = len + strlen(name) + strlen(value) + 2; 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); sprintf(s + len, "%s=%s&", name, value);
len = len1; len = len1;
curl_free(name); curl_free(name);

View File

@ -100,8 +100,9 @@ struct form_successful_control {
struct form_control *form_new_control(form_control_type type); struct form_control *form_new_control(form_control_type type);
void form_add_control(struct form *form, struct form_control *control); void form_add_control(struct form *form, struct form_control *control);
void form_free_control(struct form_control *control); void form_free_control(struct form_control *control);
struct form_successful_control *form_successful_controls(struct form *form, bool form_successful_controls(struct form *form,
struct form_control *submit_button); struct form_control *submit_button,
struct form_successful_control **successful_controls);
char *form_url_encode(struct form_successful_control *control); char *form_url_encode(struct form_successful_control *control);
void form_free_successful(struct form_successful_control *control); void form_free_successful(struct form_successful_control *control);