mirror of
https://github.com/netsurf-browser/netsurf
synced 2025-01-03 17:54:33 +03:00
fix url encoding to be compatible with nsurl API changes.
As part of this fix the form submission error handling and reporting has been improved.
This commit is contained in:
parent
9100fcb409
commit
5c96acd6f1
@ -74,16 +74,22 @@ typedef struct fetch_msg {
|
||||
} data;
|
||||
} fetch_msg;
|
||||
|
||||
/** Fetch POST multipart data */
|
||||
/**
|
||||
* Fetch POST multipart data
|
||||
*/
|
||||
struct fetch_multipart_data {
|
||||
bool file; /**< Item is a file */
|
||||
char *name; /**< Name of item */
|
||||
char *value; /**< Item value */
|
||||
char *rawfile; /**< Raw filename if file is true */
|
||||
struct fetch_multipart_data *next; /**< Next in linked list */
|
||||
|
||||
struct fetch_multipart_data *next; /**< Next in linked list */
|
||||
char *name; /**< Name of item */
|
||||
char *value; /**< Item value */
|
||||
|
||||
char *rawfile; /**< Raw filename if file is true */
|
||||
bool file; /**< Item is a file */
|
||||
};
|
||||
|
||||
/**
|
||||
* ssl certificate information for certificate error message
|
||||
*/
|
||||
struct ssl_cert_info {
|
||||
long version; /**< Certificate version */
|
||||
char not_before[32]; /**< Valid from date */
|
||||
|
@ -25,8 +25,11 @@
|
||||
|
||||
#include "utils/config.h"
|
||||
#include "utils/log.h"
|
||||
#include "utils/messages.h"
|
||||
#include "netsurf/keypress.h"
|
||||
#include "netsurf/misc.h"
|
||||
#include "desktop/textarea.h"
|
||||
#include "desktop/gui_internal.h"
|
||||
|
||||
#include "html/html_internal.h"
|
||||
#include "html/box.h"
|
||||
@ -41,6 +44,7 @@ bool box_textarea_keypress(html_content *html, struct box *box, uint32_t key)
|
||||
struct textarea *ta = gadget->data.text.ta;
|
||||
struct form* form = box->gadget->form;
|
||||
struct content *c = (struct content *) html;
|
||||
nserror res;
|
||||
|
||||
assert(ta != NULL);
|
||||
|
||||
@ -48,9 +52,16 @@ bool box_textarea_keypress(html_content *html, struct box *box, uint32_t key)
|
||||
switch (key) {
|
||||
case NS_KEY_NL:
|
||||
case NS_KEY_CR:
|
||||
if (form)
|
||||
form_submit(content_get_url(c), html->bw,
|
||||
form, 0);
|
||||
if (form) {
|
||||
res = form_submit(content_get_url(c),
|
||||
html->bw,
|
||||
form,
|
||||
NULL);
|
||||
if (res != NSERROR_OK) {
|
||||
guit->misc->warning(messages_get_errorcode(res), NULL);
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
|
||||
case NS_KEY_TAB:
|
||||
|
@ -327,10 +327,28 @@ bool form_add_option(struct form_control *control, char *value, char *text,
|
||||
}
|
||||
|
||||
|
||||
/* exported interface documented in html/form_internal.h */
|
||||
bool form_successful_controls_dom(struct form *_form,
|
||||
struct form_control *_submit_button,
|
||||
struct fetch_multipart_data **successful_controls)
|
||||
/**
|
||||
* Identify 'successful' controls via the DOM.
|
||||
*
|
||||
* All text strings in the successful controls list will be in the charset most
|
||||
* appropriate for submission. Therefore, no utf8_to_* processing should be
|
||||
* performed upon them.
|
||||
*
|
||||
* \todo The chosen charset needs to be made available such that it can be
|
||||
* included in the submission request (e.g. in the fetch's Content-Type header)
|
||||
*
|
||||
* See HTML 4.01 section 17.13.2.
|
||||
*
|
||||
* \param[in] form form to search for successful controls
|
||||
* \param[in] submit_button control used to submit the form, if any
|
||||
* \param[out] successful_controls updated to point to linked list of
|
||||
* fetch_multipart_data, NULL if no controls
|
||||
* \return NSERROR_OK on success or appropriate error code
|
||||
*/
|
||||
static nserror
|
||||
form_successful_controls_dom(struct form *_form,
|
||||
struct form_control *_submit_button,
|
||||
struct fetch_multipart_data **successful_controls)
|
||||
{
|
||||
dom_html_form_element *form = _form->node;
|
||||
dom_html_element *submit_button = (_submit_button != NULL) ? _submit_button->node : NULL;
|
||||
@ -352,7 +370,7 @@ bool form_successful_controls_dom(struct form *_form,
|
||||
charset = form_acceptable_charset(_form);
|
||||
if (charset == NULL) {
|
||||
NSLOG(netsurf, INFO, "failed to find charset");
|
||||
return false;
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
|
||||
#define ENCODE_ITEM(i) (((i) == NULL) ? ( \
|
||||
@ -685,6 +703,11 @@ bool form_successful_controls_dom(struct form *_form,
|
||||
}
|
||||
|
||||
basename = ENCODE_ITEM(inputname);
|
||||
if (basename == NULL) {
|
||||
NSLOG(netsurf, INFO,
|
||||
"Could not encode basename");
|
||||
goto dom_no_memory;
|
||||
}
|
||||
|
||||
success_new = calloc(1, sizeof(*success_new));
|
||||
if (success_new == NULL) {
|
||||
@ -704,6 +727,8 @@ bool form_successful_controls_dom(struct form *_form,
|
||||
"Could not allocate name for image.x");
|
||||
goto dom_no_memory;
|
||||
}
|
||||
sprintf(success_new->name, "%s.x", basename);
|
||||
|
||||
success_new->value = malloc(20);
|
||||
if (success_new->value == NULL) {
|
||||
free(basename);
|
||||
@ -711,7 +736,6 @@ bool form_successful_controls_dom(struct form *_form,
|
||||
"Could not allocate value for image.x");
|
||||
goto dom_no_memory;
|
||||
}
|
||||
sprintf(success_new->name, "%s.x", basename);
|
||||
sprintf(success_new->value, "%d", coords->x);
|
||||
|
||||
success_new = calloc(1, sizeof(*success_new));
|
||||
@ -890,7 +914,7 @@ bool form_successful_controls_dom(struct form *_form,
|
||||
|
||||
*successful_controls = sentinel.next;
|
||||
|
||||
return true;
|
||||
return NSERROR_OK;
|
||||
|
||||
dom_no_memory:
|
||||
free(charset);
|
||||
@ -915,73 +939,61 @@ dom_no_memory:
|
||||
if (rawfile_temp != NULL)
|
||||
free(rawfile_temp);
|
||||
|
||||
return false;
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
#undef ENCODE_ITEM
|
||||
|
||||
/**
|
||||
* Encode controls using application/x-www-form-urlencoded.
|
||||
*
|
||||
* \param form form to which successful controls relate
|
||||
* \param control linked list of fetch_multipart_data
|
||||
* \param query_string iff true add '?' to the start of returned data
|
||||
* \return URL-encoded form, or 0 on memory exhaustion
|
||||
* \param[in] form form to which successful controls relate
|
||||
* \param[in] control linked list of fetch_multipart_data
|
||||
* \param[out] encoded_out URL-encoded form data
|
||||
* \return NSERROR_OK on success and \a encoded_out updated else appropriate error code
|
||||
*/
|
||||
|
||||
static char *form_url_encode(struct form *form,
|
||||
static nserror
|
||||
form_url_encode(struct form *form,
|
||||
struct fetch_multipart_data *control,
|
||||
bool query_string)
|
||||
char **encoded_out)
|
||||
{
|
||||
char *name, *value;
|
||||
char *s, *s2;
|
||||
unsigned int len, len1, len_init;
|
||||
nserror url_err;
|
||||
nserror res;
|
||||
|
||||
if (query_string)
|
||||
s = malloc(2);
|
||||
else
|
||||
s = malloc(1);
|
||||
s = malloc(1);
|
||||
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
if (query_string) {
|
||||
s[0] = '?';
|
||||
s[1] = '\0';
|
||||
len_init = len = 1;
|
||||
} else {
|
||||
s[0] = '\0';
|
||||
len_init = len = 0;
|
||||
if (s == NULL) {
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
|
||||
s[0] = '\0';
|
||||
len_init = len = 0;
|
||||
|
||||
for (; control; control = control->next) {
|
||||
url_err = url_escape(control->name, true, NULL, &name);
|
||||
if (url_err == NSERROR_NOMEM) {
|
||||
res = url_escape(control->name, true, NULL, &name);
|
||||
if (res != NSERROR_OK) {
|
||||
free(s);
|
||||
return NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
assert(url_err == NSERROR_OK);
|
||||
|
||||
url_err = url_escape(control->value, true, NULL, &value);
|
||||
if (url_err == NSERROR_NOMEM) {
|
||||
res = url_escape(control->value, true, NULL, &value);
|
||||
if (res != NSERROR_OK) {
|
||||
free(name);
|
||||
free(s);
|
||||
return NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
assert(url_err == NSERROR_OK);
|
||||
|
||||
/* resize string to allow for new key/value pair,
|
||||
* equals, amphersand and terminator
|
||||
*/
|
||||
len1 = len + strlen(name) + strlen(value) + 2;
|
||||
s2 = realloc(s, len1 + 1);
|
||||
if (!s2) {
|
||||
if (s2 == NULL) {
|
||||
free(value);
|
||||
free(name);
|
||||
free(s);
|
||||
return NULL;
|
||||
return NSERROR_NOMEM;
|
||||
}
|
||||
s = s2;
|
||||
|
||||
@ -995,7 +1007,10 @@ static char *form_url_encode(struct form *form,
|
||||
/* Replace trailing '&' */
|
||||
s[len - 1] = '\0';
|
||||
}
|
||||
return s;
|
||||
|
||||
*encoded_out = s;
|
||||
|
||||
return NSERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1008,17 +1023,15 @@ char *form_acceptable_charset(struct form *form)
|
||||
{
|
||||
char *temp, *c;
|
||||
|
||||
if (!form)
|
||||
return NULL;
|
||||
|
||||
if (!form->accept_charsets) {
|
||||
/* no accept-charsets attribute for this form */
|
||||
if (form->document_charset)
|
||||
if (form->document_charset) {
|
||||
/* document charset present, so use it */
|
||||
return strdup(form->document_charset);
|
||||
else
|
||||
} else {
|
||||
/* no document charset, so default to 8859-1 */
|
||||
return strdup("ISO-8859-1");
|
||||
}
|
||||
}
|
||||
|
||||
/* make temporary copy of accept-charsets attribute */
|
||||
@ -1768,98 +1781,85 @@ void form_radio_set(struct form_control *radio)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Collect controls and submit a form.
|
||||
*/
|
||||
|
||||
void form_submit(nsurl *page_url, struct browser_window *target,
|
||||
struct form *form, struct form_control *submit_button)
|
||||
/* private interface described in html/form_internal.h */
|
||||
nserror
|
||||
form_submit(nsurl *page_url,
|
||||
struct browser_window *target,
|
||||
struct form *form,
|
||||
struct form_control *submit_button)
|
||||
{
|
||||
char *data = NULL;
|
||||
struct fetch_multipart_data *success;
|
||||
nserror res;
|
||||
char *data = NULL; /* encoded form data */
|
||||
struct fetch_multipart_data *success = NULL; /* gcc is incapable of correctly reasoning about use and generates "maybe used uninitialised" warnings */
|
||||
nsurl *action_url;
|
||||
nsurl *action_query;
|
||||
nserror error;
|
||||
nsurl *query_url;
|
||||
|
||||
assert(form != NULL);
|
||||
|
||||
if (form_successful_controls_dom(form, submit_button, &success) == false) {
|
||||
guit->misc->warning("NoMemory", 0);
|
||||
return;
|
||||
/* obtain list of controls from DOM */
|
||||
res = form_successful_controls_dom(form, submit_button, &success);
|
||||
if (res != NSERROR_OK) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Decompose action */
|
||||
if (nsurl_create(form->action, &action_url) != NSERROR_OK) {
|
||||
free(data);
|
||||
res = nsurl_create(form->action, &action_url);
|
||||
if (res != NSERROR_OK) {
|
||||
fetch_multipart_data_destroy(success);
|
||||
guit->misc->warning("NoMemory", 0);
|
||||
return;
|
||||
return res;
|
||||
}
|
||||
|
||||
switch (form->method) {
|
||||
case method_GET:
|
||||
data = form_url_encode(form, success, true);
|
||||
if (data == NULL) {
|
||||
fetch_multipart_data_destroy(success);
|
||||
guit->misc->warning("NoMemory", 0);
|
||||
return;
|
||||
}
|
||||
res = form_url_encode(form, success, &data);
|
||||
if (res == NSERROR_OK) {
|
||||
/* Replace query segment */
|
||||
res = nsurl_replace_query(action_url, data, &query_url);
|
||||
if (res == NSERROR_OK) {
|
||||
res = browser_window_navigate(target,
|
||||
query_url,
|
||||
page_url,
|
||||
BW_NAVIGATE_HISTORY,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
/* Replace query segment */
|
||||
error = nsurl_replace_query(action_url, data, &action_query);
|
||||
if (error != NSERROR_OK) {
|
||||
nsurl_unref(action_query);
|
||||
nsurl_unref(query_url);
|
||||
}
|
||||
free(data);
|
||||
fetch_multipart_data_destroy(success);
|
||||
guit->misc->warning(messages_get_errorcode(error), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Construct submit url */
|
||||
browser_window_navigate(target,
|
||||
action_query,
|
||||
page_url,
|
||||
BW_NAVIGATE_HISTORY,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
nsurl_unref(action_query);
|
||||
break;
|
||||
|
||||
case method_POST_URLENC:
|
||||
data = form_url_encode(form, success, false);
|
||||
if (data == NULL) {
|
||||
fetch_multipart_data_destroy(success);
|
||||
guit->misc->warning("NoMemory", 0);
|
||||
nsurl_unref(action_url);
|
||||
return;
|
||||
res = form_url_encode(form, success, &data);
|
||||
if (res == NSERROR_OK) {
|
||||
res = browser_window_navigate(target,
|
||||
action_url,
|
||||
page_url,
|
||||
BW_NAVIGATE_HISTORY,
|
||||
data,
|
||||
NULL,
|
||||
NULL);
|
||||
free(data);
|
||||
}
|
||||
|
||||
browser_window_navigate(target,
|
||||
action_url,
|
||||
page_url,
|
||||
BW_NAVIGATE_HISTORY,
|
||||
data,
|
||||
NULL,
|
||||
NULL);
|
||||
break;
|
||||
|
||||
case method_POST_MULTIPART:
|
||||
browser_window_navigate(target,
|
||||
action_url,
|
||||
page_url,
|
||||
BW_NAVIGATE_HISTORY,
|
||||
NULL,
|
||||
success,
|
||||
NULL);
|
||||
res = browser_window_navigate(target,
|
||||
action_url,
|
||||
page_url,
|
||||
BW_NAVIGATE_HISTORY,
|
||||
NULL,
|
||||
success,
|
||||
NULL);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
nsurl_unref(action_url);
|
||||
fetch_multipart_data_destroy(success);
|
||||
free(data);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void form_gadget_update_value(struct form_control *control, char *value)
|
||||
|
@ -194,29 +194,6 @@ bool form_successful_controls(struct form *form,
|
||||
struct form_control *submit_button,
|
||||
struct fetch_multipart_data **successful_controls);
|
||||
|
||||
/**
|
||||
* Identify 'successful' controls via the DOM.
|
||||
*
|
||||
* All text strings in the successful controls list will be in the charset most
|
||||
* appropriate for submission. Therefore, no utf8_to_* processing should be
|
||||
* performed upon them.
|
||||
*
|
||||
* \todo The chosen charset needs to be made available such that it can be
|
||||
* included in the submission request (e.g. in the fetch's Content-Type header)
|
||||
*
|
||||
* See HTML 4.01 section 17.13.2.
|
||||
*
|
||||
* \param[in] form form to search for successful controls
|
||||
* \param[in] submit_button control used to submit the form, if any
|
||||
* \param[out] successful_controls updated to point to linked list of
|
||||
* fetch_multipart_data, 0 if no controls
|
||||
* \return true on success, false on memory exhaustion
|
||||
*/
|
||||
bool form_successful_controls_dom(struct form *form,
|
||||
struct form_control *submit_button,
|
||||
struct fetch_multipart_data **successful_controls);
|
||||
|
||||
|
||||
/**
|
||||
* Open a select menu for a select form control, creating it if necessary.
|
||||
*
|
||||
@ -268,8 +245,18 @@ void form_select_mouse_drag_end(struct form_control *control,
|
||||
enum browser_mouse_state mouse, int x, int y);
|
||||
void form_select_get_dimensions(struct form_control *control,
|
||||
int *width, int *height);
|
||||
void form_submit(struct nsurl *page_url, struct browser_window *target,
|
||||
|
||||
/**
|
||||
* navigate browser window based on form submission.
|
||||
*
|
||||
* \param page_url content url
|
||||
* \param target The browsing context in which the navigation will occour.
|
||||
* \param form The form to submit.
|
||||
* \param submit_button The control used to submit the form.
|
||||
*/
|
||||
nserror form_submit(struct nsurl *page_url, struct browser_window *target,
|
||||
struct form *form, struct form_control *submit_button);
|
||||
|
||||
void form_radio_set(struct form_control *radio);
|
||||
|
||||
void form_gadget_update_value(struct form_control *control, char *value);
|
||||
|
@ -389,6 +389,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
|
||||
BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2 |
|
||||
BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2);
|
||||
|
||||
nserror res;
|
||||
|
||||
if (drag_type != DRAGGING_NONE && !mouse &&
|
||||
html->visible_select_menu != NULL) {
|
||||
/* drag end: select menu */
|
||||
@ -875,9 +877,12 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
|
||||
}
|
||||
} else if (url) {
|
||||
if (nsoption_bool(display_decoded_idn) == true) {
|
||||
if (nsurl_get_utf8(url, &url_s, &url_l) != NSERROR_OK) {
|
||||
/* Unable to obtain a decoded IDN. This is not a fatal error.
|
||||
* Ensure the string pointer is NULL so we use the encoded version. */
|
||||
res = nsurl_get_utf8(url, &url_s, &url_l);
|
||||
if (res != NSERROR_OK) {
|
||||
/* Unable to obtain a decoded IDN. This is not
|
||||
* a fatal error. Ensure the string pointer
|
||||
* is NULL so we use the encoded version.
|
||||
*/
|
||||
url_s = NULL;
|
||||
}
|
||||
}
|
||||
@ -1072,22 +1077,32 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
|
||||
*/
|
||||
switch (action) {
|
||||
case ACTION_SUBMIT:
|
||||
form_submit(content_get_url(c),
|
||||
browser_window_find_target(bw, target, mouse),
|
||||
gadget->form, gadget);
|
||||
res = form_submit(content_get_url(c),
|
||||
browser_window_find_target(bw, target, mouse),
|
||||
gadget->form,
|
||||
gadget);
|
||||
break;
|
||||
|
||||
case ACTION_GO:
|
||||
browser_window_navigate(browser_window_find_target(bw, target, mouse),
|
||||
url,
|
||||
content_get_url(c),
|
||||
BW_NAVIGATE_HISTORY,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
res = browser_window_navigate(
|
||||
browser_window_find_target(bw, target, mouse),
|
||||
url,
|
||||
content_get_url(c),
|
||||
BW_NAVIGATE_HISTORY,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
break;
|
||||
|
||||
case ACTION_NONE:
|
||||
res = NSERROR_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
if (res != NSERROR_OK) {
|
||||
guit->misc->warning(messages_get_errorcode(res), NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user