X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=cgiedit.c;h=3b8b12c921e835815ececb438205ddc6c545d7b8;hp=14886d45301ce38356db9a6415a947adf6512b8c;hb=bd4b1ca35dfabe720b7631bbd8305adfe2be08d4;hpb=1197b9d2c922eef32bccb8411748d2d18f27a454 diff --git a/cgiedit.c b/cgiedit.c index 14886d45..3b8b12c9 100644 --- a/cgiedit.c +++ b/cgiedit.c @@ -188,7 +188,7 @@ struct editable_file * Information about the filter types. * Used for macro replacement in cgi_edit_actions_for_url. */ -struct filter_type_info +struct action_type_info { const int multi_action_index; /**< The multi action index as defined in project.h */ const char *macro_name; /**< Name of the macro that has to be replaced @@ -208,7 +208,7 @@ struct filter_type_info }; /* Accessed by index, keep the order in the way the FT_ macros are defined. */ -static const struct filter_type_info filter_type_info[] = +static const struct action_type_info action_type_info[] = { { ACTION_MULTI_FILTER, @@ -240,6 +240,24 @@ static const struct filter_type_info filter_type_info[] = "server-header-tagger-all", "server_header_tagger_all", "E", "SERVER-HEADER-TAGGER" }, + { + ACTION_MULTI_SUPPRESS_TAG, + "suppress-tag-params", "suppress-tag", + "suppress-tag-all", "suppress_tag_all", + "U", "SUPPRESS-TAG" + }, + { + ACTION_MULTI_CLIENT_BODY_FILTER, + "client-body-filter-params", "client-body-filter", + "client-body-filter-all", "client_body_filter_all", + "P", "CLIENT-BODY-FILTER" + }, + { + ACTION_MULTI_ADD_HEADER, + "add-header-params", "add-header", + "add-header-all", "add_header_all", + "H", "ADD-HEADER" + }, #ifdef FEATURE_EXTERNAL_FILTERS { ACTION_MULTI_EXTERNAL_FILTER, @@ -250,6 +268,30 @@ static const struct filter_type_info filter_type_info[] = #endif }; +/** + * Information about the string filter actions. + * Used for macro replacement in action_render_string_actions_template + */ +struct string_action_type_info +{ + const enum filter_type action_type; /**< Action type */ + const char *description; /**< Action description */ + const char *input_description; /**< Input field description */ +}; + +/* String action types: special CGI handling */ +static const struct string_action_type_info string_action_type_info[] = +{ + { + FT_SUPPRESS_TAG, + "Suppress tag", "Tag to suppress" + }, + { + FT_ADD_HEADER, + "Add HTTP client header", "HTTP client header to add" + }, +}; + /* FIXME: Following non-static functions should be prototyped in .h or made static */ /* Functions to read and write arbitrary config files */ @@ -306,6 +348,10 @@ static jb_err actions_to_radio(struct map * exports, const struct action_spec *action); static jb_err actions_from_radio(const struct map * parameters, struct action_spec *action); +static jb_err action_render_string_actions_template(struct map * exports, + const struct action_spec *action, + const char* action_template, + const struct string_action_type_info *string_action_type); static jb_err map_copy_parameter_html(struct map *out, @@ -2685,6 +2731,7 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, const struct map *parameters) { struct map * exports; + char *filter_template; unsigned sectionid; struct editable_file * file; struct file_line * cur_line; @@ -2734,12 +2781,27 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, return JB_ERR_MEMORY; } + err = template_load(csp, &filter_template, "edit-actions-for-url-string-action", 0); + if (err) + { + edit_free_file(file); + free_map(exports); + return cgi_error_no_template(csp, rsp, "edit-actions-for-url-string-action"); + } + err = map(exports, "f", 1, stringify(file->identifier), 0); if (!err) err = map(exports, "v", 1, file->version_str, 1); if (!err) err = map(exports, "s", 1, url_encode(lookup(parameters, "s")), 0); if (!err) err = actions_to_radio(exports, cur_line->data.action); + for (i = 0; !err && i < SZ(string_action_type_info); i++) + { + err = action_render_string_actions_template(exports, cur_line->data.action, filter_template, + &string_action_type_info[i]); + } + freez(filter_template); + /* * XXX: Some browsers (at least IE6 and IE7) have an artificial URL * length limitation and ignore clicks on the Submit buttons if @@ -2782,7 +2844,7 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, #ifndef FEATURE_EXTERNAL_FILTERS if (!err) err = map_block_killer(exports, "external-content-filters"); #endif -#ifndef FEATURE_HTTP_INSPECTION +#ifndef FEATURE_HTTPS_INSPECTION if (!err) err = map_block_killer(exports, "https-inspection"); #endif @@ -2802,7 +2864,6 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, /* * List available filters and their settings. */ - char *filter_template; int filter_identifier = 0; char *prepared_templates[MAX_FILTER_TYPES]; @@ -2837,7 +2898,7 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, struct list_entry *filter_name; struct map *line_exports; const enum filter_type type = filter_group->type; - const int multi_action_index = filter_type_info[type].multi_action_index; + const int multi_action_index = action_type_info[type].multi_action_index; assert(type < MAX_FILTER_TYPES); @@ -2883,9 +2944,9 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, if (!err) err = map(line_exports, "name", 1, filter_group->name, 1); if (!err) err = map(line_exports, "description", 1, filter_group->description, 1); if (!err) err = map_radio(line_exports, "this-filter", "ynx", current_mode); - if (!err) err = map(line_exports, "filter-type", 1, filter_type_info[type].type, 1); - if (!err) err = map(line_exports, "abbr-filter-type", 1, filter_type_info[type].abbr_type, 1); - if (!err) err = map(line_exports, "anchor", 1, filter_type_info[type].anchor, 1); + if (!err) err = map(line_exports, "filter-type", 1, action_type_info[type].type, 1); + if (!err) err = map(line_exports, "abbr-action-type", 1, action_type_info[type].abbr_type, 1); + if (!err) err = map(line_exports, "anchor", 1, action_type_info[type].anchor, 1); if (!err) { @@ -2893,7 +2954,7 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, if (filter_line == NULL) err = JB_ERR_MEMORY; } if (!err) err = template_fill(&filter_line, line_exports); - string_join(&prepared_templates[type], filter_line); + if (!err) err = string_join(&prepared_templates[type], filter_line); free_map(line_exports); } @@ -2906,7 +2967,7 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, for (i = 0; i < MAX_FILTER_TYPES; i++) { if (err) break; - err = map(exports, filter_type_info[i].macro_name, 1, prepared_templates[i], 0); + err = map(exports, action_type_info[i].macro_name, 1, prepared_templates[i], 0); } if (err) @@ -2922,10 +2983,10 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, /* Check or uncheck the "disable all of this type" radio buttons. */ for (i = 0; i < MAX_FILTER_TYPES; i++) { - const int a = filter_type_info[i].multi_action_index; + const int a = action_type_info[i].multi_action_index; const int disable_all = cur_line->data.action->multi_remove_all[a]; if (err) break; - err = map_radio(exports, filter_type_info[i].disable_all_option, "nx", (disable_all ? 'n' : 'x')); + err = map_radio(exports, action_type_info[i].disable_all_option, "nx", (disable_all ? 'n' : 'x')); } edit_free_file(file); @@ -2940,6 +3001,215 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, } +/********************************************************************* + * + * Function : get_number_of_filters + * + * Description : Counts the number of filter available. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : Number of filters available. + * + *********************************************************************/ +static int get_number_of_filters(const struct client_state *csp) +{ + int i; + struct re_filterfile_spec *b; + struct file_list *fl; + int number_of_filters = 0; + + for (i = 0; i < MAX_AF_FILES; i++) + { + fl = csp->rlist[i]; + if ((NULL == fl) || (NULL == fl->f)) + { + /* + * Either there are no filter files left or this + * filter file just contains no valid filters. + * + * Continue to be sure we don't miss valid filter + * files that are chained after empty or invalid ones. + */ + continue; + } + + for (b = fl->f; b != NULL; b = b->next) + { + number_of_filters++; + } + } + + return number_of_filters; + +} + + +/********************************************************************* + * + * Function : cgi_edit_process_string_action + * + * Description : Helper CGI function that actually edits the Actions list for + * the action string parameters. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * 2 : rsp = http_response data structure for output + * 3 : parameters = map of cgi parameters + * 4 : cur_line = current config file line + * 5 : action_type = string filter type to process + * + * Returns : JB_ERR_OK on success + * JB_ERR_MEMORY on out-of-memory + * JB_ERR_CGI_PARAMS if the CGI parameters are not + * specified or not valid. + * + *********************************************************************/ +static jb_err cgi_edit_process_string_action(struct client_state *csp, + struct http_response *rsp, + const struct map *parameters, + struct file_line *cur_line, + enum filter_type action_type) +{ + jb_err err = JB_ERR_OK; + const char *abbr_type = action_type_info[action_type].abbr_type; + int action_identifier = 0; + + /* process existing string filter actions */ + for (action_identifier = 0; !err; action_identifier++) + { + char key_value[30]; + char key_name[30]; + char old_name[30]; + char key_type[30]; + const char *name, *new_name; + char value; /* + * Action state. Valid states are: 'Y' (active), + * 'N' (inactive) and 'X' (no change). + * XXX: bad name. + */ + char type; /* + * Abbreviated filter type. Valid types are: 'U' (suppress tag), 'H' (add header) + */ + int multi_action_index = 0; + + /* Generate the keys */ + snprintf(key_value, sizeof(key_value), "string_action_%s_r%x", abbr_type, action_identifier); + snprintf(key_name, sizeof(key_name), "string_action_%s_n%x", abbr_type, action_identifier); + snprintf(old_name, sizeof(old_name), "string_action_%s_o%x", abbr_type, action_identifier); + snprintf(key_type, sizeof(key_type), "string_action_%s_t%x", abbr_type, action_identifier); + + err = get_string_param(parameters, old_name, &name); + if (err) break; + + if (name == NULL) + { + /* The action identifier isn't present: we're done! */ + break; + } + + err = get_string_param(parameters, key_name, &new_name); + if (err) break; + if (new_name == NULL) new_name = name; + + type = get_char_param(parameters, key_type); + switch (type) + { + case 'U': + multi_action_index = ACTION_MULTI_SUPPRESS_TAG; + break; + case 'H': + multi_action_index = ACTION_MULTI_ADD_HEADER; + break; + default: + log_error(LOG_LEVEL_ERROR, + "Unknown action type: %c for action %s. Action ignored.", type, name); + continue; + } + + value = get_char_param(parameters, key_value); + if (value == 'X' || value == 'Y' || value == 'N') + { + list_remove_item(cur_line->data.action->multi_add[multi_action_index], name); + list_remove_item(cur_line->data.action->multi_remove[multi_action_index], name); + } + + if (value == 'Y') + { + err = enlist(cur_line->data.action->multi_add[multi_action_index], new_name); + } + else if (value == 'N') + { + err = enlist(cur_line->data.action->multi_remove[multi_action_index], new_name); + } + } + + /* process new string filter actions */ + for (action_identifier = 0; !err; action_identifier++) + { + char key_value[30]; + char key_name[30]; + char key_type[30]; + const char *name; + char value; /* + * Action state. Valid states are: 'Y' (active), + * 'N' (inactive) and 'X' (no change). + * XXX: bad name. + */ + char type; /* + * Abbreviated filter type. Valid types are: 'U' (suppress tag), 'H' (add header) + */ + int multi_action_index = 0; + + /* Generate the keys */ + snprintf(key_value, sizeof(key_value), "new_string_action_%s_r%x", abbr_type, action_identifier); + snprintf(key_name, sizeof(key_name), "new_string_action_%s_n%x", abbr_type, action_identifier); + snprintf(key_type, sizeof(key_type), "new_string_action_%s_t%x", abbr_type, action_identifier); + + err = get_string_param(parameters, key_name, &name); + if (err) break; + + if (name == NULL) + { + /* The action identifier isn't present: we've done! */ + break; + } + + type = get_char_param(parameters, key_type); + switch (type) + { + case 'U': + multi_action_index = ACTION_MULTI_SUPPRESS_TAG; + break; + case 'H': + multi_action_index = ACTION_MULTI_ADD_HEADER; + break; + default: + log_error(LOG_LEVEL_ERROR, + "Unknown filter type: %c for filter %s. Filter ignored.", type, name); + continue; + } + + value = get_char_param(parameters, key_value); + if (value == 'Y') + { + list_remove_item(cur_line->data.action->multi_add[multi_action_index], name); + if (!err) err = enlist(cur_line->data.action->multi_add[multi_action_index], name); + list_remove_item(cur_line->data.action->multi_remove[multi_action_index], name); + } + else if (value == 'N') + { + list_remove_item(cur_line->data.action->multi_add[multi_action_index], name); + list_remove_item(cur_line->data.action->multi_remove[multi_action_index], name); + if (!err) err = enlist(cur_line->data.action->multi_remove[multi_action_index], name); + } + /* nothing to do if the value is 'X' */ + } + return err; +} + + /********************************************************************* * * Function : cgi_edit_actions_submit @@ -2978,6 +3248,7 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, const char * action_set_name; struct file_list * fl; struct url_actions * b; + int number_of_filters; if (0 == (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS)) { @@ -3051,8 +3322,8 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, /* Check the "disable all of this type" parameters. */ for (i = 0; i < MAX_FILTER_TYPES; i++) { - const int multi_action_index = filter_type_info[i].multi_action_index; - const char ch = get_char_param(parameters, filter_type_info[i].disable_all_param); + const int multi_action_index = action_type_info[i].multi_action_index; + const char ch = get_char_param(parameters, action_type_info[i].disable_all_param); if (ch == 'N') { @@ -3066,7 +3337,9 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, } } - for (filter_identifier = 0; !err; filter_identifier++) + number_of_filters = get_number_of_filters(csp); + + for (filter_identifier = 0; filter_identifier < number_of_filters && !err; filter_identifier++) { char key_value[30]; char key_name[30]; @@ -3095,8 +3368,8 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, if (name == NULL) { - /* End of list */ - break; + /* The filter identifier isn't present. Try the next one. */ + continue; } type = get_char_param(parameters, key_type); @@ -3117,6 +3390,9 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, case 'E': multi_action_index = ACTION_MULTI_SERVER_HEADER_TAGGER; break; + case 'P': + multi_action_index = ACTION_MULTI_CLIENT_BODY_FILTER; + break; default: log_error(LOG_LEVEL_ERROR, "Unknown filter type: %c for filter %s. Filter ignored.", type, name); @@ -3147,6 +3423,13 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, } } + /* process new string filters */ + for (i = 0; !err && i < SZ(string_action_type_info); i++) + { + err = cgi_edit_process_string_action(csp, rsp, parameters, cur_line, + string_action_type_info[i].action_type); + } + if (err) { /* Out of memory */ @@ -4200,6 +4483,88 @@ static jb_err actions_to_radio(struct map * exports, return JB_ERR_OK; } +/********************************************************************* + * + * Function : action_render_string_actions_template + * + * Description : Converts a actionsfile entry into HTML template for actions with string + * filters (currently SUPPRESS-TAG actions only) + * + * Parameters : + * 1 : exports = List of substitutions to add to. + * 2 : action = Action to read + * 3 : action_template = template to fill + * 4 : type = filter type info for rendered values/macro name + * + * Returns : JB_ERR_OK on success + * JB_ERR_MEMORY on out-of-memory + * + *********************************************************************/ +static jb_err action_render_string_actions_template(struct map * exports, + const struct action_spec *action, + const char* action_template, + const struct string_action_type_info *string_action_type) +{ + jb_err err = JB_ERR_OK; + int filter_identifier = 0; + int i; + char *prepared_template = strdup(""); + const struct action_type_info *type = &action_type_info[string_action_type->action_type]; + + struct action_multi { + char radio; + struct list_entry *list; + }; + + struct action_multi desc[] = { + { 'y', action->multi_add[type->multi_action_index][0].first }, + { 'n', action->multi_remove[type->multi_action_index][0].first } + }; + + for (i = 0; i < SZ(desc); ++i) + { + const char radio = desc[i].radio; + struct list_entry *entry = desc[i].list; + for (;(!err) && (entry != NULL); entry = entry->next) + { + char number[20]; + struct map *line_exports; + + /* Generate a unique serial number */ + snprintf(number, sizeof(number), "%x", filter_identifier++); + + line_exports = new_map(); + if (line_exports == NULL) + { + err = JB_ERR_MEMORY; + } + else + { + char *action_line; + if (!err) err = map(line_exports, "index", 1, number, 1); + if (!err) err = map(line_exports, "name", 1, entry->str, 1); + if (!err) err = map_radio(line_exports, "this-filter", "ynx", radio); + if (!err) err = map(line_exports, "filter-type", 1, type->type, 1); + if (!err) err = map(line_exports, "abbr-action-type", 1, type->abbr_type, 1); + if (!err) err = map(line_exports, "anchor", 1, type->anchor, 1); + if (!err) err = map(line_exports, "desc", 1, string_action_type->description, 1); + if (!err) err = map(line_exports, "input_desc", 1, string_action_type->input_description, 1); + if (!err) + { + action_line = strdup(action_template); + if (action_line == NULL) err = JB_ERR_MEMORY; + } + if (!err) err = template_fill(&action_line, line_exports); + if (!err) err = string_join(&prepared_template, action_line); + + free_map(line_exports); + } + } + } + if (!err) map(exports, type->macro_name, 1, prepared_template, 1); + freez(prepared_template); + return err; +} /********************************************************************* *