⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uri.c

📁 一个很有名的浏览器
💻 C
📖 第 1 页 / 共 3 页
字号:
	int retries = 0;	/* Strip starting spaces */	while (*url == ' ') url++;	if (!*url) return NULL;	newurl = expand_tilde(url); /* XXX: Post data copy. */	if (!newurl) return NULL;parse_uri:	/* Yay a goto loop. If we get some URI parse error and try to	 * fix it we go back to here and try again. */	/* Ordinary parse */	uri_errno = parse_uri(&uri, newurl);	/* Bail out if the same error occurs twice */	if (uri_errno == prev_errno || retries++ > MAX_TRANSLATION_ATTEMPTS) {		if (retries > MAX_TRANSLATION_ATTEMPTS) {			ERROR("Maximum number of parsing attempts exceeded "			      "for %s.", url);		}		mem_free(newurl);		return NULL;	}	prev_errno = uri_errno;	switch (uri_errno) {	case URI_ERRNO_OK:		/* Fix translation of 1.2.3.4:5 so IP address part won't be		 * interpreted as the protocol name. */		if (uri.protocol == PROTOCOL_UNKNOWN) {			unsigned char *ipscan = newurl;			/* FIXME: This is looking more and more like the code			 * for the URI_ERRNO_INVALID_PROTOCOL label and			 * find_uri_protocol(). Unite? --jonas */			/* Check if it could be just some local file with ':'			 * in its name. */			if (check_uri_file(newurl) >= 0) {				struct string str;				if (!init_string(&str)) return NULL;				add_to_string(&str, "file://");				if (!dir_sep(*newurl))					add_to_string(&str, "./");				encode_file_uri_string(&str, newurl);				mem_free(newurl);				newurl = str.source;				/* Work around the infinite loop prevention */				prev_errno = URI_ERRNO_EMPTY;				goto parse_uri;			}			/* Check if it's <IP-address>:<port> */			while (isdigit(*ipscan) || *ipscan == '.')				ipscan++;			if (!*ipscan || *ipscan == ':' || *ipscan == '/') {				insert_in_string(&newurl, 0, "http://", 7);				/* Work around the infinite loop prevention */				prev_errno = URI_ERRNO_EMPTY;				goto parse_uri;			}		}		/* If file:// URI is transformed we need to reparse. */		if (uri.protocol == PROTOCOL_FILE && cwd && *cwd		    && transform_file_url(&uri, cwd))			return normalize_uri_reparse(struri(&uri));		/* Translate the proxied URI too if proxy:// */		if (uri.protocol == PROTOCOL_PROXY) {			unsigned char *data = translate_url(uri.data, cwd);			int pos = uri.data - struri(&uri);			if (!data) break;			struri(&uri)[pos] = 0;			insert_in_string(&struri(&uri), pos, data, strlen(data));			mem_free(data);			return normalize_uri_reparse(struri(&uri));		}		return normalize_uri_noparse(&uri);	case URI_ERRNO_TOO_MANY_SLASHES:	{		unsigned char *from, *to;		assert(uri.string[uri.protocollen] == ':'		       && uri.string[uri.protocollen + 1] == '/'		       && uri.string[uri.protocollen + 2] == '/');		from = to = uri.string + uri.protocollen + 3;		while (*from == '/') from++;		assert(to < from);		memmove(to, from, strlen(from) + 1);		goto parse_uri;	}	case URI_ERRNO_NO_SLASHES:	{		/* Try prefix:some.url -> prefix://some.url.. */		int slashes = 2;		/* Check if only one '/' is needed. */		if (uri.string[uri.protocollen + 1] == '/')			slashes--;		insert_in_string(&newurl, uri.protocollen + 1, "//", slashes);		goto parse_uri;	}	case URI_ERRNO_TRAILING_DOTS:	{		/* Trim trailing '.'s */		unsigned char *from = uri.host + uri.hostlen;		unsigned char *to = from;		assert(uri.host < to && to[-1] == '.' && *from != '.');		while (uri.host < to && to[-1] == '.') to--;		assert(to < from);		memmove(to, from, strlen(from) + 1);		goto parse_uri;	}	case URI_ERRNO_NO_PORT_COLON:		assert(uri.portlen == 0		       && uri.string < uri.port		       && uri.port[-1] == ':');		memmove(uri.port - 1, uri.port, strlen(uri.port) + 1);		goto parse_uri;	case URI_ERRNO_NO_HOST_SLASH:	{		int offset = uri.port			   ? uri.port + uri.portlen - struri(&uri)			   : uri.host + uri.hostlen - struri(&uri) + uri.ipv6 /* ']' */;		assertm(uri.host, "uri.host not set after no host slash error");		insert_in_string(&newurl, offset, "/", 1);		goto parse_uri;	}	case URI_ERRNO_INVALID_PROTOCOL:	{		/* No protocol name */		enum protocol protocol = find_uri_protocol(newurl);		struct string str;		if (!init_string(&str)) return NULL;		switch (protocol) {			case PROTOCOL_FTP:				add_to_string(&str, "ftp://");				encode_uri_string(&str, newurl, 0);				break;			case PROTOCOL_HTTP:				add_to_string(&str, "http://");				add_to_string(&str, newurl);				break;			case PROTOCOL_FILE:			default:				add_to_string(&str, "file://");				if (!dir_sep(*newurl))					add_to_string(&str, "./");				encode_file_uri_string(&str, newurl);		}		mem_free(newurl);		newurl = str.source;		goto parse_uri;	}	case URI_ERRNO_EMPTY:	case URI_ERRNO_IPV6_SECURITY:	case URI_ERRNO_NO_HOST:	case URI_ERRNO_INVALID_PORT:	case URI_ERRNO_INVALID_PORT_RANGE:		/* None of these can be handled properly. */		break;	}	mem_free(newurl);	return NULL;}struct uri *get_composed_uri(struct uri *uri, enum uri_component components){	unsigned char *string;	assert(uri);	if_assert_failed return NULL;	string = get_uri_string(uri, components);	if (!string) return NULL;	uri = get_uri(string, 0);	mem_free(string);	return uri;}struct uri *get_translated_uri(unsigned char *uristring, unsigned char *cwd){	struct uri *uri;	uristring = translate_url(uristring, cwd);	if (!uristring) return NULL;	uri = get_uri(uristring, 0);	mem_free(uristring);	return uri;}unsigned char *get_extension_from_uri(struct uri *uri){	unsigned char *extension = NULL;	int afterslash = 1;	unsigned char *pos = uri->data;	assert(pos);	for (; *pos && !end_of_dir(*pos); pos++) {		if (!afterslash && !extension && *pos == '.') {			extension = pos;		} else if (is_uri_dir_sep(uri, *pos)) {			extension = NULL;			afterslash = 1;		} else {			afterslash = 0;		}	}	if (extension && extension < pos)		return memacpy(extension, pos - extension);	return NULL;}/* URI encoding, escaping unallowed characters. */static inline intsafe_char(unsigned char c){	/* RFC 2396, Page 8, Section 2.3 ;-) */	return isident(c) || c == '.' || c == '!' || c == '~'	       || c == '*' || c == '\''|| c == '(' || c == ')';}voidencode_uri_string(struct string *string, unsigned char *name,		  int convert_slashes){	unsigned char n[4];	n[0] = '%';	n[3] = '\0';	for (; *name; name++) {#if 0		/* This is probably correct only for query part of URI..? */		if (*name == ' ') add_char_to_string(data, len, '+');		else#endif		if (safe_char(*name) || (!convert_slashes && *name == '/')) {			add_char_to_string(string, *name);		} else {			/* Hex it. */			n[1] = hx((((int) *name) & 0xF0) >> 4);			n[2] = hx(((int) *name) & 0xF);			add_bytes_to_string(string, n, sizeof(n) - 1);		}	}}/* This function is evil, it modifies its parameter. *//* XXX: but decoded string is _never_ longer than encoded string so it's an * efficient way to do that, imho. --Zas */voiddecode_uri(unsigned char *src){	unsigned char *dst = src;	unsigned char c;	do {		c = *src++;		if (c == '%') {			int x1 = unhx(*src);			if (x1 >= 0) {				int x2 = unhx(*(src + 1));				if (x2 >= 0) {					x1 = (x1 << 4) + x2;					if (x1 != 0) { /* don't allow %00 */						c = (unsigned char) x1;						src += 2;					}				}			}#if 0		} else if (c == '+') {			/* As the comment in encode_uri_string suggests, '+'			 * should only be decoded in the query part of a URI			 * (should that be 'URL'?). I'm not bold enough to			 * disable this code, tho. -- Miciah */			c = ' ';#endif		}		*dst++ = c;	} while (c != '\0');}voiddecode_uri_string(struct string *string){	decode_uri(string->source);	string->length = strlen(string->source);}voiddecode_uri_for_display(unsigned char *src){	decode_uri(src);	for (; *src; src++)		if (!isprint(*src) || iscntrl(*src))			*src = '*';}voiddecode_uri_string_for_display(struct string *string){	decode_uri_for_display(string->source);	string->length = strlen(string->source);}/* URI list */#define URI_LIST_GRANULARITY 0x3#define realloc_uri_list(list) \	mem_align_alloc(&(list)->uris, (list)->size, (list)->size + 1, \			struct uri *, URI_LIST_GRANULARITY)struct uri *add_to_uri_list(struct uri_list *list, struct uri *uri){	if (!realloc_uri_list(list))		return NULL;	list->uris[list->size++] = get_uri_reference(uri);	return uri;};voidfree_uri_list(struct uri_list *list){	struct uri *uri;	int index;	if (!list->uris) return;	foreach_uri (uri, index, list) {		done_uri(uri);	}	mem_free(list->uris);	list->size = 0;}/* URI cache */struct uri_cache_entry {	struct uri uri;	unsigned char string[1];};struct uri_cache {	struct hash *map;	struct object object;};static struct uri_cache uri_cache;#ifdef CONFIG_DEBUGstatic inline voidcheck_uri_sanity(struct uri *uri){	int pos;	for (pos = 0; pos < uri->protocollen; pos++)		if (isupper(uri->string[pos])) goto error;	if (uri->hostlen)		for (pos = 0; pos < uri->hostlen; pos++)			if (isupper(uri->host[pos])) goto error;	return;error:	INTERNAL("Uppercase letters detected in protocol or host part (%s).", struri(uri));}#else#define check_uri_sanity(uri)#endifstatic inline struct uri_cache_entry *get_uri_cache_entry(unsigned char *string, int length){	struct uri_cache_entry *entry;	struct hash_item *item;	assert(string && length > 0);	if_assert_failed return NULL;	item = get_hash_item(uri_cache.map, string, length);	if (item) return item->value;	/* Setup a new entry */	entry = mem_calloc(1, sizeof(*entry) + length);	if (!entry) return NULL;	object_nolock(&entry->uri, "uri");	memcpy(&entry->string, string, length);	string = entry->string;	if (parse_uri(&entry->uri, string) != URI_ERRNO_OK	    || !add_hash_item(uri_cache.map, string, length, entry)) {		mem_free(entry);		return NULL;	}	object_lock(&uri_cache);	return entry;}struct uri *get_uri(unsigned char *string, enum uri_component components){	struct uri_cache_entry *entry;	assert(string);	if (components) {		struct uri uri;		if (parse_uri(&uri, string) != URI_ERRNO_OK)			return NULL;		return get_composed_uri(&uri, components);	}	if (!is_object_used(&uri_cache)) {		uri_cache.map = init_hash(hash_size(3), strhash);		if (!uri_cache.map) return NULL;		object_nolock(&uri_cache, "uri_cache");	}	entry = get_uri_cache_entry(string, strlen(string));	if (!entry) {		if (!is_object_used(&uri_cache))			free_hash(uri_cache.map);		return NULL;	}	check_uri_sanity(&entry->uri);	object_nolock(&entry->uri, "uri");	object_lock(&entry->uri);	return &entry->uri;}voiddone_uri(struct uri *uri){	unsigned char *string = struri(uri);	int length = strlen(string);	struct hash_item *item;	struct uri_cache_entry *entry;	assert(is_object_used(&uri_cache));	object_unlock(uri);	if (is_object_used(uri)) return;	item = get_hash_item(uri_cache.map, string, length);	entry = item ? item->value : NULL;	assertm(entry, "Releasing unknown URI [%s]", string);	del_hash_item(uri_cache.map, item);	mem_free(entry);	/* Last URI frees the cache */	object_unlock(&uri_cache);	if (!is_object_used(&uri_cache))		free_hash(uri_cache.map);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -