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

📄 http.c

📁 一个很有名的浏览器
💻 C
📖 第 1 页 / 共 4 页
字号:
	 * we will always have at least PIPE_BUF / 2 + 1 in the pipe (returning	 * early otherwise)). */	int to_read = PIPE_BUF / 2, did_read = 0;	int *length_of_block;	unsigned char *output = NULL;	length_of_block = (info->length == LEN_CHUNKED ? &info->chunk_remaining						       : &info->length);#define BIG_READ 65536	if (!*length_of_block) {		/* Going to finish this decoding bussiness. */		/* Some nicely big value - empty encoded output queue by reading		 * big chunks from it. */		to_read = BIG_READ;	}	if (conn->content_encoding == ENCODING_NONE) {		*new_len = len;		if (*length_of_block > 0) *length_of_block -= len;		return data;	}	*new_len = 0; /* new_len must be zero if we would ever return NULL */	if (conn->stream_pipes[0] == -1	    && (c_pipe(conn->stream_pipes) < 0		|| set_nonblocking_fd(conn->stream_pipes[0]) < 0		|| set_nonblocking_fd(conn->stream_pipes[1]) < 0)) {		return NULL;	}	do {		int init = 0;		if (to_read == PIPE_BUF / 2) {			/* ... we aren't finishing yet. */			int written = safe_write(conn->stream_pipes[1], data,						 len > to_read ? to_read : len);			if (written > 0) {				data += written;				len -= written;				/* In non-keep-alive connections info->length == -1, so the test below */				if (*length_of_block > 0)					*length_of_block -= written;				/* info->length is 0 at the end of block for all modes: keep-alive,				 * non-keep-alive and chunked */				if (!info->length) {					/* That's all, folks - let's finish this. */					to_read = BIG_READ;				} else if (!len) {					/* We've done for this round (but not done					 * completely). Thus we will get out with					 * what we have and leave what we wrote to					 * the next round - we have to do that since					 * we MUST NOT ever empty the pipe completely					 * - this would cause a disaster for					 * read_encoded(), which would simply not					 * work right then. */					return output;				}			}		}		if (!conn->stream) {			conn->stream = open_encoded(conn->stream_pipes[0],					conn->content_encoding);			if (!conn->stream) return NULL;			/* On "startup" pipe is treated with care, but if everything			 * was already written to the pipe, caution isn't necessary */			else if (to_read != BIG_READ) init = 1;		} else init = 0;		output = (unsigned char *) mem_realloc(output, *new_len + to_read);		if (!output) break;		did_read = read_encoded(conn->stream, output + *new_len,					init ? PIPE_BUF / 32 : to_read); /* on init don't read too much */		if (did_read > 0) *new_len += did_read;		else if (did_read == -1) {			mem_free_set(&output, NULL);			*new_len = 0;			break; /* Loop prevention (bug 517), is this correct ? --Zas */		}	} while (!(!len && did_read != to_read));	decompress_shutdown(conn);	return output;}/* FIXME: Unfortunately, we duplicate this in free_connection_data(). */static voiddecompress_shutdown(struct connection *conn){	if (conn->stream) {		close_encoded(conn->stream);		conn->stream = NULL;	}	if (conn->stream_pipes[1] >= 0)		close(conn->stream_pipes[1]);	conn->stream_pipes[0] = conn->stream_pipes[1] = -1;}static intis_line_in_buffer(struct read_buffer *rb){	int l;	for (l = 0; l < rb->len; l++) {		unsigned char a0 = rb->data[l];		if (a0 == ASCII_LF)			return l + 1;		if (a0 == ASCII_CR) {			if (rb->data[l + 1] == ASCII_LF			    && l < rb->len - 1)				return l + 2;			if (l == rb->len - 1)				return 0;		}		if (a0 < ' ')			return -1;	}	return 0;}static void read_http_data(struct connection *conn, struct read_buffer *rb);static voidread_more_http_data(struct connection *conn, struct read_buffer *rb,                    int already_got_anything){	read_from_socket(conn, &conn->socket, rb, read_http_data);	if (already_got_anything)		set_connection_state(conn, S_TRANS);}static voidread_http_data_done(struct connection *conn){	struct http_connection_info *info = conn->info;	/* There's no content but an error so just print	 * that instead of nothing. */	if (!conn->from) {		if (info->http_code >= 400) {			http_error_document(conn, info->http_code);		} else {			/* This is not an error, thus fine. No need generate any			 * document, as this may be empty and it's not a problem.			 * In case of 3xx, we're probably just getting kicked to			 * another page anyway. And in case of 2xx, the document			 * may indeed be empty and thus the user should see it so. */		}	}	http_end_request(conn, S_OK, 0);}/* Returns: * -1 on error * 0 if more to read * 1 if done */static intread_chunked_http_data(struct connection *conn, struct read_buffer *rb){	struct http_connection_info *info = conn->info;	int total_data_len = 0;	while (1) {		/* Chunked. Good luck! */		/* See RFC2616, section 3.6.1. Basically, it looks like:		 * 1234 ; a = b ; c = d\r\n		 * aklkjadslkfjalkfjlkajkljfdkljdsfkljdf*1234\r\n		 * 0\r\n		 * \r\n */		if (info->chunk_remaining == CHUNK_DATA_END) {			int l = is_line_in_buffer(rb);			if (l) {				if (l == -1) {					/* Invalid character in buffer. */					return -1;				}				/* Remove everything to the EOLN. */				kill_buffer_data(rb, l);				if (l <= 2) {					/* Empty line. */					return 2;				}				continue;			}		} else if (info->chunk_remaining == CHUNK_SIZE) {			int l = is_line_in_buffer(rb);			if (l) {				unsigned char *de;				int n = 0;				if (l != -1) {					errno = 0;					n = strtol(rb->data, (char **) &de, 16);					if (errno || !*de) {						return -1;					}				}				if (l == -1 || de == rb->data) {					return -1;				}				/* Remove everything to the EOLN. */				kill_buffer_data(rb, l);				info->chunk_remaining = n;				if (!info->chunk_remaining)					info->chunk_remaining = CHUNK_ZERO_SIZE;				continue;			}		} else {			unsigned char *data;			int data_len;			int len;			int zero = (info->chunk_remaining == CHUNK_ZERO_SIZE);			if (zero) info->chunk_remaining = 0;			len = info->chunk_remaining;			/* Maybe everything necessary didn't come yet.. */			int_upper_bound(&len, rb->len);			conn->received += len;			data = decompress_data(conn, rb->data, len, &data_len);			if (add_fragment(conn->cached, conn->from,					 data, data_len) == 1)				conn->tries = 0;			if (data && data != rb->data) mem_free(data);			conn->from += data_len;			total_data_len += data_len;			kill_buffer_data(rb, len);			if (zero) {				/* Last chunk has zero length, so this is last				 * chunk, we finished decompression just now				 * and now we can happily finish reading this				 * stuff. */				info->chunk_remaining = CHUNK_DATA_END;				continue;			}			if (!info->chunk_remaining && rb->len > 0) {				/* Eat newline succeeding each chunk. */				if (rb->data[0] == ASCII_LF) {					kill_buffer_data(rb, 1);				} else {					if (rb->data[0] != ASCII_CR					    || (rb->len >= 2						&& rb->data[1] != ASCII_LF)) {						return -1;					}					if (rb->len < 2) break;					kill_buffer_data(rb, 2);				}				info->chunk_remaining = CHUNK_SIZE;				continue;			}		}		break;	}	/* More to read. */	return !!total_data_len;}/* Returns 0 if more data, 1 if done. */static intread_normal_http_data(struct connection *conn, struct read_buffer *rb){	struct http_connection_info *info = conn->info;	unsigned char *data;	int data_len;	int len = rb->len;	if (info->length >= 0 && info->length < len) {		/* We won't read more than we have to go. */		len = info->length;	}	conn->received += len;	data = decompress_data(conn, rb->data, len, &data_len);	if (add_fragment(conn->cached, conn->from, data, data_len) == 1)		conn->tries = 0;	if (data && data != rb->data) mem_free(data);	conn->from += data_len;	kill_buffer_data(rb, len);	if (!info->length && rb->close == READ_BUFFER_RETRY_ONCLOSE) {		return 2;	}	return !!data_len;}static voidread_http_data(struct connection *conn, struct read_buffer *rb){	struct http_connection_info *info = conn->info;	int ret;	set_connection_timeout(conn);	if (rb->close == READ_BUFFER_END) {		if (conn->content_encoding && info->length == -1) {			/* Flush decompression first. */			info->length = 0;		} else {			read_http_data_done(conn);			return;		}	}	if (info->length != LEN_CHUNKED) {		ret = read_normal_http_data(conn, rb);	} else {		ret = read_chunked_http_data(conn, rb);	}	switch (ret) {	case -1:		abort_conn_with_state(conn, S_HTTP_ERROR);		break;	case 0:		read_more_http_data(conn, rb, 0);		break;	case 1:		read_more_http_data(conn, rb, 1);		break;	case 2:		read_http_data_done(conn);		break;	default:		INTERNAL("Unexpected return value: %d", ret);	}}/* Returns offset of the header end, zero if more data is needed, -1 when * incorrect data was received, -2 if this is HTTP/0.9 and no header is to * come. */static intget_header(struct read_buffer *rb){	int i;	/* XXX: We will have to do some guess about whether an HTTP header is	 * coming or not, in order to support HTTP/0.9 reply correctly. This	 * means a little code duplication with get_http_code(). --pasky */	if (rb->len > 4 && strncasecmp(rb->data, "HTTP/", 5))		return -2;	for (i = 0; i < rb->len; i++) {		unsigned char a0 = rb->data[i];		unsigned char a1 = rb->data[i + 1];		if (a0 == 0) {			rb->data[i] = ' ';			continue;		}		if (a0 == ASCII_LF && a1 == ASCII_LF		    && i < rb->len - 1)			return i + 2;		if (a0 == ASCII_CR && i < rb->len - 3) {			if (a1 == ASCII_CR) continue;			if (a1 != ASCII_LF) return -1;			if (rb->data[i + 2] == ASCII_CR) {				if (rb->data[i + 3] != ASCII_LF) return -1;				return i + 4;			}		}	}	return 0;}static voidcheck_http_authentication(struct uri *uri, unsigned char *header,			  unsigned char *header_field){	unsigned char *str, *d;	d = parse_header(header, header_field, &str);	while (d) {		if (!strncasecmp(d, "Basic", 5)) {			unsigned char *realm = get_header_param(d, "realm");			if (realm) {				add_auth_entry(uri, realm, NULL, NULL, 0);				mem_free(realm);				mem_free(d);				break;			}		} else if (!strncasecmp(d, "Digest", 6)) {			unsigned char *realm = get_header_param(d, "realm");			unsigned char *nonce = get_header_param(d, "nonce");			unsigned char *opaque = get_header_param(d, "opaque");			add_auth_entry(uri, realm, nonce, opaque, 1);			mem_free_if(realm);			mem_free_if(nonce);			mem_free_if(opaque);			mem_free(d);			break;		}		mem_free(d);		d = parse_header(str, header_field, &str);	}}voidhttp_got_header(struct connection *conn, struct read_buffer *rb){	struct http_connection_info *info = conn->info;	unsigned char *head;#ifdef CONFIG_COOKIES	unsigned char *cookie, *ch;#endif	unsigned char *d;	struct uri *uri = conn->proxied_uri; /* Set to the real uri */	struct http_version version;	enum connection_state state = (conn->state != S_PROC ? S_GETH : S_PROC);	int a, h = 200;	int cf;	set_connection_timeout(conn);

⌨️ 快捷键说明

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