summaryrefslogtreecommitdiff
path: root/content/handlers/html/form.c
diff options
context:
space:
mode:
Diffstat (limited to 'content/handlers/html/form.c')
-rw-r--r--content/handlers/html/form.c1439
1 files changed, 883 insertions, 556 deletions
diff --git a/content/handlers/html/form.c b/content/handlers/html/form.c
index f779f07bd..5a915b84e 100644
--- a/content/handlers/html/form.c
+++ b/content/handlers/html/form.c
@@ -326,622 +326,946 @@ bool form_add_option(struct form_control *control, char *value, char *text,
return true;
}
+/** string allocation size for numeric values in multipart data */
+#define FETCH_DATA_INT_VALUE_SIZE 20
/**
- * Identify 'successful' controls via the DOM.
+ * append split key name and integer value to a multipart data list
*
- * 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
+ * \param name key name
+ * \param ksfx key name suffix
+ * \param value The value to encode
+ * \param fetch_data_next_ptr The multipart data list to append to.
*/
static nserror
-form_successful_controls_dom(struct form *_form,
- struct form_control *_submit_button,
- struct fetch_multipart_data **successful_controls)
+fetch_data_list_add_sname(const char *name,
+ const char *ksfx,
+ int value,
+ struct fetch_multipart_data ***fetch_data_next_ptr)
{
- dom_html_form_element *form = _form->node;
- dom_html_element *submit_button = (_submit_button != NULL) ? _submit_button->node : NULL;
- dom_html_collection *form_elements = NULL;
- dom_html_options_collection *options = NULL;
- dom_node *form_element = NULL, *option_element = NULL;
- dom_exception err;
- dom_string *nodename = NULL, *inputname = NULL, *inputvalue = NULL, *inputtype = NULL;
- struct fetch_multipart_data sentinel, *last_success, *success_new;
- bool had_submit = false, element_disabled, checked;
- char *charset, *rawfile_temp = NULL, *basename;
- uint32_t index, element_count;
- struct image_input_coords *coords;
+ struct fetch_multipart_data *fetch_data;
+ int keysize;
- last_success = &sentinel;
- sentinel.next = NULL;
+ fetch_data = calloc(1, sizeof(*fetch_data));
+ if (fetch_data == NULL) {
+ NSLOG(netsurf, INFO, "failed allocation for fetch data");
+ return NSERROR_NOMEM;
+ }
- /** \todo Replace this call with something DOMish */
- charset = form_acceptable_charset(_form);
- if (charset == NULL) {
- NSLOG(netsurf, INFO, "failed to find charset");
+ /* key name */
+ keysize = snprintf(fetch_data->name, 0, "%s%s", name, ksfx);
+ fetch_data->name = malloc(keysize + 1); /* allow for null */
+ if (fetch_data->name == NULL) {
+ free(fetch_data);
+ NSLOG(netsurf, INFO,
+ "keyname allocation failure for %s%s", name, ksfx);
return NSERROR_NOMEM;
}
+ snprintf(fetch_data->name, keysize + 1, "%s%s", name, ksfx);
+
+ /* value */
+ fetch_data->value = malloc(FETCH_DATA_INT_VALUE_SIZE);
+ if (fetch_data->value == NULL) {
+ free(fetch_data->name);
+ free(fetch_data);
+ NSLOG(netsurf, INFO, "value allocation failure");
+ return NSERROR_NOMEM;
+ }
+ snprintf(fetch_data->value, FETCH_DATA_INT_VALUE_SIZE, "%d", value);
-#define ENCODE_ITEM(i) (((i) == NULL) ? ( \
- form_encode_item("", 0, charset, _form->document_charset) \
- ):( \
- form_encode_item(dom_string_data(i), dom_string_byte_length(i), \
- charset, _form->document_charset) \
- ))
+ /* link into list */
+ **fetch_data_next_ptr = fetch_data;
+ *fetch_data_next_ptr = &fetch_data->next;
- err = dom_html_form_element_get_elements(form, &form_elements);
+ return NSERROR_OK;
+}
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO, "Could not get form elements");
- goto dom_no_memory;
- }
+/**
+ * append DOM string name/value pair to a multipart data list
+ *
+ * \param name key name
+ * \param value the value to associate with the key
+ * \param rawfile the raw file value to associate with the key.
+ * \param form_charset The form character set
+ * \param docu_charset The document character set for fallback
+ * \param fetch_data_next_ptr The multipart data list being constructed.
+ * \return NSERROR_OK on success or appropriate error code.
+ */
+static nserror
+fetch_data_list_add(dom_string *name,
+ dom_string *value,
+ const char *rawfile,
+ const char *form_charset,
+ const char *docu_charset,
+ struct fetch_multipart_data ***fetch_data_next_ptr)
+{
+ struct fetch_multipart_data *fetch_data;
- err = dom_html_collection_get_length(form_elements, &element_count);
+ assert(name != NULL);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO, "Could not get form element count");
- goto dom_no_memory;
+ fetch_data = calloc(1, sizeof(*fetch_data));
+ if (fetch_data == NULL) {
+ NSLOG(netsurf, INFO, "failed allocation for fetch data");
+ return NSERROR_NOMEM;
}
- for (index = 0; index < element_count; index++) {
- if (form_element != NULL) {
- dom_node_unref(form_element);
- form_element = NULL;
- }
- if (nodename != NULL) {
- dom_string_unref(nodename);
- nodename = NULL;
- }
- if (inputname != NULL) {
- dom_string_unref(inputname);
- inputname = NULL;
- }
- if (inputvalue != NULL) {
- dom_string_unref(inputvalue);
- inputvalue = NULL;
- }
- if (inputtype != NULL) {
- dom_string_unref(inputtype);
- inputtype = NULL;
- }
- if (options != NULL) {
- dom_html_options_collection_unref(options);
- options = NULL;
- }
- err = dom_html_collection_item(form_elements,
- index, &form_element);
- if (err != DOM_NO_ERR) {
+ fetch_data->name = form_encode_item(dom_string_data(name),
+ dom_string_byte_length(name),
+ form_charset,
+ docu_charset);
+ if (fetch_data->name == NULL) {
+ NSLOG(netsurf, INFO, "Could not encode name for fetch data");
+ free(fetch_data);
+ return NSERROR_NOMEM;
+ }
+
+ if (value == NULL) {
+ fetch_data->value = strdup("");
+ } else {
+ fetch_data->value = form_encode_item(dom_string_data(value),
+ dom_string_byte_length(value),
+ form_charset,
+ docu_charset);
+ }
+ if (fetch_data->value == NULL) {
+ NSLOG(netsurf, INFO, "Could not encode value for fetch data");
+ free(fetch_data->name);
+ free(fetch_data);
+ return NSERROR_NOMEM;
+ }
+
+ /* deal with raw file name */
+ if (rawfile != NULL) {
+ fetch_data->file = true;
+ fetch_data->rawfile = strdup(rawfile);
+ if (fetch_data->rawfile == NULL) {
NSLOG(netsurf, INFO,
- "Could not retrieve form element %d", index);
- goto dom_no_memory;
+ "Could not encode rawfile value for fetch data");
+ free(fetch_data->value);
+ free(fetch_data->name);
+ free(fetch_data);
+ return NSERROR_NOMEM;
}
+ }
- /* Form elements are one of:
- * HTMLButtonElement
- * HTMLInputElement
- * HTMLTextAreaElement
- * HTMLSelectElement
- */
- err = dom_node_get_node_name(form_element, &nodename);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO, "Could not get node name");
- goto dom_no_memory;
- }
+ /* link into list */
+ **fetch_data_next_ptr = fetch_data;
+ *fetch_data_next_ptr = &fetch_data->next;
- if (dom_string_isequal(nodename, corestring_dom_TEXTAREA)) {
- err = dom_html_text_area_element_get_disabled(
- (dom_html_text_area_element *)form_element,
- &element_disabled);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get text area disabled property");
- goto dom_no_memory;
- }
- err = dom_html_text_area_element_get_name(
- (dom_html_text_area_element *)form_element,
- &inputname);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get text area name property");
- goto dom_no_memory;
- }
- } else if (dom_string_isequal(nodename, corestring_dom_SELECT)) {
- err = dom_html_select_element_get_disabled(
- (dom_html_select_element *)form_element,
- &element_disabled);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get select disabled property");
- goto dom_no_memory;
- }
- err = dom_html_select_element_get_name(
- (dom_html_select_element *)form_element,
- &inputname);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get select name property");
- goto dom_no_memory;
- }
- } else if (dom_string_isequal(nodename, corestring_dom_INPUT)) {
- err = dom_html_input_element_get_disabled(
- (dom_html_input_element *)form_element,
- &element_disabled);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get input disabled property");
- goto dom_no_memory;
- }
- err = dom_html_input_element_get_name(
- (dom_html_input_element *)form_element,
- &inputname);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get input name property");
- goto dom_no_memory;
- }
- } else if (dom_string_isequal(nodename, corestring_dom_BUTTON)) {
- err = dom_html_button_element_get_disabled(
- (dom_html_button_element *)form_element,
- &element_disabled);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get button disabled property");
- goto dom_no_memory;
- }
- err = dom_html_button_element_get_name(
- (dom_html_button_element *)form_element,
- &inputname);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get button name property");
- goto dom_no_memory;
- }
- } else {
- /* Unknown element type came through! */
- NSLOG(netsurf, INFO, "Unknown element type: %*s",
- (int)dom_string_byte_length(nodename),
- dom_string_data(nodename));
- goto dom_no_memory;
- }
- if (element_disabled)
- continue;
- if (inputname == NULL)
- continue;
+ return NSERROR_OK;
+}
- if (dom_string_isequal(nodename, corestring_dom_TEXTAREA)) {
- err = dom_html_text_area_element_get_value(
- (dom_html_text_area_element *)form_element,
- &inputvalue);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get text area content");
- goto dom_no_memory;
- }
- } else if (dom_string_isequal(nodename, corestring_dom_SELECT)) {
- uint32_t options_count, option_index;
- err = dom_html_select_element_get_options(
- (dom_html_select_element *)form_element,
- &options);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get select options collection");
- goto dom_no_memory;
- }
- err = dom_html_options_collection_get_length(
- options, &options_count);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get select options collection length");
- goto dom_no_memory;
- }
- for(option_index = 0; option_index < options_count;
- ++option_index) {
- bool selected;
- if (option_element != NULL) {
- dom_node_unref(option_element);
- option_element = NULL;
- }
- if (inputvalue != NULL) {
- dom_string_unref(inputvalue);
- inputvalue = NULL;
- }
- err = dom_html_options_collection_item(
- options, option_index, &option_element);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get options item %d",
- option_index);
- goto dom_no_memory;
- }
- err = dom_html_option_element_get_selected(
- (dom_html_option_element *)option_element,
- &selected);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get option selected property");
- goto dom_no_memory;
- }
- if (!selected)
- continue;
- err = dom_html_option_element_get_value(
- (dom_html_option_element *)option_element,
- &inputvalue);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get option value");
- goto dom_no_memory;
- }
+/**
+ * process form HTMLTextAreaElement into multipart data.
+ *
+ * \param text_area_element The form select DOM element to convert.
+ * \param form_charset The form character set
+ * \param doc_charset The document character set for fallback
+ * \param fetch_data_next_ptr The multipart data list being constructed.
+ * \return NSERROR_OK on success or appropriate error code.
+ */
+static nserror
+form_dom_to_data_textarea(dom_html_text_area_element *text_area_element,
+ const char *form_charset,
+ const char *doc_charset,
+ struct fetch_multipart_data ***fetch_data_next_ptr)
+{
+ dom_exception exp; /* the result from DOM operations */
+ bool element_disabled;
+ dom_string *inputname;
+ dom_string *inputvalue;
+ nserror res;
- success_new = calloc(1, sizeof(*success_new));
- if (success_new == NULL) {
- NSLOG(netsurf, INFO,
- "Could not allocate data for option");
- goto dom_no_memory;
- }
+ /* check if element is disabled */
+ exp = dom_html_text_area_element_get_disabled(text_area_element,
+ &element_disabled);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO,
+ "Could not get text area disabled property. exp %d", exp);
+ return NSERROR_DOM;
+ }
- last_success->next = success_new;
- last_success = success_new;
+ if (element_disabled) {
+ /* allow enumeration to continue after disabled element */
+ return NSERROR_OK;
+ }
- success_new->name = ENCODE_ITEM(inputname);
- if (success_new->name == NULL) {
- NSLOG(netsurf, INFO,
- "Could not encode name for option");
- goto dom_no_memory;
- }
- success_new->value = ENCODE_ITEM(inputvalue);
- if (success_new->value == NULL) {
- NSLOG(netsurf, INFO,
- "Could not encode value for option");
- goto dom_no_memory;
- }
- }
- continue;
- } else if (dom_string_isequal(nodename, corestring_dom_BUTTON)) {
- err = dom_html_button_element_get_type(
- (dom_html_button_element *) form_element,
- &inputtype);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get button element type");
- goto dom_no_memory;
- }
- if (dom_string_caseless_isequal(
- inputtype, corestring_dom_submit)) {
-
- if (submit_button == NULL && !had_submit) {
- /* no button used, and first submit
- * node found, so use it
- */
- had_submit = true;
- } else if ((dom_node *)submit_button !=
- (dom_node *)form_element) {
- continue;
- }
+ /* obtain name property */
+ exp = dom_html_text_area_element_get_name(text_area_element,
+ &inputname);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO,
+ "Could not get text area name property. exp %d", exp);
+ return NSERROR_DOM;
+ }
- err = dom_html_button_element_get_value(
- (dom_html_button_element *)form_element,
- &inputvalue);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get submit button value");
- goto dom_no_memory;
- }
- /* Drop through to report successful button */
- } else {
- continue;
- }
- } else if (dom_string_isequal(nodename, corestring_dom_INPUT)) {
- /* Things to consider here */
- /* Buttons -- only if the successful control */
- /* radio and checkbox -- only if selected */
- /* file -- also get the rawfile */
- /* everything else -- just value */
- err = dom_html_input_element_get_type(
- (dom_html_input_element *) form_element,
- &inputtype);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get input element type");
- goto dom_no_memory;
- }
- if (dom_string_caseless_isequal(
- inputtype, corestring_dom_submit)) {
-
- if (submit_button == NULL && !had_submit) {
- /* no button used, and first submit
- * node found, so use it
- */
- had_submit = true;
- } else if ((dom_node *)submit_button !=
- (dom_node *)form_element) {
- continue;
- }
+ if (inputname == NULL) {
+ /* allow enumeration to continue after element with no name */
+ return NSERROR_OK;
+ }
- err = dom_html_input_element_get_value(
- (dom_html_input_element *)form_element,
- &inputvalue);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get submit button value");
- goto dom_no_memory;
- }
- /* Drop through to report the successful button */
- } else if (dom_string_caseless_isequal(
- inputtype, corestring_dom_image)) {
- /* We *ONLY* use an image input if it was the
- * thing which activated us
- */
- if ((dom_node *)submit_button !=
- (dom_node *)form_element)
- continue;
-
- err = dom_node_get_user_data(
- form_element,
- corestring_dom___ns_key_image_coords_node_data,
- &coords);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get image XY data");
- goto dom_no_memory;
- }
- if (coords == NULL) {
- NSLOG(netsurf, INFO,
- "No XY data on the image input");
- goto dom_no_memory;
- }
-
- 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) {
- free(basename);
- NSLOG(netsurf, INFO,
- "Could not allocate data for image.x");
- goto dom_no_memory;
- }
-
- last_success->next = success_new;
- last_success = success_new;
-
- success_new->name = malloc(strlen(basename) + 3);
- if (success_new->name == NULL) {
- free(basename);
- NSLOG(netsurf, INFO,
- "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);
- NSLOG(netsurf, INFO,
- "Could not allocate value for image.x");
- goto dom_no_memory;
- }
- sprintf(success_new->value, "%d", coords->x);
-
- success_new = calloc(1, sizeof(*success_new));
- if (success_new == NULL) {
- free(basename);
- NSLOG(netsurf, INFO,
- "Could not allocate data for image.y");
- goto dom_no_memory;
- }
-
- last_success->next = success_new;
- last_success = success_new;
-
- success_new->name = malloc(strlen(basename) + 3);
- if (success_new->name == NULL) {
- free(basename);
- NSLOG(netsurf, INFO,
- "Could not allocate name for image.y");
- goto dom_no_memory;
- }
- success_new->value = malloc(20);
- if (success_new->value == NULL) {
- free(basename);
- NSLOG(netsurf, INFO,
- "Could not allocate value for image.y");
- goto dom_no_memory;
- }
- sprintf(success_new->name, "%s.y", basename);
- sprintf(success_new->value, "%d", coords->y);
- free(basename);
- continue;
- } else if (dom_string_caseless_isequal(
- inputtype, corestring_dom_radio) ||
- dom_string_caseless_isequal(
- inputtype, corestring_dom_checkbox)) {
- err = dom_html_input_element_get_checked(
- (dom_html_input_element *)form_element,
- &checked);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get input element checked");
- goto dom_no_memory;
- }
- if (!checked)
- continue;
- err = dom_html_input_element_get_value(
- (dom_html_input_element *)form_element,
- &inputvalue);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get input element value");
- goto dom_no_memory;
- }
- if (inputvalue == NULL) {
- inputvalue = dom_string_ref(
- corestring_dom_on);
- }
- /* Fall through to simple allocation */
- } else if (dom_string_caseless_isequal(
- inputtype, corestring_dom_file)) {
-
- err = dom_html_input_element_get_value(
- (dom_html_input_element *)form_element,
- &inputvalue);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get file value");
- goto dom_no_memory;
- }
- err = dom_node_get_user_data(
- form_element,
- corestring_dom___ns_key_file_name_node_data,
- &rawfile_temp);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get file rawname");
- goto dom_no_memory;
- }
- rawfile_temp = strdup(rawfile_temp != NULL ?
- rawfile_temp :
- "");
- if (rawfile_temp == NULL) {
- NSLOG(netsurf, INFO,
- "Could not copy file rawname");
- goto dom_no_memory;
- }
- /* Fall out to the allocation */
- } else if (dom_string_caseless_isequal(
- inputtype, corestring_dom_reset) ||
- dom_string_caseless_isequal(
- inputtype, corestring_dom_button)) {
- /* Skip these */
- NSLOG(netsurf, INFO,
- "Skipping RESET and BUTTON");
- continue;
- } else {
- /* Everything else is treated as text values */
- err = dom_html_input_element_get_value(
- (dom_html_input_element *)form_element,
- &inputvalue);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get input value");
- goto dom_no_memory;
- }
- /* Fall out to the allocation */
- }
- }
+ /* obtain text area value */
+ exp = dom_html_text_area_element_get_value(text_area_element,
+ &inputvalue);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO,
+ "Could not get text area content. exp %d", exp);
+ dom_string_unref(inputname);
+ return NSERROR_DOM;
+ }
- success_new = calloc(1, sizeof(*success_new));
- if (success_new == NULL) {
- NSLOG(netsurf, INFO,
- "Could not allocate data for generic");
- goto dom_no_memory;
- }
+ /* add key/value pair to fetch data list */
+ res = fetch_data_list_add(inputname,
+ inputvalue,
+ NULL,
+ form_charset,
+ doc_charset,
+ fetch_data_next_ptr);
- last_success->next = success_new;
- last_success = success_new;
+ dom_string_unref(inputvalue);
+ dom_string_unref(inputname);
- success_new->name = ENCODE_ITEM(inputname);
- if (success_new->name == NULL) {
- NSLOG(netsurf, INFO,
- "Could not encode name for generic");
- goto dom_no_memory;
- }
- success_new->value = ENCODE_ITEM(inputvalue);
- if (success_new->value == NULL) {
+ return res;
+}
+
+static nserror
+form_dom_to_data_select_option(dom_html_option_element *option_element,
+ dom_string *keyname,
+ const char *form_charset,
+ const char *docu_charset,
+ struct fetch_multipart_data ***fetch_data_next_ptr)
+{
+ nserror res;
+ dom_exception exp; /* the result from DOM operations */
+ dom_string *value;
+ bool selected;
+
+ exp = dom_html_option_element_get_selected(option_element, &selected);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO, "Could not get option selected property");
+ return NSERROR_DOM;
+ }
+
+ if (!selected) {
+ /* unselected options do not add fetch data entries */
+ return NSERROR_OK;
+ }
+
+ exp = dom_html_option_element_get_value(option_element, &value);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO, "Could not get option value");
+ return NSERROR_DOM;
+ }
+
+ /* add key/value pair to fetch data list */
+ res = fetch_data_list_add(keyname,
+ value,
+ NULL,
+ form_charset,
+ docu_charset,
+ fetch_data_next_ptr);
+
+ dom_string_unref(value);
+
+ return res;
+}
+
+/**
+ * process form HTMLSelectElement into multipart data.
+ *
+ * \param select_element The form select DOM element to convert.
+ * \param form_charset The form character set
+ * \param doc_charset The document character set for fallback
+ * \param fetch_data_next_ptr The multipart data list being constructed.
+ * \return NSERROR_OK on success or appropriate error code.
+ */
+static nserror
+form_dom_to_data_select(dom_html_select_element *select_element,
+ const char *form_charset,
+ const char *doc_charset,
+ struct fetch_multipart_data ***fetch_data_next_ptr)
+{
+ nserror res = NSERROR_OK;
+ dom_exception exp; /* the result from DOM operations */
+ bool element_disabled;
+ dom_string *inputname;
+ dom_html_options_collection *options = NULL;
+ uint32_t options_count;
+ uint32_t option_index;
+ dom_node *option_element = NULL;
+
+ /* check if element is disabled */
+ exp = dom_html_select_element_get_disabled(select_element,
+ &element_disabled);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO,
+ "Could not get select disabled property. exp %d", exp);
+ return NSERROR_DOM;
+ }
+
+ if (element_disabled) {
+ /* allow enumeration to continue after disabled element */
+ return NSERROR_OK;
+ }
+
+ /* obtain name property */
+ exp = dom_html_select_element_get_name(select_element, &inputname);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO,
+ "Could not get select name property. exp %d", exp);
+ return NSERROR_DOM;
+ }
+
+ if (inputname == NULL) {
+ /* allow enumeration to continue after element with no name */
+ return NSERROR_OK;
+ }
+
+ /* get options collection */
+ exp = dom_html_select_element_get_options(select_element, &options);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO,
+ "Could not get select options collection");
+ dom_string_unref(inputname);
+ return NSERROR_DOM;
+ }
+
+ /* get options collection length */
+ exp = dom_html_options_collection_get_length(options, &options_count);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO,
+ "Could not get select options collection length");
+ dom_html_options_collection_unref(options);
+ dom_string_unref(inputname);
+ return NSERROR_DOM;
+ }
+
+ /* iterate over options collection */
+ for (option_index = 0; option_index < options_count; ++option_index) {
+ exp = dom_html_options_collection_item(options,
+ option_index,
+ &option_element);
+ if (exp != DOM_NO_ERR) {
NSLOG(netsurf, INFO,
- "Could not encode value for generic");
- goto dom_no_memory;
+ "Could not get options item %d", option_index);
+ res = NSERROR_DOM;
+ } else {
+ res = form_dom_to_data_select_option(
+ (dom_html_option_element *)option_element,
+ inputname,
+ form_charset,
+ doc_charset,
+ fetch_data_next_ptr);
+
+ dom_node_unref(option_element);
}
- if (rawfile_temp != NULL) {
- success_new->file = true;
- success_new->rawfile = rawfile_temp;
- rawfile_temp = NULL;
+
+ if (res != NSERROR_OK) {
+ break;
}
}
- free(charset);
+ dom_html_options_collection_unref(options);
+ dom_string_unref(inputname);
+
+ return res;
+}
- if (form_element != NULL) {
- dom_node_unref(form_element);
+static nserror
+form_dom_to_data_input_submit(dom_html_input_element *input_element,
+ dom_string *inputname,
+ const char *charset,
+ const char *document_charset,
+ dom_html_element **submit_button,
+ struct fetch_multipart_data ***fetch_data_next_ptr)
+{
+ dom_exception exp; /* the result from DOM operations */
+ dom_string *inputvalue;
+ nserror res;
+
+ if (*submit_button == NULL) {
+ /* caller specified no button so use this one */
+ *submit_button = (dom_html_element *)input_element;
+ } else if (*submit_button != (dom_html_element *)input_element) {
+ return NSERROR_OK;
}
- if (form_elements != NULL) {
- dom_html_collection_unref(form_elements);
+ /* matched button used to submit form */
+ exp = dom_html_input_element_get_value(input_element, &inputvalue);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO, "Could not get submit button value");
+ return NSERROR_DOM;
}
- if (nodename != NULL) {
- dom_string_unref(nodename);
+ /* add key/value pair to fetch data list */
+ res = fetch_data_list_add(inputname,
+ inputvalue,
+ NULL,
+ charset,
+ document_charset,
+ fetch_data_next_ptr);
+
+ dom_string_unref(inputvalue);
+
+ return res;
+}
+
+
+
+static nserror
+form_dom_to_data_input_image(dom_html_input_element *input_element,
+ dom_string *inputname,
+ const char *charset,
+ const char *document_charset,
+ dom_html_element **submit_button,
+ struct fetch_multipart_data ***fetch_data_next_ptr)
+{
+ nserror res;
+ dom_exception exp; /* the result from DOM operations */
+ struct image_input_coords *coords;
+ char *basename;
+
+ /* Only use an image input if it was the thing which activated us */
+ if (*submit_button != (dom_html_element *)input_element) {
+ return NSERROR_OK;
+ }
+
+ exp = dom_node_get_user_data((dom_node *)input_element,
+ corestring_dom___ns_key_image_coords_node_data,
+ &coords);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO, "Could not get image XY data");
+ return NSERROR_DOM;
+ }
+
+ if (coords == NULL) {
+ NSLOG(netsurf, INFO, "No XY data on the image input");
+ return NSERROR_DOM;
+ }
+
+ /* encode input name once */
+ basename = form_encode_item(dom_string_data(inputname),
+ dom_string_byte_length(inputname),
+ charset,
+ document_charset);
+ if (basename == NULL) {
+ NSLOG(netsurf, INFO, "Could not encode basename");
+ return NSERROR_NOMEM;
+ }
+
+ res = fetch_data_list_add_sname(basename, ".x",
+ coords->x,
+ fetch_data_next_ptr);
+
+ if (res == NSERROR_OK) {
+ res = fetch_data_list_add_sname(basename, ".y",
+ coords->y,
+ fetch_data_next_ptr);
+ }
+
+ free(basename);
+
+ return res;
+}
+
+static nserror
+form_dom_to_data_input_checkbox(dom_html_input_element *input_element,
+ dom_string *inputname,
+ const char *charset,
+ const char *document_charset,
+ struct fetch_multipart_data ***fetch_data_next_ptr)
+{
+ nserror res;
+ dom_exception exp; /* the result from DOM operations */
+ bool checked;
+ dom_string *inputvalue;
+
+ exp = dom_html_input_element_get_checked(input_element, &checked);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO,
+ "Could not get input element checked");
+ return NSERROR_DOM;
+ }
+
+ if (!checked) {
+ /* unchecked items do not generate a data entry */
+ return NSERROR_OK;
+ }
+
+ exp = dom_html_input_element_get_value(input_element, &inputvalue);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO,
+ "Could not get input element value");
+ return NSERROR_DOM;
+ }
+
+ /* ensure a default value */
+ if (inputvalue == NULL) {
+ inputvalue = dom_string_ref(corestring_dom_on);
+ }
+
+ /* add key/value pair to fetch data list */
+ res = fetch_data_list_add(inputname,
+ inputvalue,
+ NULL,
+ charset,
+ document_charset,
+ fetch_data_next_ptr);
+
+ dom_string_unref(inputvalue);
+
+ return res;
+}
+
+static nserror
+form_dom_to_data_input_file(dom_html_input_element *input_element,
+ dom_string *inputname,
+ const char *charset,
+ const char *document_charset,
+ struct fetch_multipart_data ***fetch_data_next_ptr)
+{
+ nserror res;
+ dom_exception exp; /* the result from DOM operations */
+ dom_string *inputvalue;
+ const char *rawfile = NULL;
+
+ exp = dom_html_input_element_get_value(input_element, &inputvalue);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO, "Could not get file value");
+ return NSERROR_DOM;
+ }
+
+ exp = dom_node_get_user_data((dom_node *)input_element,
+ corestring_dom___ns_key_file_name_node_data,
+ &rawfile);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO, "Could not get file rawname");
+ return NSERROR_DOM;
}
- if (inputname != NULL) {
+ if (rawfile == NULL) {
+ rawfile = "";
+ }
+
+ /* add key/value pair to fetch data list */
+ res = fetch_data_list_add(inputname,
+ inputvalue,
+ rawfile,
+ charset,
+ document_charset,
+ fetch_data_next_ptr);
+
+ dom_string_unref(inputvalue);
+
+ return res;
+}
+
+static nserror
+form_dom_to_data_input_text(dom_html_input_element *input_element,
+ dom_string *inputname,
+ const char *charset,
+ const char *document_charset,
+ struct fetch_multipart_data ***fetch_data_next_ptr)
+{
+ nserror res;
+ dom_exception exp; /* the result from DOM operations */
+ dom_string *inputvalue;
+
+ exp = dom_html_input_element_get_value(input_element, &inputvalue);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO, "Could not get input value");
+ return NSERROR_DOM;
+ }
+
+ /* add key/value pair to fetch data list */
+ res = fetch_data_list_add(inputname,
+ inputvalue,
+ NULL,
+ charset,
+ document_charset,
+ fetch_data_next_ptr);
+
+ dom_string_unref(inputvalue);
+
+ return res;
+}
+
+/**
+ * process form input element into multipart data.
+ *
+ * \param input_element The form input DOM element to convert.
+ * \param charset The form character set
+ * \param document_charset The document character set for fallback
+ * \param submit_button The DOM element of the button submitting the form
+ * \param had_submit A boolean value indicating if the submit button
+ * has already been processed in the form element enumeration.
+ * \param fetch_data_next_ptr The multipart data list being constructed.
+ * \return NSERROR_OK on success or appropriate error code.
+ */
+static nserror
+form_dom_to_data_input(dom_html_input_element *input_element,
+ const char *charset,
+ const char *document_charset,
+ dom_html_element **submit_button,
+ struct fetch_multipart_data ***fetch_data_next_ptr)
+{
+ dom_exception exp; /* the result from DOM operations */
+ bool element_disabled;
+ dom_string *inputname;
+ dom_string *inputtype;
+ nserror res;
+
+ /* check if element is disabled */
+ exp = dom_html_input_element_get_disabled(input_element,
+ &element_disabled);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO,
+ "Could not get input disabled property. exp %d", exp);
+ return NSERROR_DOM;
+ }
+
+ if (element_disabled) {
+ /* disabled element requires no more processing */
+ return NSERROR_OK;
+ }
+
+ /* obtain name property */
+ exp = dom_html_input_element_get_name(input_element, &inputname);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO,
+ "Could not get input name property. exp %d", exp);
+ return NSERROR_DOM;
+ }
+
+ if (inputname == NULL) {
+ /* element with no name is not converted */
+ return NSERROR_OK;
+ }
+
+ /* get input type */
+ exp = dom_html_input_element_get_type(input_element, &inputtype);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO, "Could not get input element type");
dom_string_unref(inputname);
+ return NSERROR_DOM;
}
- if (inputvalue != NULL) {
- dom_string_unref(inputvalue);
+ /* process according to input element type */
+ if (dom_string_caseless_isequal(inputtype, corestring_dom_submit)) {
+
+ res = form_dom_to_data_input_submit(input_element,
+ inputname,
+ charset,
+ document_charset,
+ submit_button,
+ fetch_data_next_ptr);
+
+ } else if (dom_string_caseless_isequal(inputtype,
+ corestring_dom_image)) {
+
+ res = form_dom_to_data_input_image(input_element,
+ inputname,
+ charset,
+ document_charset,
+ submit_button,
+ fetch_data_next_ptr);
+
+ } else if (dom_string_caseless_isequal(inputtype,
+ corestring_dom_radio) ||
+ dom_string_caseless_isequal(inputtype,
+ corestring_dom_checkbox)) {
+
+ res = form_dom_to_data_input_checkbox(input_element,
+ inputname,
+ charset,
+ document_charset,
+ fetch_data_next_ptr);
+
+ } else if (dom_string_caseless_isequal(inputtype,
+ corestring_dom_file)) {
+
+ res = form_dom_to_data_input_file(input_element,
+ inputname,
+ charset,
+ document_charset,
+ fetch_data_next_ptr);
+
+ } else if (dom_string_caseless_isequal(inputtype,
+ corestring_dom_reset) ||
+ dom_string_caseless_isequal(inputtype,
+ corestring_dom_button)) {
+ /* Skip these */
+ NSLOG(netsurf, INFO, "Skipping RESET and BUTTON");
+ res = NSERROR_OK;
+
+ } else {
+ /* Everything else is treated as text values */
+ res = form_dom_to_data_input_text(input_element,
+ inputname,
+ charset,
+ document_charset,
+ fetch_data_next_ptr);
+
}
- if (options != NULL) {
- dom_html_options_collection_unref(options);
+ dom_string_unref(inputtype);
+ dom_string_unref(inputname);
+
+ return res;
+}
+
+/**
+ * process form HTMLButtonElement into multipart data.
+ *
+ * \param button_element The form button DOM element to convert.
+ * \param form_charset The form character set
+ * \param doc_charset The document character set for fallback
+ * \param submit_button The DOM element of the button submitting the form
+ * \param fetch_data_next_ptr The multipart data list being constructed.
+ * \return NSERROR_OK on success or appropriate error code.
+ */
+static nserror
+form_dom_to_data_button(dom_html_button_element *button_element,
+ const char *form_charset,
+ const char *doc_charset,
+ dom_html_element **submit_button,
+ struct fetch_multipart_data ***fetch_data_next_ptr)
+{
+ dom_exception exp; /* the result from DOM operations */
+ bool element_disabled;
+ dom_string *inputname;
+ dom_string *inputvalue;
+ dom_string *inputtype;
+ nserror res = NSERROR_OK;
+
+ /* check if element is disabled */
+ exp = dom_html_button_element_get_disabled(button_element,
+ &element_disabled);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO,
+ "Unabe to get disabled property. exp %d", exp);
+ return NSERROR_DOM;
+ }
+
+ if (element_disabled) {
+ /* allow enumeration to continue after disabled element */
+ return NSERROR_OK;
}
- if (option_element != NULL) {
- dom_node_unref(option_element);
+ /* only submit buttons can cause data elements */
+ exp = dom_html_button_element_get_type(button_element, &inputtype);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO, "Could not get button element type");
+ return NSERROR_DOM;
}
- if (inputtype != NULL) {
+ if (!dom_string_caseless_isequal(inputtype, corestring_dom_submit)) {
+ /* multipart data entry not required for non submit buttons */
dom_string_unref(inputtype);
+ return NSERROR_OK;
}
+ dom_string_unref(inputtype);
- if (rawfile_temp != NULL) {
- free(rawfile_temp);
+ /* only submision button generates an element */
+ if (*submit_button == NULL) {
+ /* no submission button selected yet so use this one */
+ *submit_button = (dom_html_element *)button_element;
+ }
+ if (*submit_button != (dom_html_element *)button_element) {
+ return NSERROR_OK;
}
- *successful_controls = sentinel.next;
+ /* obtain name property */
+ exp = dom_html_button_element_get_name(button_element, &inputname);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO,
+ "Could not get button name property. exp %d", exp);
+ return NSERROR_DOM;
+ }
- return NSERROR_OK;
+ if (inputname == NULL) {
+ /* allow enumeration to continue after element with no name */
+ return NSERROR_OK;
+ }
-dom_no_memory:
- free(charset);
- fetch_multipart_data_destroy(sentinel.next);
+ /* get button value and add to fetch data list */
+ exp = dom_html_button_element_get_value(button_element, &inputvalue);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO, "Could not get submit button value");
+ res = NSERROR_DOM;
+ } else {
+ res = fetch_data_list_add(inputname,
+ inputvalue,
+ NULL,
+ form_charset,
+ doc_charset,
+ fetch_data_next_ptr);
- if (form_elements != NULL)
- dom_html_collection_unref(form_elements);
- if (form_element != NULL)
- dom_node_unref(form_element);
- if (nodename != NULL)
- dom_string_unref(nodename);
- if (inputname != NULL)
- dom_string_unref(inputname);
- if (inputvalue != NULL)
dom_string_unref(inputvalue);
- if (options != NULL)
- dom_html_options_collection_unref(options);
- if (option_element != NULL)
- dom_node_unref(option_element);
- if (inputtype != NULL)
- dom_string_unref(inputtype);
- if (rawfile_temp != NULL)
- free(rawfile_temp);
+ }
+
+ dom_string_unref(inputname);
+
+ return res;
+}
+
- return NSERROR_NOMEM;
+/**
+ * Construct multipart data list from '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.
+ *
+ * \note care is taken to abort even if the error is recoverable as it
+ * is not desirable to submit incomplete form data.
+ *
+ * \param[in] form form to search for successful controls
+ * \param[in] submit_button control used to submit the form, if any
+ * \param[out] fetch_data_out 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_dom_to_data(struct form *form,
+ struct form_control *submit_control,
+ struct fetch_multipart_data **fetch_data_out)
+{
+ nserror res = NSERROR_OK;
+ char *charset; /* form characterset */
+ dom_exception exp; /* the result from DOM operations */
+ dom_html_collection *elements = NULL; /* the dom form elements */
+ uint32_t element_count; /* the number of elements in the DOM form */
+ uint32_t element_idx; /* the index of thr enumerated element */
+ dom_node *element = NULL; /* the DOM form element */
+ dom_string *nodename = NULL; /* the DOM node name of the element */
+ struct fetch_multipart_data *fetch_data = NULL; /* fetch data list */
+ struct fetch_multipart_data **fetch_data_next = &fetch_data;
+ dom_html_element *submit_button;
+
+ /* obtain the submit_button DOM node from the control */
+ if (submit_control != NULL) {
+ submit_button = submit_control->node;
+ } else {
+ submit_button = NULL;
+ }
+
+ /** \todo Replace this call with something DOMish */
+ charset = form_acceptable_charset(form);
+ if (charset == NULL) {
+ NSLOG(netsurf, INFO, "failed to find charset");
+ return NSERROR_NOMEM;
+ }
+
+ /* obtain the form elements and count */
+ exp = dom_html_form_element_get_elements(form->node, &elements);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO, "Could not get form elements");
+ free(charset);
+ return NSERROR_DOM;
+ }
+
+ exp = dom_html_collection_get_length(elements, &element_count);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO, "Could not get form element count");
+ res = NSERROR_DOM;
+ goto form_dom_to_data_error;
+ }
+
+ for (element_idx = 0; element_idx < element_count; element_idx++) {
+ /* obtain a form element */
+ exp = dom_html_collection_item(elements, element_idx, &element);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO,
+ "retrieving form element %d failed with %d",
+ element_idx, exp);
+ res = NSERROR_DOM;
+ goto form_dom_to_data_error;
+ }
+
+ /* node name from element */
+ exp = dom_node_get_node_name(element, &nodename);
+ if (exp != DOM_NO_ERR) {
+ NSLOG(netsurf, INFO,
+ "getting element node name %d failed with %d",
+ element_idx, exp);
+ dom_node_unref(element);
+ res = NSERROR_DOM;
+ goto form_dom_to_data_error;
+ }
+
+ if (dom_string_isequal(nodename, corestring_dom_TEXTAREA)) {
+ /* Form element is HTMLTextAreaElement */
+ res = form_dom_to_data_textarea(
+ (dom_html_text_area_element *)element,
+ charset,
+ form->document_charset,
+ &fetch_data_next);
+
+ } else if (dom_string_isequal(nodename, corestring_dom_SELECT)) {
+ /* Form element is HTMLSelectElement */
+ res = form_dom_to_data_select(
+ (dom_html_select_element *)element,
+ charset,
+ form->document_charset,
+ &fetch_data_next);
+
+ } else if (dom_string_isequal(nodename, corestring_dom_INPUT)) {
+ /* Form element is HTMLInputElement */
+ res = form_dom_to_data_input(
+ (dom_html_input_element *)element,
+ charset,
+ form->document_charset,
+ &submit_button,
+ &fetch_data_next);
+
+ } else if (dom_string_isequal(nodename, corestring_dom_BUTTON)) {
+ /* Form element is HTMLButtonElement */
+ res = form_dom_to_data_button(
+ (dom_html_button_element *)element,
+ charset,
+ form->document_charset,
+ &submit_button,
+ &fetch_data_next);
+
+ } else {
+ /* Form element is not handled */
+ NSLOG(netsurf, INFO,
+ "Unhandled element type: %*s",
+ (int)dom_string_byte_length(nodename),
+ dom_string_data(nodename));
+ res = NSERROR_DOM;
+
+ }
+
+ dom_string_unref(nodename);
+ dom_node_unref(element);
+
+ /* abort form element enumeration on error */
+ if (res != NSERROR_OK) {
+ goto form_dom_to_data_error;
+ }
+ }
+
+ *fetch_data_out = fetch_data;
+ dom_html_collection_unref(elements);
+ free(charset);
+
+ return NSERROR_OK;
+
+form_dom_to_data_error:
+ fetch_multipart_data_destroy(fetch_data);
+ dom_html_collection_unref(elements);
+ free(charset);
+
+ return res;
}
-#undef ENCODE_ITEM
/**
* Encode controls using application/x-www-form-urlencoded.
@@ -1087,8 +1411,11 @@ char *form_acceptable_charset(struct form *form)
* used iff converting to charset fails
* \return Pointer to converted string (on heap, caller frees), or NULL
*/
-char *form_encode_item(const char *item, uint32_t len, const char *charset,
- const char *fallback)
+char *
+form_encode_item(const char *item,
+ uint32_t len,
+ const char *charset,
+ const char *fallback)
{
nserror err;
char *ret = NULL;
@@ -1797,7 +2124,7 @@ form_submit(nsurl *page_url,
assert(form != NULL);
/* obtain list of controls from DOM */
- res = form_successful_controls_dom(form, submit_button, &success);
+ res = form_dom_to_data(form, submit_button, &success);
if (res != NSERROR_OK) {
return res;
}