Example #1
0
static int request_check_hostname(server * srv, connection * con, buffer * host)
{
	enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
	size_t i;
	int label_len = 0;
	size_t host_len;
	char *colon;
	int is_ip = -1;				/* -1 don't know yet, 0 no, 1 yes */
	int level = 0;

	UNUSED(srv);
	UNUSED(con);

	/*
	 *       hostport      = host [ ":" port ]
	 *       host          = hostname | IPv4address | IPv6address
	 *       hostname      = *( domainlabel "." ) toplabel [ "." ]
	 *       domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
	 *       toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
	 *       IPv4address   = 1*digit "." 1*digit "." 1*digit "." 1*digit
	 *       IPv6address   = "[" ... "]" //IPv6地址用[]包围.
	 *       port          = *digit
	 */

	/*
	 * no Host: 
	 */
	if (!host || host->used == 0)
		return 0;

	host_len = host->used - 1;

	/*
	 * IPv6 adress 
	 */
	if (host->ptr[0] == '[')
	{
		char *c = host->ptr + 1;
		int colon_cnt = 0;

		/*
		 * check portnumber 
		 */
		for (; *c && *c != ']'; c++)
		{
			if (*c == ':')
			{
				//至多7个分号。
				if (++colon_cnt > 7)
				{
					return -1;
				}
			} 
			else if (!light_isxdigit(*c))
			{
				return -1;
			}
		}

		/*
		 * missing ] 
		 */
		if (!*c)
		{
			return -1;
		}

		/*
		 * check port 
		 */
		if (*(c + 1) == ':')
		{
			for (c += 2; *c; c++)
			{
				if (!light_isdigit(*c))
				{
					return -1;
				}
			}
		}
		return 0;
	}

	if (NULL != (colon = memchr(host->ptr, ':', host_len)))
	{
		char *c = colon + 1;

		/*
		 * check portnumber 
		 */
		for (; *c; c++)
		{
			if (!light_isdigit(*c))
				return -1;
		}

		/*
		 * remove the port from the host-len 
		 */
		host_len = colon - host->ptr;
	}

	/*
	 * Host is empty 
	 */
	if (host_len == 0)
		return -1;

	/*
	 * if the hostname ends in a "." strip it 
	 */
	if (host->ptr[host_len - 1] == '.')
		host_len -= 1;

	/*
	 * scan from the right and skip the \0 
	 */
	for (i = host_len - 1; i + 1 > 0; i--)
	{
		const char c = host->ptr[i];

		switch (stage)
		{
		case TOPLABEL:
			if (c == '.')
			{
				/*/**
 * header lines中的value,可以是以","分割的多个value。
 * 这个函数将v中value,按照","分割成多个值,存放在vals中。
 */
int http_request_split_value(array * vals, buffer * b)
{
	char *s;
	size_t i;
	int state = 0;
	/*
	 * parse
	 * val1, val2, val3, val4
	 * into a array (more or less a explode() incl. striping of whitespaces
	 */

	if (b->used == 0)
		return 0;
	s = b->ptr;
	for (i = 0; i < b->used - 1;)
	{
		char *start = NULL, *end = NULL;
		data_string *ds;

		switch (state)
		{
		case 0:				/* ws */

			/*
			 * skip ws 
			 */
			for (; (*s == ' ' || *s == '\t') && i < b->used - 1; i++, s++);

			state = 1;
			break;
		case 1:				/* value */
			start = s;

			for (; *s != ',' && i < b->used - 1; i++, s++);
			end = s - 1;
			//去掉空格
			for (; (*end == ' ' || *end == '\t') && end > start; end--);

			if (NULL ==	(ds = (data_string *) array_get_unused_element(vals, TYPE_STRING)))
			{
				ds = data_string_init();
			}

			buffer_copy_string_len(ds->value, start, end - start + 1);
			array_insert_unique(vals, (data_unset *) ds);

			if (*s == ',')
			{
				state = 0;
				i++;
				s++;
			} 
			else
			{
				/*
				 * end of string 
				 */
				state = 2;
			}
			break;
		default:
			i++;
			break;
		}
	}
	return 0;
}
				 * only switch stage, if this is not the last character 
				 */
				if (i != host_len - 1)
				{
					if (label_len == 0)
					{
						return -1;
					}

					/*
					 * check the first character at right of the dot 
					 */
					if (is_ip == 0)
					{
						if (!light_isalpha(host->ptr[i + 1]))
						{
							return -1;
						}
					} 
					else if (!light_isdigit(host->ptr[i + 1]))
					{
						is_ip = 0;
					} 
					else if ('-' == host->ptr[i + 1])
					{
						return -1;
					} 
					else
					{
						/*
						 * just digits 
						 */
						is_ip = 1;
					}

					stage = DOMAINLABEL;

					label_len = 0;
					level++;
				} 
				else if (i == 0)
				{
					/*
					 * just a dot and nothing else is evil 
					 */
					return -1;
				}
			} 
			else if (i == 0)
static handler_t proxy_http_parse_chunked_stream(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out) {
	protocol_state_data *data = (protocol_state_data *)sess->proxy_con->protocol_data;
	char *err = NULL;
	off_t we_have = 0, we_want = 0;
	off_t chunk_len = 0;
	off_t offset = 0;
	buffer *b;
	chunk *c;
	char ch = '\0';
	int finished = 0;

	UNUSED(srv);

	for (c = in->first; c && !finished;) {
		if(c->mem->used == 0) {
			c = c->next;
			continue;
		}
		switch(data->chunk_parse_state) {
		case HTTP_CHUNK_LEN:
			/* parse chunk len. */
			for(offset = c->offset; (size_t)(offset) < (c->mem->used - 1) ; offset++) {
				ch = c->mem->ptr[offset];
				if(!light_isxdigit(ch)) break;
			}
			if(offset > c->offset) {
				buffer_append_string_len(data->buf, (c->mem->ptr + c->offset), offset - c->offset);
				in->bytes_out += (offset - c->offset);
				c->offset = offset;
			}
			if (!(ch == ' ' || ch == '\r' || ch == ';')) {
				if (ch == '\0') {
					/* get next chunk from queue */
					break;
				}
				/* protocol error.  bad http-chunk len */
				return HANDLER_ERROR;
			}
			data->chunk_len = strtol(BUF_STR(data->buf), &err, 16);
			data->chunk_offset = 0;
			buffer_reset(data->buf);
			data->chunk_parse_state = HTTP_CHUNK_EXTENSION;
		case HTTP_CHUNK_EXTENSION:
			/* find CRLF.  discard chunk-extension */
			for(ch = 0; (size_t)(c->offset) < (c->mem->used - 1) && ch != '\n' ;) {
				ch = c->mem->ptr[c->offset];
				c->offset++;
				in->bytes_out++;
			}
			if(ch != '\n') {
				/* get next chunk from queue */
				break;
			}
			if(data->chunk_len > 0) {
				data->chunk_parse_state = HTTP_CHUNK_DATA;
			} else {
				data->chunk_parse_state = HTTP_CHUNK_END;
			}
		case HTTP_CHUNK_DATA:
			chunk_len = data->chunk_len - data->chunk_offset;
			/* copy chunk_len bytes from in queue to out queue. */
			we_have = c->mem->used - c->offset - 1;
			we_want = chunk_len > we_have ? we_have : chunk_len;

			if (c->offset == 0 && we_want == we_have) {
				/* we are copying the whole buffer, just steal it */
				chunkqueue_steal_chunk(out, c);
				/* c is an empty chunk now */
			} else {
				b = chunkqueue_get_append_buffer(out);
				buffer_copy_string_len(b, c->mem->ptr + c->offset, we_want);
				c->offset += we_want;
			}

			chunk_len -= we_want;
			out->bytes_in += we_want;
			in->bytes_out += we_want;
			data->chunk_offset += we_want;
			if(chunk_len > 0) {
				/* get next chunk from queue */
				break;
			}
			data->chunk_offset = 0;
			data->chunk_parse_state = HTTP_CHUNK_END;
		case HTTP_CHUNK_END:
			/* discard CRLF.*/
			for(ch = 0; c->mem->used > 0 && (size_t)(c->offset) < (c->mem->used - 1) && ch != '\n' ;) {
				ch = c->mem->ptr[c->offset];
				c->offset++;
				in->bytes_out++;
			}
			if(ch != '\n') {
				/* get next chunk from queue */
				break;
			}
			/* final chunk */
			if(data->chunk_len == 0) {
				finished = 1;
			}
			/* finished http-chunk.  reset and parse next chunk. */
			protocol_state_data_reset(data);
			break;
		}
		if((size_t)(c->offset) == c->mem->used - 1) {
			c = c->next;
		}
	}
	chunkqueue_remove_finished_chunks(in);
	if (finished) {
		sess->is_request_finished = 1;
		return HANDLER_FINISHED;
	}
	/* ran out of data. */
	return HANDLER_GO_ON;
}
Example #3
0
static int request_check_hostname(buffer *host) {
	enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
	size_t i;
	int label_len = 0;
	size_t host_len, hostport_len;
	char *colon;
	int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
	int level = 0;

	/*
	 *       hostport      = host [ ":" port ]
	 *       host          = hostname | IPv4address | IPv6address
	 *       hostname      = *( domainlabel "." ) toplabel [ "." ]
	 *       domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
	 *       toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
	 *       IPv4address   = 1*digit "." 1*digit "." 1*digit "." 1*digit
	 *       IPv6address   = "[" ... "]"
	 *       port          = *digit
	 */

	/* IPv6 adress */
	if (host->ptr[0] == '[') {
		char *c = host->ptr + 1;
		int colon_cnt = 0;

		/* check the address inside [...] */
		for (; *c && *c != ']'; c++) {
			if (*c == ':') {
				if (++colon_cnt > 7) {
					return -1;
				}
			} else if (!light_isxdigit(*c) && '.' != *c) {
				return -1;
			}
		}

		/* missing ] */
		if (!*c) {
			return -1;
		}

		/* check port */
		if (*(c+1) == ':') {
			for (c += 2; *c; c++) {
				if (!light_isdigit(*c)) {
					return -1;
				}
			}
		}
		else if ('\0' != *(c+1)) {
			/* only a port is allowed to follow [...] */
			return -1;
		}
		return 0;
	}

	hostport_len = host_len = buffer_string_length(host);

	if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
		char *c = colon + 1;

		/* check portnumber */
		for (; *c; c++) {
			if (!light_isdigit(*c)) return -1;
		}

		/* remove the port from the host-len */
		host_len = colon - host->ptr;
	}

	/* Host is empty */
	if (host_len == 0) return -1;

	/* if the hostname ends in a "." strip it */
	if (host->ptr[host_len-1] == '.') {
		/* shift port info one left */
		if (NULL != colon) memmove(colon-1, colon, hostport_len - host_len);
		buffer_string_set_length(host, --hostport_len);
		if (--host_len == 0) return -1;
	}


	/* scan from the right and skip the \0 */
	for (i = host_len; i-- > 0; ) {
		const char c = host->ptr[i];

		switch (stage) {
		case TOPLABEL:
			if (c == '.') {
				/* only switch stage, if this is not the last character */
				if (i != host_len - 1) {
					if (label_len == 0) {
						return -1;
					}

					/* check the first character at right of the dot */
					if (is_ip == 0) {
						if (!light_isalnum(host->ptr[i+1])) {
							return -1;
						}
					} else if (!light_isdigit(host->ptr[i+1])) {
						is_ip = 0;
					} else if ('-' == host->ptr[i+1]) {
						return -1;
					} else {
						/* just digits */
						is_ip = 1;
					}

					stage = DOMAINLABEL;

					label_len = 0;
					level++;
				} else if (i == 0) {
					/* just a dot and nothing else is evil */
					return -1;
				}
			} else if (i == 0) {
				/* the first character of the hostname */
				if (!light_isalnum(c)) {
					return -1;
				}
				label_len++;
			} else {
				if (c != '-' && !light_isalnum(c)) {
					return -1;
				}
				if (is_ip == -1) {
					if (!light_isdigit(c)) is_ip = 0;
				}
				label_len++;
			}

			break;
		case DOMAINLABEL:
			if (is_ip == 1) {
				if (c == '.') {
					if (label_len == 0) {
						return -1;
					}

					label_len = 0;
					level++;
				} else if (!light_isdigit(c)) {
					return -1;
				} else {
					label_len++;
				}
			} else {
				if (c == '.') {
					if (label_len == 0) {
						return -1;
					}

					/* c is either - or alphanum here */
					if ('-' == host->ptr[i+1]) {
						return -1;
					}

					label_len = 0;
					level++;
				} else if (i == 0) {
					if (!light_isalnum(c)) {
						return -1;
					}
					label_len++;
				} else {
					if (c != '-' && !light_isalnum(c)) {
						return -1;
					}
					label_len++;
				}
			}

			break;
		}
	}

	/* a IP has to consist of 4 parts */
	if (is_ip == 1 && level != 3) {
		return -1;
	}

	if (label_len == 0) {
		return -1;
	}

	return 0;
}