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

📄 http.c

📁 一个很有名的浏览器
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (rb->close == READ_BUFFER_END) {		if (!conn->tries && uri->host) {			if (info->bl_flags & SERVER_BLACKLIST_NO_CHARSET) {				del_blacklist_entry(uri, SERVER_BLACKLIST_NO_CHARSET);			} else {				add_blacklist_entry(uri, SERVER_BLACKLIST_NO_CHARSET);				conn->tries = -1;			}		}		retry_conn_with_state(conn, S_CANT_READ);		return;	}	rb->close = READ_BUFFER_RETRY_ONCLOSE;again:	a = get_header(rb);	if (a == -1) {		abort_conn_with_state(conn, S_HTTP_ERROR);		return;	}	if (!a) {		read_from_socket(conn, &conn->socket, rb, http_got_header);		set_connection_state(conn, state);		return;	}	if (a == -2) a = 0;	if ((a && get_http_code(rb->data, &h, &version))	    || h == 101) {		abort_conn_with_state(conn, S_HTTP_ERROR);		return;	}	/* When no header, HTTP/0.9 document. That's always text/html,	 * according to	 * http://www.w3.org/Protocols/HTTP/AsImplemented.html. */	/* FIXME: This usage of fake protocol headers for setting up the	 * content type has been obsoleted by the @content_type member of	 * {struct cache_entry}. */	head = (a ? memacpy(rb->data, a)		  : stracpy("\r\nContent-Type: text/html\r\n"));	if (!head) {		abort_conn_with_state(conn, S_OUT_OF_MEM);		return;	}	if (check_http_server_bugs(uri, info, head)) {		mem_free(head);		retry_conn_with_state(conn, S_RESTART);		return;	}#ifdef CONFIG_CGI	if (uri->protocol == PROTOCOL_FILE) {		/* ``Status'' is not a standard HTTP header field although some		 * HTTP servers like www.php.net uses it for some reason. It should		 * only be used for CGI scripts so that it does not interfere		 * with status code depended handling for ``normal'' HTTP like		 * redirects. */		d = parse_header(head, "Status", NULL);		if (d) {			int h2 = atoi(d);			mem_free(d);			if (h2 >= 100 && h2 < 600) h = h2;			if (h == 101) {				mem_free(head);				abort_conn_with_state(conn, S_HTTP_ERROR);				return;			}		}	}#endif#ifdef CONFIG_COOKIES	ch = head;	while ((cookie = parse_header(ch, "Set-Cookie", &ch))) {		set_cookie(uri, cookie);		mem_free(cookie);	}#endif	info->http_code = h;	if (h == 100) {		mem_free(head);		state = S_PROC;		kill_buffer_data(rb, a);		goto again;	}	if (h < 200) {		mem_free(head);		abort_conn_with_state(conn, S_HTTP_ERROR);		return;	}	if (h == 304) {		mem_free(head);		http_end_request(conn, S_OK, 1);		return;	}	if (h == 204) {		mem_free(head);		http_end_request(conn, S_HTTP_204, 0);		return;	}	if (h == 200 && connection_is_https_proxy(conn) && !conn->socket.ssl) {#ifdef CONFIG_SSL		mem_free(head);		conn->conn_info = init_connection_info(uri, &conn->socket,						       http_send_header);		if (!conn->conn_info) {			abort_conn_with_state(conn, S_OUT_OF_MEM);			return;		}		if (ssl_connect(conn, &conn->socket) == -1) return;#else		abort_conn_with_state(conn, S_SSL_ERROR);#endif		return;	}	conn->cached = get_cache_entry(conn->uri);	if (!conn->cached) {		mem_free(head);		abort_conn_with_state(conn, S_OUT_OF_MEM);		return;	}	mem_free_set(&conn->cached->head, head);	if (!get_opt_bool("document.cache.ignore_cache_control")) {		struct cache_entry *cached = conn->cached;		/* I am not entirely sure in what order we should process these		 * headers and if we should still process Cache-Control max-age		 * if we already set max age to date mentioned in Expires.		 * --jonas */		/* Ensure that when ever cached->max_age is set, cached->expired		 * is also set, so the cache management knows max_age contains a		 * valid time. If on the other hand no caching is requested		 * cached->expire should be set to zero.  */		if ((d = parse_header(cached->head, "Expires", NULL))) {			/* Convert date to seconds. */			time_t expires = parse_date(&d, NULL, 0, 1);			mem_free(d);			if (expires && cached->cache_mode != CACHE_MODE_NEVER) {				cached->max_age = expires;				cached->expire = 1;			}		}		if ((d = parse_header(cached->head, "Pragma", NULL))) {			if (strstr(d, "no-cache")) {				cached->cache_mode = CACHE_MODE_NEVER;				cached->expire = 0;			}			mem_free(d);		}		if (cached->cache_mode != CACHE_MODE_NEVER		    && (d = parse_header(cached->head, "Cache-Control", NULL))) {			if (strstr(d, "no-cache") || strstr(d, "must-revalidate")) {				cached->cache_mode = CACHE_MODE_NEVER;				cached->expire = 0;			} else  {				unsigned char *pos = strstr(d, "max-age=");				assert(cached->cache_mode != CACHE_MODE_NEVER);				if (pos) {					/* Grab the number of seconds. */					time_t max_age = str_to_ttime(pos + 8);					cached->max_age = max_age + time(NULL);					cached->expire = 1;				}			}			mem_free(d);		}	}#ifdef CONFIG_SSL	/* TODO: Move this to some more generic place like lowlevel/connect.c	 * or sched/connection.c when other protocols will need it. --jonas */	if (conn->socket.ssl)		mem_free_set(&conn->cached->ssl_info, get_ssl_connection_cipher(conn));#endif	/* XXX: Is there some reason why NOT to follow the Location header	 * for any status? If the server didn't mean it, it wouldn't send	 * it, after all...? --pasky */	if (h == 201 || h == 301 || h == 302 || h == 303 || h == 307) {		d = parse_header(conn->cached->head, "Location", NULL);		if (d) {			int use_get_method = (h == 303);			/* A note from RFC 2616 section 10.3.3:			 * RFC 1945 and RFC 2068 specify that the client is not			 * allowed to change the method on the redirected			 * request. However, most existing user agent			 * implementations treat 302 as if it were a 303			 * response, performing a GET on the Location			 * field-value regardless of the original request			 * method. */			/* So POST must not be redirected to GET, but some			 * BUGGY message boards rely on it :-( */	    		if (h == 302			    && get_opt_bool("protocol.http.bugs.broken_302_redirect"))				use_get_method = 1;			redirect_cache(conn->cached, d, use_get_method, -1);			mem_free(d);		}	}	if (h == 401) {		unsigned char *head = conn->cached->head;		check_http_authentication(uri, head, "WWW-Authenticate");	}	if (h == 407) {		unsigned char *str;		d = parse_header(conn->cached->head, "Proxy-Authenticate", &str);		while (d) {			if (!strncasecmp(d, "Basic", 5)) {				unsigned char *realm = get_header_param(d, "realm");				if (realm) {					mem_free_set(&proxy_auth.realm, realm);					proxy_auth.digest = 0;					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");				mem_free_set(&proxy_auth.realm, realm);				mem_free_set(&proxy_auth.nonce, nonce);				mem_free_set(&proxy_auth.opaque, opaque);				proxy_auth.digest = 1;				mem_free(d);				break;			}			mem_free(d);			d = parse_header(str, "Proxy-Authenticate", &str);		}	}	kill_buffer_data(rb, a);	info->close = 0;	info->length = -1;	info->recv_version = version;	if ((d = parse_header(conn->cached->head, "Connection", NULL))	     || (d = parse_header(conn->cached->head, "Proxy-Connection", NULL))) {		if (!strcasecmp(d, "close")) info->close = 1;		mem_free(d);	} else if (PRE_HTTP_1_1(version)) {		info->close = 1;	}	cf = conn->from;	conn->from = 0;	d = parse_header(conn->cached->head, "Content-Range", NULL);	if (d) {		if (strlen(d) > 6) {			d[5] = 0;			if (isdigit(d[6]) && !strcasecmp(d, "bytes")) {				int f;				errno = 0;				f = strtol(d + 6, NULL, 10);				if (!errno && f >= 0) conn->from = f;			}		}		mem_free(d);	}	if (cf && !conn->from && !conn->unrestartable) conn->unrestartable = 1;	if ((conn->progress.start <= 0 && conn->from > cf) || conn->from < 0) {		/* We don't want this if conn->progress.start because then conn->from will		 * be probably value of conn->progress.start, while cf is 0. */		abort_conn_with_state(conn, S_HTTP_ERROR);		return;	}#if 0	{		struct status *s;		foreach (s, conn->downloads) {			fprintf(stderr, "conn %p status %p pri %d st %d er %d :: ce %s",				conn, s, s->pri, s->state, s->prev_error,				s->cached ? s->cached->url : (unsigned char *) "N-U-L-L");		}	}#endif	if (conn->progress.start >= 0) {		/* Update to the real value which we've got from Content-Range. */		conn->progress.seek = conn->from;	}	conn->progress.start = conn->from;	d = parse_header(conn->cached->head, "Content-Length", NULL);	if (d) {		unsigned char *ep;		int l;		errno = 0;		l = strtol(d, (char **) &ep, 10);		if (!errno && !*ep && l >= 0) {			if (!info->close || POST_HTTP_1_0(version))				info->length = l;			conn->est_length = conn->from + l;		}		mem_free(d);	}	if (!conn->unrestartable) {		d = parse_header(conn->cached->head, "Accept-Ranges", NULL);		if (d) {			if (!strcasecmp(d, "none"))				conn->unrestartable = 1;			mem_free(d);		} else {			if (!conn->from)				conn->unrestartable = 1;		}	}	d = parse_header(conn->cached->head, "Transfer-Encoding", NULL);	if (d) {		if (!strcasecmp(d, "chunked")) {			info->length = LEN_CHUNKED;			info->chunk_remaining = CHUNK_SIZE;		}		mem_free(d);	}	if (!info->close && info->length == -1) info->close = 1;	d = parse_header(conn->cached->head, "Last-Modified", NULL);	if (d) {		if (conn->cached->last_modified && strcasecmp(conn->cached->last_modified, d)) {			delete_entry_content(conn->cached);			if (conn->from) {				conn->from = 0;				mem_free(d);				retry_conn_with_state(conn, S_MODIFIED);				return;			}		}		if (!conn->cached->last_modified) conn->cached->last_modified = d;		else mem_free(d);	}	if (!conn->cached->last_modified) {		d = parse_header(conn->cached->head, "Date", NULL);		if (d) conn->cached->last_modified = d;	}	/* FIXME: Parse only if HTTP/1.1 or later? --Zas */	d = parse_header(conn->cached->head, "ETag", NULL);	if (d) {		if (conn->cached->etag) {			unsigned char *old_tag = conn->cached->etag;			unsigned char *new_tag = d;			/* http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19 */			if (new_tag[0] == 'W' && new_tag[1] == '/')				new_tag += 2;			if (old_tag[0] == 'W' && old_tag[1] == '/')				old_tag += 2;			if (strcmp(new_tag, old_tag)) {				delete_entry_content(conn->cached);				if (conn->from) {					conn->from = 0;					mem_free(d);					retry_conn_with_state(conn, S_MODIFIED);					return;				}			}		}		if (!conn->cached->etag)			conn->cached->etag = d;		else			mem_free(d);	}	d = parse_header(conn->cached->head, "Content-Encoding", NULL);	if (d) {		unsigned char *extension = get_extension_from_uri(uri);		enum stream_encoding file_encoding;		file_encoding = extension ? guess_encoding(extension) : ENCODING_NONE;		mem_free_if(extension);		/* If the content is encoded, we want to preserve the encoding		 * if it is implied by the extension, so that saving the URI		 * will leave the saved file with the correct encoding. */#ifdef CONFIG_GZIP		if (file_encoding != ENCODING_GZIP		    && (!strcasecmp(d, "gzip") || !strcasecmp(d, "x-gzip")))		    	conn->content_encoding = ENCODING_GZIP;#endif#ifdef BUG_517#ifdef CONFIG_BZIP2		if (file_encoding != ENCODING_BZIP2		    && (!strcasecmp(d, "bzip2") || !strcasecmp(d, "x-bzip2")))			conn->content_encoding = ENCODING_BZIP2;#endif#endif		mem_free(d);	}	if (conn->content_encoding != ENCODING_NONE) {		mem_free_if(conn->cached->encoding_info);		conn->cached->encoding_info = stracpy(get_encoding_name(conn->content_encoding));	}	if (info->length == -1	    || (PRE_HTTP_1_1(info->recv_version) && info->close))		rb->close = READ_BUFFER_END_ONCLOSE;	read_http_data(conn, rb);}static voidhttp_get_header(struct connection *conn){	struct read_buffer *rb = alloc_read_buffer(conn);	if (!rb) return;	set_connection_timeout(conn);	rb->close = READ_BUFFER_END_ONCLOSE;	read_from_socket(conn, &conn->socket, rb, http_got_header);}

⌨️ 快捷键说明

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