http.c

来自「elinks下lynx是最重要的二个文本浏览器, 在linux下非常实用, el」· C语言 代码 · 共 1,812 行 · 第 1/4 页

C
1,812
字号
		return 0;	for (s = buggy_servers; *s; s++) {		if (strstr(server, *s)) {			add_blacklist_entry(uri, SERVER_BLACKLIST_HTTP10);			break;		}	}	mem_free(server);	return (*s != NULL);}static voidhttp_end_request(struct connection *conn, enum connection_state state,		 int notrunc){	shutdown_connection_stream(conn);	if (state == S_OK && conn->cached) {		normalize_cache_entry(conn->cached, !notrunc ? conn->from : -1);	}	if (conn->info && !((struct http_connection_info *) conn->info)->close	    && (!conn->socket->ssl) /* We won't keep alive ssl connections */	    && (!get_opt_bool("protocol.http.bugs.post_no_keepalive")		|| !conn->uri->post)) {		set_connection_state(conn, state);		add_keepalive_connection(conn, HTTP_KEEPALIVE_TIMEOUT, NULL);	} else {		abort_connection(conn, state);	}}static void http_send_header(struct socket *);voidhttp_protocol_handler(struct connection *conn){	/* setcstate(conn, S_CONN); */	if (!has_keepalive_connection(conn)) {		make_connection(conn->socket, conn->uri, http_send_header,				conn->cache_mode >= CACHE_MODE_FORCE_RELOAD);	} else {		http_send_header(conn->socket);	}}voidproxy_protocol_handler(struct connection *conn){	http_protocol_handler(conn);}#define IS_PROXY_URI(x) ((x)->protocol == PROTOCOL_PROXY)#define connection_is_https_proxy(conn) \	(IS_PROXY_URI((conn)->uri) && (conn)->proxied_uri->protocol == PROTOCOL_HTTPS)struct http_connection_info *init_http_connection_info(struct connection *conn, int major, int minor, int close){	struct http_connection_info *http;	http = mem_calloc(1, sizeof(*http));	if (!http) {		http_end_request(conn, S_OUT_OF_MEM, 0);		return NULL;	}	http->sent_version.major = major;	http->sent_version.minor = minor;	http->close = close;	/* The CGI code uses this too and blacklisting expects a host name. */	if (conn->proxied_uri->protocol != PROTOCOL_FILE)		http->bl_flags = get_blacklist_flags(conn->proxied_uri);	if (http->bl_flags & SERVER_BLACKLIST_HTTP10	    || get_opt_bool("protocol.http.bugs.http10")) {		http->sent_version.major = 1;		http->sent_version.minor = 0;	}	/* If called from HTTPS proxy connection the connection info might have	 * already been allocated. */	mem_free_set(&conn->info, http);	return http;}static voidhttp_send_header(struct socket *socket){	struct connection *conn = socket->conn;	struct http_connection_info *http;	int trace = get_opt_bool("protocol.http.trace");	struct string header;	unsigned char *post_data = NULL;	struct auth_entry *entry;	struct uri *uri = conn->proxied_uri; /* Set to the real uri */	unsigned char *optstr;	int use_connect, talking_to_proxy;	/* Sanity check for a host */	if (!uri || !uri->host || !*uri->host || !uri->hostlen) {		http_end_request(conn, S_BAD_URL, 0);		return;	}	http = init_http_connection_info(conn, 1, 1, 0);	if (!http) return;	if (!init_string(&header)) {		http_end_request(conn, S_OUT_OF_MEM, 0);		return;	}	talking_to_proxy = IS_PROXY_URI(conn->uri) && !conn->socket->ssl;	use_connect = connection_is_https_proxy(conn) && !conn->socket->ssl;	if (trace) {		add_to_string(&header, "TRACE ");	} else if (use_connect) {		add_to_string(&header, "CONNECT ");	} else if (uri->post) {		add_to_string(&header, "POST ");		conn->unrestartable = 1;	} else {		add_to_string(&header, "GET ");	}	if (!talking_to_proxy) {		add_char_to_string(&header, '/');	}	if (use_connect) {		/* Add port if it was specified or the default port */		add_uri_to_string(&header, uri, URI_HTTP_CONNECT);	} else {		if (connection_is_https_proxy(conn) && conn->socket->ssl) {			add_url_to_http_string(&header, uri, URI_DATA);		} else if (talking_to_proxy) {			add_url_to_http_string(&header, uri, URI_PROXY);		} else {			add_url_to_http_string(&header, conn->uri, URI_DATA);		}	}	add_to_string(&header, " HTTP/");	add_long_to_string(&header, http->sent_version.major);	add_char_to_string(&header, '.');	add_long_to_string(&header, http->sent_version.minor);	add_crlf_to_string(&header);	add_to_string(&header, "Host: ");	add_uri_to_string(&header, uri, URI_HTTP_HOST);	add_crlf_to_string(&header);	if (talking_to_proxy) {		unsigned char *user = get_opt_str("protocol.http.proxy.user");		unsigned char *passwd = get_opt_str("protocol.http.proxy.passwd");		if (proxy_auth.digest) {			unsigned char *response;			int userlen = int_min(strlen(user), AUTH_USER_MAXLEN - 1);			int passwordlen = int_min(strlen(passwd), AUTH_PASSWORD_MAXLEN - 1);			if (userlen)				memcpy(proxy_auth.user, user, userlen);			proxy_auth.user[userlen] = '\0';			if (passwordlen)				memcpy(proxy_auth.password, passwd, passwordlen);			proxy_auth.password[passwordlen] = '\0';			/* FIXME: @uri is the proxied URI. Maybe the passed URI			 * should be the proxy URI aka conn->uri. --jonas */			response = get_http_auth_digest_response(&proxy_auth, uri);			if (response) {				add_to_string(&header, "Proxy-Authorization: Digest ");				add_to_string(&header, response);				add_crlf_to_string(&header);				mem_free(response);			}		} else {			if (user[0]) {				unsigned char *proxy_data;				proxy_data = straconcat(user, ":", passwd, NULL);				if (proxy_data) {					unsigned char *proxy_64 = base64_encode(proxy_data);					if (proxy_64) {						add_to_string(&header, "Proxy-Authorization: Basic ");						add_to_string(&header, proxy_64);						add_crlf_to_string(&header);						mem_free(proxy_64);					}					mem_free(proxy_data);				}			}		}	}	optstr = get_opt_str("protocol.http.user_agent");	if (*optstr && strcmp(optstr, " ")) {		unsigned char *ustr, ts[64] = "";		add_to_string(&header, "User-Agent: ");		if (!list_empty(terminals)) {			unsigned int tslen = 0;			struct terminal *term = terminals.prev;			ulongcat(ts, &tslen, term->width, 3, 0);			ts[tslen++] = 'x';			ulongcat(ts, &tslen, term->height, 3, 0);		}		ustr = subst_user_agent(optstr, VERSION_STRING, system_name,					ts);		if (ustr) {			add_to_string(&header, ustr);			mem_free(ustr);		}		add_crlf_to_string(&header);	}	switch (get_opt_int("protocol.http.referer.policy")) {		case REFERER_NONE:			/* oh well */			break;		case REFERER_FAKE:			optstr = get_opt_str("protocol.http.referer.fake");			if (!optstr[0]) break;			add_to_string(&header, "Referer: ");			add_to_string(&header, optstr);			add_crlf_to_string(&header);			break;		case REFERER_TRUE:			if (!conn->referrer) break;			add_to_string(&header, "Referer: ");			add_url_to_http_string(&header, conn->referrer, URI_HTTP_REFERRER);			add_crlf_to_string(&header);			break;		case REFERER_SAME_URL:			add_to_string(&header, "Referer: ");			add_url_to_http_string(&header, uri, URI_HTTP_REFERRER);			add_crlf_to_string(&header);			break;	}	add_to_string(&header, "Accept: */*");	add_crlf_to_string(&header);	/* TODO: Make this encoding.c function. */#if defined(CONFIG_GZIP) || defined(CONFIG_BZIP2)	add_to_string(&header, "Accept-Encoding: ");#ifdef BUG_517#ifdef CONFIG_BZIP2	add_to_string(&header, "bzip2");#endif#endif#ifdef CONFIG_GZIP#ifdef BUG_517#ifdef CONFIG_BZIP2	add_to_string(&header, ", ");#endif#endif	add_to_string(&header, "gzip");#endif	add_crlf_to_string(&header);#endif	if (!accept_charset) {		init_accept_charset();	}	if (!(http->bl_flags & SERVER_BLACKLIST_NO_CHARSET)	    && !get_opt_bool("protocol.http.bugs.accept_charset")	    && accept_charset) {		add_to_string(&header, accept_charset);	}	optstr = get_opt_str("protocol.http.accept_language");	if (optstr[0]) {		add_to_string(&header, "Accept-Language: ");		add_to_string(&header, optstr);		add_crlf_to_string(&header);	}#ifdef CONFIG_NLS	else if (get_opt_bool("protocol.http.accept_ui_language")) {		unsigned char *code = language_to_iso639(current_language);		if (code) {			add_to_string(&header, "Accept-Language: ");			add_to_string(&header, code);			add_crlf_to_string(&header);		}	}#endif	/* FIXME: What about post-HTTP/1.1?? --Zas */	if (HTTP_1_1(http->sent_version)) {		if (!IS_PROXY_URI(conn->uri)) {			add_to_string(&header, "Connection: ");		} else {			add_to_string(&header, "Proxy-Connection: ");		}		if (!uri->post || !get_opt_bool("protocol.http.bugs.post_no_keepalive")) {			add_to_string(&header, "Keep-Alive");		} else {			add_to_string(&header, "close");		}		add_crlf_to_string(&header);	}	if (conn->cached) {		if (!conn->cached->incomplete && conn->cached->head && conn->cached->last_modified		    && conn->cache_mode <= CACHE_MODE_CHECK_IF_MODIFIED) {			add_to_string(&header, "If-Modified-Since: ");			add_to_string(&header, conn->cached->last_modified);			add_crlf_to_string(&header);		}	}	if (conn->cache_mode >= CACHE_MODE_FORCE_RELOAD) {		add_to_string(&header, "Pragma: no-cache");		add_crlf_to_string(&header);		add_to_string(&header, "Cache-Control: no-cache");		add_crlf_to_string(&header);	}	if (conn->from || conn->progress->start > 0) {		/* conn->from takes precedence. conn->progress.start is set only the first		 * time, then conn->from gets updated and in case of any retries		 * etc we have everything interesting in conn->from already. */		add_to_string(&header, "Range: bytes=");		add_long_to_string(&header, conn->from ? conn->from : conn->progress->start);		add_char_to_string(&header, '-');		add_crlf_to_string(&header);	}	entry = find_auth(uri);	if (entry) {		if (entry->digest) {			unsigned char *response;			response = get_http_auth_digest_response(entry, uri);			if (response) {				add_to_string(&header, "Authorization: Digest ");				add_to_string(&header, response);				add_crlf_to_string(&header);				mem_free(response);			}		} else {			/* RFC2617 section 2 [Basic Authentication Scheme]			 *			 * To receive authorization, the client sends the userid			 * and password, separated by a single colon (":")			 * character, within a base64 [7] encoded string in the			 * credentials. */			unsigned char *id;			/* Create base64 encoded string. */			id = straconcat(entry->user, ":", entry->password, NULL);			if (id) {				unsigned char *base64 = base64_encode(id);				mem_free_set(&id, base64);			}			if (id) {				add_to_string(&header, "Authorization: Basic ");				add_to_string(&header, id);				add_crlf_to_string(&header);				mem_free(id);			}		}	}	if (uri->post) {		/* We search for first '\n' in uri->post to get content type		 * as set by get_form_uri(). This '\n' is dropped if any		 * and replaced by correct '\r\n' termination here. */		unsigned char *postend = strchr(uri->post, '\n');		if (postend) {			add_to_string(&header, "Content-Type: ");			add_bytes_to_string(&header, uri->post, postend - uri->post);			add_crlf_to_string(&header);		}		post_data = postend ? postend + 1 : uri->post;		add_to_string(&header, "Content-Length: ");		add_long_to_string(&header, strlen(post_data) / 2);		add_crlf_to_string(&header);	}#ifdef CONFIG_COOKIES	{		struct string *cookies = send_cookies(uri);		if (cookies) {			add_to_string(&header, "Cookie: ");			add_string_to_string(&header, cookies);			add_crlf_to_string(&header);			done_string(cookies);		}	}#endif	add_crlf_to_string(&header);	if (post_data) {#define POST_BUFFER_SIZE 4096		unsigned char *post = post_data;		unsigned char buffer[POST_BUFFER_SIZE];		int n = 0;		while (post[0] && post[1]) {			int h1, h2;			h1 = unhx(post[0]);			assert(h1 >= 0 && h1 < 16);			if_assert_failed h1 = 0;			h2 = unhx(post[1]);			assert(h2 >= 0 && h2 < 16);			if_assert_failed h2 = 0;			buffer[n++] = (h1<<4) + h2;			post += 2;			if (n == POST_BUFFER_SIZE) {				add_bytes_to_string(&header, buffer, n);				n = 0;			}

⌨️ 快捷键说明

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