Пример #1
0
int
map_scanner_string(struct scanner *scanner,
		   unsigned char *ident, unsigned char *end, int base_type)
{
	const struct scanner_string_mapping *mappings = scanner->info->mappings;
	int length = end - ident;

	for (; mappings->name; mappings++) {
		if (mappings->base_type == base_type
		    && !c_strlcasecmp(mappings->name, -1, ident, length))
			return mappings->type;
	}

	return base_type;
}
Пример #2
0
/** Checks whether a host name matches a pattern that may contain
 * wildcards.
 *
 * @param[in] hostname
 *   The host name to which the user wanted to connect.
 *   Should be in UTF-8 and need not be null-terminated.
 * @param[in] hostname_length
 *   The length of @a hostname, in bytes.
 * @param[in] pattern
 *   A pattern that the host name might match.
 *   Should be in UTF-8 and need not be null-terminated.
 *   The pattern may contain wildcards, as specified in
 *   RFC 2818 section 3.1.
 * @param[in] pattern_length
 *   The length of @a pattern, in bytes.
 *
 * @return
 *   Nonzero if the host name matches.  Zero if it doesn't.
 *
 * According to RFC 2818 section 3.1, '*' matches any number of
 * characters except '.'.  For example, "*r*.example.org" matches
 * "random.example.org" or "history.example.org" but not
 * "frozen.fruit.example.org".
 *
 * This function does not allocate memory, and consumes at most
 * O(@a hostname_length * @a pattern_length) time.  */
int
match_hostname_pattern(const unsigned char *hostname,
		       size_t hostname_length,
		       const unsigned char *pattern,
		       size_t pattern_length)
{
	const unsigned char *const hostname_end = hostname + hostname_length;
	const unsigned char *const pattern_end = pattern + pattern_length;

	assert(hostname <= hostname_end);
	assert(pattern <= pattern_end);
	if_assert_failed return 0;

	while (pattern < pattern_end) {
		if (*pattern == '*') {
			const unsigned char *next_wildcard;
			size_t literal_length;

			++pattern;
			next_wildcard = memchr(pattern, '*',
					       pattern_end - pattern);
			if (next_wildcard == NULL)
				literal_length = pattern_end - pattern;
			else
				literal_length = next_wildcard - pattern;

			for (;;) {
				size_t hostname_left = hostname_end - hostname;
				unicode_val_T uni;

				if (hostname_left < literal_length)
					return 0;

				/* If next_wildcard == NULL, then the
				 * literal string is at the end of the
				 * pattern, so anchor the match to the
				 * end of the hostname.  The end of
				 * this function can then easily
				 * verify that the whole hostname was
				 * matched.
				 *
				 * But do not jump directly there;
				 * first verify that there are no '.'
				 * characters in between.  */
				if ((next_wildcard != NULL
				     || hostname_left == literal_length)
				    && !c_strlcasecmp(pattern, literal_length,
						      hostname, literal_length))
					break;

				/* The literal string doesn't match here.
				 * Skip one character of the hostname and
				 * retry.  If the skipped character is '.'
				 * or one of the equivalent characters
				 * listed in RFC 3490 section 3.1
				 * requirement 1, then return 0, because
				 * '*' must not match such characters.
				 * Do the same if invalid UTF-8 is found.
				 * Cast away const.  */
				uni = utf8_to_unicode((unsigned char **) hostname,
						      hostname_end);
				if (uni == 0x002E
				    || uni == 0x3002
				    || uni == 0xFF0E
				    || uni == 0xFF61
				    || uni == UCS_NO_CHAR)
					return 0;
			}

			pattern += literal_length;
			hostname += literal_length;
		} else {
			if (hostname == hostname_end)
				return 0;

			if (c_toupper(*pattern) != c_toupper(*hostname))
				return 0;

			++pattern;
			++hostname;
		}
	}

	return hostname == hostname_end;
}
Пример #3
0
void
html_textarea(struct html_context *html_context, unsigned char *attr,
              unsigned char *html, unsigned char *eof, unsigned char **end)
{
	struct form_control *fc;
	unsigned char *p, *t_name, *wrap_attr;
	int t_namelen;
	int cols, rows;
	int i;

	html_focusable(html_context, attr);
	while (html < eof && (*html == '\n' || *html == '\r')) html++;
	p = html;
	while (p < eof && *p != '<') {

pp:
		p++;
	}
	if (p >= eof) {
		*end = eof;
		return;
	}
	if (parse_element(p, eof, &t_name, &t_namelen, NULL, end)) goto pp;
	if (c_strlcasecmp(t_name, t_namelen, (const unsigned char *)"/TEXTAREA", 9)) goto pp;

	fc = init_form_control(FC_TEXTAREA, attr, html_context);
	if (!fc) return;

	fc->id = get_attr_val(attr, (unsigned char *)"id", html_context->doc_cp);
	fc->name = get_attr_val(attr, (unsigned char *)"name", html_context->doc_cp);
	fc->default_value = convert_string(NULL, html, p - html,
					   html_context->doc_cp,
					   CSM_DEFAULT, NULL, NULL, NULL);
	for (p = fc->default_value; p && p[0]; p++) {
		/* FIXME: We don't cope well with entities here. Bugzilla uses
		 * &#13; inside of textarea and we fail miserably upon that
		 * one.  --pasky */
		if (p[0] == '\r') {
			if (p[1] == '\n'
			    || (p > fc->default_value && p[-1] == '\n')) {
				memmove(p, p + 1, strlen((const char *)p));
				p--;
			} else {
				p[0] = '\n';
			}
		}
	}

	cols = get_num(attr, (unsigned char *)"cols", html_context->doc_cp);
	if (cols <= 0)
		cols = html_context->options->default_form_input_size;
	cols++; /* Add 1 column, other browsers may have different
		   behavior here (mozilla adds 2) --Zas */
	if (cols > html_context->options->box.width)
		cols = html_context->options->box.width;
	fc->cols = cols;

	rows = get_num(attr, (unsigned char *)"rows", html_context->doc_cp);
	if (rows <= 0) rows = 1;
	if (rows > html_context->options->box.height)
		rows = html_context->options->box.height;
	fc->rows = rows;
	html_context->options->needs_height = 1;

	wrap_attr = get_attr_val(attr, (unsigned char *)"wrap", html_context->doc_cp);
	if (wrap_attr) {
		if (!c_strcasecmp((const char *)wrap_attr, "hard")
		    || !c_strcasecmp((const char *)wrap_attr, "physical")) {
			fc->wrap = FORM_WRAP_HARD;
		} else if (!c_strcasecmp((const char *)wrap_attr, "soft")
			   || !c_strcasecmp((const char *)wrap_attr, "virtual")) {
			fc->wrap = FORM_WRAP_SOFT;
		} else if (!c_strcasecmp((const char *)wrap_attr, "none")
			   || !c_strcasecmp((const char *)wrap_attr, "off")) {
			fc->wrap = FORM_WRAP_NONE;
		}
		mem_free(wrap_attr);

	} else if (has_attr(attr, (unsigned char *)"nowrap", html_context->doc_cp)) {
		fc->wrap = FORM_WRAP_NONE;

	} else {
		fc->wrap = FORM_WRAP_SOFT;
	}

	fc->maxlength = get_num(attr, (unsigned char *)"maxlength", html_context->doc_cp);
	if (fc->maxlength == -1) fc->maxlength = INT_MAX;

	if (rows > 1) ln_break(html_context, 1);
	else put_chrs(html_context, (unsigned char *)" ", 1);

	html_stack_dup(html_context, ELEMENT_KILLABLE);
	format.form = fc;
	format.style.attr |= AT_BOLD;

	for (i = 0; i < rows; i++) {
		int j;

		for (j = 0; j < cols; j++)
			put_chrs(html_context, (unsigned char *)"_", 1);
		if (i < rows - 1)
			ln_break(html_context, 1);
	}

	pop_html_element(html_context);
	if (rows > 1)
		ln_break(html_context, 1);
	else
		put_chrs(html_context, (unsigned char *)" ", 1);
	html_context->special_f(html_context, SP_CONTROL, fc);
}
Пример #4
0
void
html_option(struct html_context *html_context, unsigned char *a,
            unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
{
	struct form_control *fc;
	unsigned char *val;

	if (!format.select) return;

	val = get_attr_val(a, (unsigned char *)"value", html_context->doc_cp);
	if (!val) {
		struct string str;
		unsigned char *p, *r;
		unsigned char *name;
		int namelen;

		for (p = a - 1; *p != '<'; p--);

		if (!init_string(&str)) goto end_parse;
		if (parse_element(p, html_context->eoff, NULL, NULL, NULL, &p)) {
			INTERNAL("parse element failed");
			val = str.source;
			goto end_parse;
		}

se:
		while (p < html_context->eoff && isspace(*p)) p++;
		while (p < html_context->eoff && !isspace(*p) && *p != '<') {

sp:
			add_char_to_string(&str, *p ? *p : ' '), p++;
		}

		r = p;
		val = str.source; /* Has to be before the possible 'goto end_parse' */

		while (r < html_context->eoff && isspace(*r)) r++;
		if (r >= html_context->eoff) goto end_parse;
		if (r - 2 <= html_context->eoff && (r[1] == '!' || r[1] == '?')) {
			p = skip_comment(r, html_context->eoff);
			goto se;
		}
		if (parse_element(r, html_context->eoff, &name, &namelen, NULL, &p)) goto sp;

		if (namelen < 6) goto se;
		if (name[0] == '/') name++, namelen--;
		
		if (c_strlcasecmp(name, namelen, (const unsigned char *)"OPTION", 6)
		    && c_strlcasecmp(name, namelen, (const unsigned char *)"SELECT", 6)
		    && c_strlcasecmp(name, namelen, (const unsigned char *)"OPTGROUP", 8))
			goto se;
	}

end_parse:
	fc = init_form_control(FC_CHECKBOX, a, html_context);
	if (!fc) {
		mem_free_if(val);
		return;
	}

	fc->id = get_attr_val(a, (unsigned char *)"id", html_context->doc_cp);
	fc->name = null_or_stracpy(format.select);
	fc->default_value = val;
	fc->default_state = has_attr(a, (unsigned char *)"selected", html_context->doc_cp);
	fc->mode = has_attr(a, (unsigned char *)"disabled", html_context->doc_cp)
	           ? FORM_MODE_DISABLED
	           : format.select_disabled;

	put_chrs(html_context, (unsigned char *)" ", 1);
	html_stack_dup(html_context, ELEMENT_KILLABLE);
	format.form = fc;
	format.style.attr |= AT_BOLD;
	put_chrs(html_context, (unsigned char *)"[ ]", 3);
	pop_html_element(html_context);
	put_chrs(html_context, (unsigned char *)" ", 1);
	html_context->special_f(html_context, SP_CONTROL, fc);
}
Пример #5
0
static void
do_html_select(unsigned char *attr, unsigned char *html,
	       unsigned char *eof, unsigned char **end,
	       struct html_context *html_context)
{
	struct conv_table *ct = (struct conv_table *)html_context->special_f(html_context, SP_TABLE, NULL);
	struct form_control *fc;
	struct string lbl = NULL_STRING, orig_lbl = NULL_STRING;
	unsigned char **values = NULL;
	unsigned char **labels;
	unsigned char *name, *t_attr, *en;
	int namelen;
	int nnmi = 0;
	int order = 0;
	int preselect = -1;
	int group = 0;
	int i, max_width;
	int closing_tag;

	html_focusable(html_context, attr);
	init_menu(&lnk_menu);

se:
        en = html;

see:
        html = en;
	while (html < eof && *html != '<') html++;

	if (html >= eof) {

abort:
		*end = html;
		if (lbl.source) done_string(&lbl);
		if (orig_lbl.source) done_string(&orig_lbl);
		if (values) {
			int j;

			for (j = 0; j < order; j++)
				mem_free_if(values[j]);
			mem_free(values);
		}
		destroy_menu(&lnk_menu);
		*end = en;
		return;
	}

	if (lbl.source) {
		unsigned char *q, *s = en;
		int l = html - en;

		while (l && isspace(s[0])) s++, l--;
		while (l && isspace(s[l-1])) l--;
		q = convert_string(ct, s, l,
		                   html_context->options->cp,
		                   CSM_DEFAULT, NULL, NULL, NULL);
		if (q) add_to_string(&lbl, q), mem_free(q);
		add_bytes_to_string(&orig_lbl, s, l);
	}

	if (html + 2 <= eof && (html[1] == '!' || html[1] == '?')) {
		html = skip_comment(html, eof);
		goto se;
	}

	if (parse_element(html, eof, &name, &namelen, &t_attr, &en)) {
		html++;
		goto se;
	}

	if (!namelen) goto see;

	if (name[0] == '/') {
		namelen--;
		if (!namelen) goto see;
		name++;
		closing_tag = 1;
	} else {
		closing_tag = 0;
	}

	if (closing_tag && !c_strlcasecmp(name, namelen, (const unsigned char *)"SELECT", 6)) {
		add_select_item(&lnk_menu, &lbl, &orig_lbl, values, order, nnmi);
		goto end_parse;
	}

	if (!c_strlcasecmp(name, namelen, (const unsigned char *)"OPTION", 6)) {
		add_select_item(&lnk_menu, &lbl, &orig_lbl, values, order, nnmi);

		if (!closing_tag) {
			unsigned char *value, *label;

			if (has_attr(t_attr, (unsigned char *)"disabled", html_context->doc_cp))
				goto see;
			if (preselect == -1
			    && has_attr(t_attr, (unsigned char *)"selected", html_context->doc_cp))
				preselect = order;
			value = get_attr_val(t_attr, (unsigned char *)"value", html_context->doc_cp);

			if (!mem_align_alloc(&values, order, order + 1, 0xFF))
				goto abort;

			values[order++] = value;
			label = get_attr_val(t_attr, (unsigned char *)"label", html_context->doc_cp);
			if (label) new_menu_item(&lnk_menu, label, order - 1, 0);
			if (!value || !label) {
				init_string(&lbl);
				init_string(&orig_lbl);
				nnmi = !!label;
			}
		}

		goto see;
	}

	if (!c_strlcasecmp(name, namelen, (const unsigned char *)"OPTGROUP", 8)) {
		add_select_item(&lnk_menu, &lbl, &orig_lbl, values, order, nnmi);

		if (group) new_menu_item(&lnk_menu, NULL, -1, 0), group = 0;

		if (!closing_tag) {
			unsigned char *label;

			label = get_attr_val(t_attr, (unsigned char *)"label", html_context->doc_cp);

			if (!label) {
				label = stracpy((const unsigned char *)"");
				if (!label) goto see;
			}
			new_menu_item(&lnk_menu, label, -1, 0);
			group = 1;
		}
	}

	goto see;


end_parse:
	*end = en;
	if (!order) goto abort;

	labels = (unsigned char **)mem_calloc(order, sizeof(unsigned char *));
	if (!labels) goto abort;

	fc = init_form_control(FC_SELECT, attr, html_context);
	if (!fc) {
		mem_free(labels);
		goto abort;
	}

	fc->id = get_attr_val(attr, (unsigned char *)"id", html_context->doc_cp);
	fc->name = get_attr_val(attr, (unsigned char *)"name", html_context->doc_cp);
	fc->default_state = preselect < 0 ? 0 : preselect;
	fc->default_value = order ? stracpy(values[fc->default_state]) : stracpy((const unsigned char *)"");
	fc->nvalues = order;
	fc->values = values;
	fc->menu = detach_menu(&lnk_menu);
	fc->labels = labels;

	menu_labels(fc->menu, (unsigned char *)"", labels);
	put_chrs(html_context, (unsigned char *)"[", 1);
	html_stack_dup(html_context, ELEMENT_KILLABLE);
	format.form = fc;
	format.style.attr |= AT_BOLD;

	max_width = 0;
	for (i = 0; i < order; i++) {
		if (!labels[i]) continue;
#ifdef CONFIG_UTF8
		if (html_context->options->utf8)
			int_lower_bound(&max_width,
					utf8_ptr2cells(labels[i], NULL));
		else
#endif /* CONFIG_UTF8 */
			int_lower_bound(&max_width, strlen((const char *)labels[i]));
	}

	for (i = 0; i < max_width; i++)
		put_chrs(html_context, (unsigned char *)"_", 1);

	pop_html_element(html_context);
	put_chrs(html_context, (unsigned char *)"]", 1);
	html_context->special_f(html_context, SP_CONTROL, fc);
}
Пример #6
0
void
html_script(struct html_context *html_context, unsigned char *a,
            unsigned char *html, unsigned char *eof, unsigned char **end)
{
#ifdef CONFIG_ECMASCRIPT
	/* TODO: <noscript> processing. Well, same considerations apply as to
	 * CSS property display: none processing. */
	/* TODO: Charsets for external scripts. */
	unsigned char *type, *language, *src;
	int in_comment = 0;
#endif

	html_skip(html_context, a);

#ifdef CONFIG_ECMASCRIPT
	/* We try to process nested <script> if we didn't process the parent
	 * one. That's why's all the fuzz. */
	/* Ref:
	 * http://www.ietf.org/internet-drafts/draft-hoehrmann-script-types-03.txt
	 */
	type = get_attr_val(a, (unsigned char *)"type", html_context->doc_cp);
	if (type) {
		unsigned char *pos = type;

		if (!c_strncasecmp((const char *)type, "text/", 5)) {
			pos += 5;

		} else if (!c_strncasecmp((const char *)type, "application/", 12)) {
			pos += 12;

		} else {
			mem_free(type);
not_processed:
			/* Permit nested scripts and retreat. */
			html_top->invisible++;
			return;
		}

		if (!c_strncasecmp((const char *)pos, "javascript", 10)) {
			int len = strlen((const char *)pos);

			if (len > 10 && !isdigit(pos[10])) {
				mem_free(type);
				goto not_processed;
			}

		} else if (c_strcasecmp((const char *)pos, "ecmascript")
		    && c_strcasecmp((const char *)pos, "jscript")
		    && c_strcasecmp((const char *)pos, "livescript")
		    && c_strcasecmp((const char *)pos, "x-javascript")
		    && c_strcasecmp((const char *)pos, "x-ecmascript")) {
			mem_free(type);
			goto not_processed;
		}

		mem_free(type);
	}

	/* Check that the script content is ecmascript. The value of the
	 * language attribute can be JavaScript with optional version digits
	 * postfixed (like: ``JavaScript1.1'').
	 * That attribute is deprecated in favor of type by HTML 4.01 */
	language = get_attr_val(a, (unsigned char *)"language", html_context->doc_cp);
	if (language) {
		int languagelen = strlen((const char *)language);

		if (languagelen < 10
		    || (languagelen > 10 && !isdigit(language[10]))
		    || c_strncasecmp((const char *)language, "javascript", 10)) {
			mem_free(language);
			html_top->invisible++;
			return;
			//goto not_processed;
		}

		mem_free(language);
	}

	if (html_context->part->document
	    && (src = get_attr_val(a, (unsigned char *)"src", html_context->doc_cp))) {
		/* External reference. */

		unsigned char *import_url;
		struct uri *uri;

		if (!get_opt_bool((const unsigned char *)"ecmascript.enable", NULL)) {
			mem_free(src);
			html_top->invisible++;
			return;
			//goto not_processed;
		}

		/* HTML <head> urls should already be fine but we can.t detect them. */
		import_url = join_urls(html_context->base_href, src);
		mem_free(src);
		if (!import_url) goto imported;

		uri = get_uri(import_url, URI_BASE);
		if (!uri) goto imported;

		/* Request the imported script as part of the document ... */
		html_context->special_f(html_context, SP_SCRIPT, uri);
		done_uri(uri);

		/* Create URL reference onload snippet. */
		insert_in_string(&import_url, 0, (const unsigned char *)"^", 1);
		add_to_string_list(&html_context->part->document->onload_snippets,
		                   import_url, -1);

imported:
		/* Retreat. Do not permit nested scripts, tho'. */
		if (import_url) mem_free(import_url);
		return;
	}

	/* Positive, grab the rest and interpret it. */

	/* First position to the real script start. */
	while (html < eof && *html <= ' ') html++;
	if (eof - html > 4 && !strncmp((const char *)html, "<!--", 4)) {
		in_comment = 1;
		/* We either skip to the end of line or to -->. */
		for (; *html != '\n' && *html != '\r' && eof - html >= 3; html++) {
			if (!strncmp((const char *)html, "-->", 3)) {
				/* This means the document is probably broken.
				 * We will now try to process the rest of
				 * <script> contents, which is however likely
				 * to be empty. Should we try to process the
				 * comment too? Currently it seems safer but
				 * less tolerant to broken pages, if there are
				 * any like this. */
				html += 3;
				in_comment = 0;
				break;
			}
		}
	}

	*end = html;

	/* Now look ahead for the script end. The <script> contents is raw
	 * CDATA, so we just look for the ending tag and need not care for
	 * any quote marks counting etc - YET, we are more tolerant and permit
	 * </script> stuff inside of the script if the whole <script> element
	 * contents is wrapped in a comment. See i.e. Mozilla bug 26857 for fun
	 * reading regarding this. */
	for (; *end < eof; (*end)++) {
		unsigned char *name;
		int namelen;

		if (in_comment) {
			/* TODO: If we ever get some standards-quirk mode
			 * distinction, this should be disabled in the
			 * standards mode (and we should just look for CDATA
			 * end, which is "</"). --pasky */
			if (eof - *end >= 3 && !strncmp((const char *)*end, "-->", 3)) {
				/* Next iteration will jump passed the ending '>' */
				(*end) += 2;
				in_comment = 0;
			}
			continue;
			/* XXX: Scan for another comment? That's admittelly
			 * already stretching things a little bit to an
			 * extreme ;-). */
		}

		if (**end != '<')
			continue;
		/* We want to land before the closing element, that's why we
		 * don't pass @end also as the appropriate parse_element()
		 * argument. */
		if (parse_element(*end, eof, &name, &namelen, NULL, NULL))
			continue;
		if (c_strlcasecmp(name, namelen, (const unsigned char *)"/script", 7))
			continue;
		/* We have won! */
		break;
	}
	if (*end >= eof) {
		/* Either the document is not completely loaded yet or it's
		 * broken. At any rate, run away screaming. */
		*end = eof; /* Just for sanity. */
		return;
	}

	if (html_context->part->document && *html != '^') {
		add_to_string_list(&html_context->part->document->onload_snippets,
		                   html, *end - html);
	}
#endif
}