コード例 #1
0
ファイル: http.c プロジェクト: Vulnerability-scanner/hiawatha
int last_forwarded_ip(t_http_header *http_headers, t_ip_addr *ip_addr) {
	char *forwarded, *search, ip_str[MAX_IP_STR_LEN + 1], *begin, *end;
	size_t len;
	int port;

	if ((forwarded = get_http_header(hs_forwarded, http_headers)) != NULL) {	
		/* Forwarded header
		 */
		begin = NULL;
		while ((forwarded = strcasestr(forwarded, "for=")) == NULL) {
			begin = forwarded;
			forwarded++;
		}

		if (begin == NULL) {
			return -1;
		}

		end = begin;
		while ((*end != '\0') && (*end != ',') && (*end != ';')) {
			end++;
		}

		if (*begin == '"') {
			begin++;
			end--;
			if (*end != '"') {
				return -1;
			}
		}

		len = end - begin;
		if (len > MAX_IP_STR_LEN) {
			return -1;
		}

		memcpy(ip_str, begin, len);
		*(ip_str + len) = '\0';
		forwarded = ip_str;
	} else if ((forwarded = get_http_header(hs_x_forwarded_for, http_headers)) != NULL) {
		/* X-Forwarded-For header
		 */
		if ((search = strrchr(forwarded, ',')) != NULL) {
			forwarded = search + 1;
			while (*forwarded == ' ') {
				forwarded++;
			}
		}
	} else {
		return -1;
	}

	if (parse_ip(forwarded, ip_addr) == -1) {
		if (parse_ip_port(forwarded, ip_addr, &port) == -1) {
			return -1;
		}
	}

	return 0;
}
コード例 #2
0
ファイル: tomahawk.c プロジェクト: chogberg/hiawatha
void show_request_to_admins(char *method, char *uri, char *http_version, t_ip_addr *ip_addr,
                            t_http_header *headers, int response_code, off_t bytes_sent) {
	bool generated = false;
	char message[1024], *format, ip_str[MAX_IP_STR_LEN + 1], *hostname, *user_agent;
	t_admin *admin;

	admin = adminlist;
	while (admin != NULL) {
		if (admin->show_requests) {
			if (generated == false) {
				if ((hostname = get_http_header("Host:", headers)) == NULL) {
					hostname = "-";
				}
				if ((user_agent = get_http_header("User-Agent:", headers)) == NULL) {
					user_agent = "-";
				}
				ip_to_str(ip_addr, ip_str, MAX_IP_STR_LEN);

				format = "  %s %s %s\n"
				         "  Host: %s\n"
				         "  Client IP: %s\n"
						 "  User agent: %s\n"
				         "  Result: %d, %ld bytes sent\n\n";
				if (snprintf(message, 1023, format, method, uri, http_version, hostname, ip_str, user_agent, response_code, (long)bytes_sent) > 1023) {
					sprintf(message, "(error generating request information message)\n");
				}
				generated = true;
			}

			fprintf(admin->fp, "%s", message);
			fflush(admin->fp);
		}
		admin = admin->next;
	}
}
コード例 #3
0
ファイル: cache.c プロジェクト: BuGlessRB/hiawatha
int rproxy_cache_time(t_session *session, char *buffer) {
	int cache_time;
	char *value, *no_cache = "no-cache", extension[EXTENSION_SIZE];

	if ((cache_time = cgi_cache_time(buffer)) > 0) {
		return cache_time;
	}

	if (extension_from_uri(session->request_uri, extension, EXTENSION_SIZE) == false) {
		return 0;
	}

	if (in_charlist(extension, &(session->config->cache_rproxy_extensions)) == false) {
		return 0;
	}

	if ((value = get_http_header("Cache-Control:", session->http_headers)) != NULL) {
		if (strstr(value, no_cache) != NULL) {
			return 0;
		}
	}

	if ((value = get_http_header("Pragma:", session->http_headers)) != NULL) {
		if (strstr(value, no_cache) != NULL) {
			return 0;
		}
	}

	return TIME_IN_CACHE;
}
コード例 #4
0
ファイル: session.c プロジェクト: deniskin82/hiawatha
/* Prevent Cross-site Request Forgery
 */
int prevent_csrf(t_session *session) {
	char *referer, *slash;
	int i, n;

	if (strcmp(session->method, "POST") != 0) {
		return 0;
	}

	if ((referer = get_http_header("Referer:", session->http_headers)) == NULL) {
		return 0;
	}

	if (strncmp(referer, "http://", 7) == 0) {
		referer += 7;
	} else if (strncmp(referer, "https://", 8) == 0) {
		referer += 8;
	} else {
		session->cookie = NULL;

		log_error(session, "invalid referer while checking for CSRF");

		return 1;
	}

	if ((slash = strchr(referer, '/')) != NULL) {
		n = slash - referer;
	} else {
		n = strlen(referer);
	}

	for (i = 0; i < session->host->hostname.size; i++) {
		if (strncasecmp(referer, *(session->host->hostname.item + i), n) == 0) {
			return 0;
		}
	}

	session->cookie = NULL;

	if (session->body != NULL) {
		log_exploit_attempt(session, "CSRF", session->body);
#ifdef ENABLE_TOMAHAWK
		increment_counter(COUNTER_EXPLOIT);
#endif
#ifdef ENABLE_MONITOR
		if (session->config->monitor_enabled) {
			monitor_counter_exploit_attempt(session);
		}
#endif
	} else {
		log_error(session, "CSRF attempt detected with no request body");
	}

#ifdef ENABLE_MONITOR
	if (session->config->monitor_enabled) {
		monitor_counter_exploit_attempt(session);
	}
#endif

	return 1;
}
コード例 #5
0
ファイル: reqs.c プロジェクト: Yinzcn/Cutehttpd
int
reqs_cont_send(struct reqs_t *reqs)
{
    if (!reqs->rp_status_line) {
        set_http_status(reqs, 200); /* "200 OK" */
    }
    if (strlen(get_http_header(reqs, "Content-Type")) == 0) {
        set_http_header(reqs, "Content-Type",   "text/html");
    }
    set_http_header_x(reqs, "Content-Length", "%d", bufx_get_used(reqs->contbufx));
    send_http_header (reqs);
    bufx_get_each    (reqs->contbufx, conn_send, reqs->conn);
    return 1;
}
コード例 #6
0
ファイル: workers.c プロジェクト: BuGlessRB/hiawatha
static t_access allow_client(t_session *session) {
	char *x_forwarded_for;
	t_ip_addr forwarded_ip;
	t_access access;

	if ((access = ip_allowed(&(session->ip_address), session->host->access_list)) != allow) {
		return access;
	} else if ((x_forwarded_for = get_http_header(hs_forwarded, session->http_headers)) == NULL) {
		return allow;
	} else if (parse_ip(x_forwarded_for, &forwarded_ip) == -1) {
		return allow;
	} else if (ip_allowed(&forwarded_ip, session->host->access_list) == deny) {
		return deny;
	}

	return unspecified;
}
コード例 #7
0
ファイル: http.c プロジェクト: chogberg/hiawatha
/* Convert the requestbuffer to a session record.
 */
int parse_request(t_session *session, int total_bytes) {
	int retval = 200;
	char *request_end, *str_end, *conn;

	request_end = session->request + total_bytes;

	/* Request method
	 */
	session->method = str_end = session->request;
	while ((*str_end != ' ') && (str_end != request_end)) {
		str_end++;
	}
	if (str_end == request_end) {
		return 400;
	}
	*str_end = '\0';
	session->uri = ++str_end;

	/* URI
	 */
	while ((*str_end != ' ') && (str_end != request_end)) {
		str_end++;
	}
	if (str_end == request_end) {
		return 400;
	}
	*(str_end++) = '\0';
	session->uri_len = strlen(session->uri);
	if ((session->config->max_url_length > 0) && (session->uri_len > session->config->max_url_length)) {
		return 414;
	}

	if (strncmp(session->uri, "http://", 7) == 0) {
		return 400;
	} else if ((session->request_uri = strdup(session->uri)) == NULL) {
		return -1;
	}

	/* Protocol version
	 */
	if (min_strlen(str_end, 10) == false) {
		return 400;
	} else if (memcmp(str_end, "HTTP/", 5) != 0) {
		return 400;
	}

	session->http_version = str_end;
	str_end += 7;

	if ((*(str_end - 1) != '.') || (*(str_end + 1) != '\r') || (*(str_end + 2) != '\n')) {
		return 400;
	} else if (*(str_end - 2) != '1') {
		return 505;
	}
	*(str_end + 1) = '\0';

	/* Body and other request headerlines
	 */
	if (session->content_length > 0) {
		session->body = session->request + session->header_length;
	}
	session->http_headers = parse_http_headers(str_end + 3);
	session->hostname = strlower(get_http_header("Host:", session->http_headers));
	session->cookie = get_http_header("Cookie:", session->http_headers);

	if ((conn = get_http_header("Connection:", session->http_headers)) != NULL) {
		conn = strlower(remove_spaces(conn));
	}
	session->keep_alive = false;

	switch (*str_end) {
		case '0':
			if ((conn != NULL) && (session->kept_alive < session->binding->max_keepalive)) {
				if (strcasecmp(conn, "keep-alive") == 0) {
					session->keep_alive = true;
				}
			}
			break;
		case '1':
			if (session->hostname == NULL) {
				retval = 400;
			} else if (session->kept_alive < session->binding->max_keepalive) {
				session->keep_alive = true;
				if (conn != NULL) {
					if (strcmp(conn, "close") == 0) {
						session->keep_alive = false;
					}
				}
			}
			break;
		default:
			retval = 505;
			break;
	}
	if (session->keep_alive) {
		session->kept_alive++;
	}

	session->parsing_oke = true;

	return retval;
}
コード例 #8
0
ファイル: session.c プロジェクト: Ygrex/hiawatha
/* Prevent Cross-site Request Forgery
 */
int prevent_csrf(t_session *session) {
	char *referer, *slash, prev = '\0';
	int i, n;
#ifdef ENABLE_MONITOR
	char *csrf_url;
#endif

	if (session->request_method != POST) {
		return 0;
	}

	if ((referer = get_http_header("Origin:", session->http_headers)) == NULL) {
		if ((referer = get_http_header("Referer:", session->http_headers)) == NULL) {
			return 0;
		}
	}

#ifdef ENABLE_MONITOR
	csrf_url = referer;
#endif

	if (strncmp(referer, "http://", 7) == 0) {
		referer += 7;
	} else if (strncmp(referer, "https://", 8) == 0) {
		referer += 8;
	} else {
		session->request_method = GET;
		session->body = NULL;
		session->cookies = NULL;

		log_error(session, "invalid referer while checking for CSRF");

		return 1;
	}

	if ((slash = strchr(referer, '/')) != NULL) {
		n = slash - referer;
	} else {
		n = strlen(referer);
	}

	for (i = 0; i < session->host->hostname.size; i++) {
		if (strncasecmp(referer, *(session->host->hostname.item + i), n) == 0) {
			return 0;
		}
	}

	if (session->body != NULL) {
		prev = *(session->body + session->content_length);
		*(session->body + session->content_length) = '\0';
	}

	log_exploit_attempt(session, "CSRF", session->body);

	if (session->body != NULL) {
		*(session->body + session->content_length) = prev;
	}

	if (session->host->prevent_csrf == p_prevent) {
		session->request_method = GET;
		session->body = NULL;
		session->cookies = NULL;
	}

#ifdef ENABLE_TOMAHAWK
	increment_counter(COUNTER_EXPLOIT);
#endif
#ifdef ENABLE_MONITOR
	if (session->config->monitor_enabled) {
		monitor_count_exploit_attempt(session);
		monitor_event("CSRF attempt for %s%s via %s", session->host->hostname.item[0], session->uri, csrf_url);
	}
#endif

	return 1;
}
コード例 #9
0
ファイル: workers.c プロジェクト: JackieXie168/hiawatha
/* Serve the client that connected to the webserver
 */
static int serve_client(t_session *session) {
	int result, length, auth_result;
	char *qmark, chr, *header;
	t_host *host_record;
	t_access access;
	t_deny_body *deny_body;
	t_req_method request_method;
	t_ip_addr ip_addr;
#ifdef ENABLE_XSLT
	char *xslt_file;
#endif
#ifdef ENABLE_TOOLKIT
	int i;
	t_toolkit_options toolkit_options;
#endif
#ifdef ENABLE_RPROXY
	t_rproxy *rproxy;
#endif

#ifdef ENABLE_DEBUG
	session->current_task = "fetch & parse request";
#endif

	if ((result = fetch_request(session)) != 200) {
		session->request_method = GET;
		return result;
	} else if ((result = parse_request(session, session->header_length + session->content_length)) != 200) {
		session->request_method = GET;
		return result;
	}

#ifdef ENABLE_DEBUG
	session->current_task = "serve client";
#endif

	session->time = time(NULL);

	/* Hide reverse proxies
	 */
	if (in_iplist(session->config->hide_proxy, &(session->ip_address))) {
		if (last_forwarded_ip(session->http_headers, &ip_addr) == 0) {
			if (reposition_client(session, &ip_addr) != -1) {
				copy_ip(&(session->ip_address), &ip_addr);
			}
		}
	}

	/* SSH tunneling
	 */
#ifdef ENABLE_RPROXY
	if (session->request_method == CONNECT) {
		if (in_iplist(session->config->tunnel_ssh, &(session->ip_address)) == false) {
			return 405;
		}

#ifdef ENABLE_SSL
		if (session->binding->use_ssl) {
			return 405;
		}
#endif

		if (strcmp(session->request_uri, "localhost:22") != 0) {
			if (strcmp(session->request_uri, "127.0.0.1:22") != 0) {
				if (strcmp(session->request_uri, "::1.22") != 0) {
					return 403;
				}
			}
		}

		log_system(session, "SSH tunnel requested");
		if (tunnel_ssh_connection(session->client_socket) != 0) {
			log_system(session, "SSH tunnel failed");
		} else {
			log_system(session, "SSH tunnel terminated");
		}

		session->keep_alive = false;

		return 200;
	}
#endif

	/* Find host record
	 */
	if (session->hostname != NULL) {
		if (remove_port_from_hostname(session) == -1) {
			log_error(session, "error removing port from hostname");
			return 500;
		}

		if ((host_record = get_hostrecord(session->config->first_host, session->hostname, session->binding)) != NULL) {
			session->host = host_record;
#ifdef ENABLE_TOMAHAWK
			session->last_host = host_record;
#endif
		}
	}
	session->host->access_time = session->time;

#ifdef ENABLE_SSL
	/* SSL client authentication
	 */
	if (session->binding->use_ssl) {
		if ((session->host->ca_certificate != NULL) && (ssl_has_peer_cert(&(session->ssl_context)) == false)) {
			log_error(session, "Missing client SSL certificate");
			return 440;
		}
	}
#endif

	/* Enforce usage of first hostname
	 */
	if (session->host->enforce_first_hostname && (session->hostname != NULL)) {
		if (**(session->host->hostname.item) != '*') {
			if (strcmp(session->hostname, *(session->host->hostname.item)) != 0) {
				session->cause_of_301 = enforce_first_hostname;
				return 301;
			}
		}
	}

	/* Enforce usage of SSL
	 */
#ifdef ENABLE_SSL
	if (session->host->require_ssl && (session->binding->use_ssl == false)) {
		if ((qmark = strchr(session->uri, '?')) != NULL) {
			*qmark = '\0';
			session->vars = qmark + 1;
			session->uri_len = strlen(session->uri);
		}
		session->cause_of_301 = require_ssl;
		return 301;
	}
#endif

	/* Deny matching bodies
	 */
	if (session->body != NULL) {
		chr = *(session->body + session->content_length);
		*(session->body + session->content_length) = '\0';

		deny_body = session->host->deny_body;
		while (deny_body != NULL) {
			if (strpcmp(session->body, &(deny_body->pattern)) == 0) {
				if ((session->config->ban_on_denied_body > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) {
					ban_ip(&(session->ip_address), session->config->ban_on_denied_body, session->config->kick_on_ban);
					log_system(session, "Client banned because of denied body");
#ifdef ENABLE_MONITOR
					if (session->config->monitor_enabled) {
						monitor_count_ban(session);
					}
#endif
				}

				log_exploit_attempt(session, "denied body", session->body);
#ifdef ENABLE_TOMAHAWK
				increment_counter(COUNTER_EXPLOIT);
#endif
#ifdef ENABLE_MONITOR
				if (session->config->monitor_enabled) {
					monitor_count_exploit(session);
					monitor_event("Request body denied for %s", session->host->hostname.item[0]);
				}
#endif

				*(session->body + session->content_length) = chr;

				return 403;
			}
			deny_body = deny_body->next;
		}

		*(session->body + session->content_length) = chr;
	}

	/* Websocket
	 */
	if (session->request_method == GET) {
		if ((header = get_http_header("Connection:", session->http_headers)) != NULL) {
			if (strcasestr(header, "upgrade") != NULL) {
				if ((header = get_http_header("Upgrade:", session->http_headers)) != NULL) {
					if (strcasecmp(header, "websocket") == 0) {
						switch (access = allow_client(session)) {
							case deny:
								log_error(session, fb_accesslist);
								return 403;
							case allow:
								break;
							case pwd:
							case unspecified:
								if ((auth_result = http_authentication_result(session, access == unspecified)) != 200) {
									return auth_result;
								}
						}

						session->keep_alive = false;
						if (forward_to_websocket(session) == -1) {
							return 500;
						}

						return 200;
					}
				}
			}
		}
	}

#ifdef ENABLE_RPROXY
	/* Reverse proxy
	 */
	rproxy = session->host->rproxy;
	while (rproxy != NULL) {
		if (rproxy_match(rproxy, session->request_uri)) {
			if (rproxy_loop_detected(session->http_headers)) {
				return 508;
			}

			if ((qmark = strchr(session->uri, '?')) != NULL) {
				*qmark = '\0';
				session->vars = qmark + 1;
			}

			if (validate_url(session) == false) {
				return -1;
			}

			if ((session->vars != NULL) && (session->host->secure_url)) {
				if (forbidden_chars_present(session->vars)) {
					log_error(session, "URL contains forbidden characters");
					return 403;
				}
			}

			if (duplicate_host(session) == false) {
				log_error(session, "duplicate_host() error");
				return 500;
			}

			if ((result = uri_to_path(session)) != 200) {
				return result;
			}

			if (session->host->ignore_dot_hiawatha == false) {
				if (load_user_config(session) == -1) {
					return 500;
				}
			}

			if ((result = copy_directory_settings(session)) != 200) {
				return result;
			}

			switch (access = allow_client(session)) {
				case deny:
					log_error(session, fb_accesslist);
					return 403;
				case allow:
					break;
				case pwd:
				case unspecified:
					if ((auth_result = http_authentication_result(session, access == unspecified)) != 200) {
						return auth_result;
					}
			}

			/* Prevent SQL injection
			 */
			if (session->host->prevent_sqli) {
				result = prevent_sqli(session);
				if (result == 1) {
					session->error_cause = ec_SQL_INJECTION;
				}
				if (result != 0) {
					return -1;
				}
			}

			/* Prevent Cross-site Scripting
			 */
			if (session->host->prevent_xss != p_no) {
				if (prevent_xss(session) > 0) {
					if (session->host->prevent_xss == p_block) {
						session->error_cause = ec_XSS;
						return -1;
					}
				}
			}

			/* Prevent Cross-site Request Forgery
			 */
			if (session->host->prevent_csrf != p_no) {
				if (prevent_csrf(session) > 0) {
					if (session->host->prevent_csrf == p_block) {
						session->error_cause = ec_CSRF;
						return -1;
					}
				}
			}

			return proxy_request(session, rproxy);
		}

		rproxy = rproxy->next;
	}
#endif

	/* Actions based on request method
	 */
	switch (session->request_method) {
		case TRACE:
			if (session->binding->enable_trace == false) {
				return 501;
			}
			return handle_trace_request(session);
		case PUT:
		case DELETE:
			if ((session->binding->enable_alter == false) && (session->host->webdav_app == false)) {
				return 501;
			}
			break;
		case unknown:
			return 400;
		case unsupported:
			if (session->host->webdav_app == false) {
				return 501;
			}
			break;
		default:
			break;
	}

	if (duplicate_host(session) == false) {
		log_error(session, "duplicate_host() error");
		return 500;
	}

#ifdef ENABLE_TOOLKIT
	if (session->host->ignore_dot_hiawatha == false) {
		if (load_user_root_config(session) == -1) {
			return 500;
		}
	}

	/* URL toolkit
	 */
	init_toolkit_options(&toolkit_options);
	toolkit_options.method = session->method;
	toolkit_options.website_root = session->host->website_root;
	toolkit_options.url_toolkit = session->config->url_toolkit;
	toolkit_options.allow_dot_files = session->host->allow_dot_files;
	toolkit_options.http_headers = session->http_headers;
#ifdef ENABLE_SSL
	toolkit_options.use_ssl = session->binding->use_ssl;
#endif

	if (((session->request_method != PUT) && (session->request_method != DELETE)) || session->host->webdav_app) {
		for (i = 0; i < session->host->toolkit_rules.size; i++) {
			if ((result = use_toolkit(session->uri, session->host->toolkit_rules.item[i], &toolkit_options)) == UT_ERROR) {
				return 500;
			}

			if ((toolkit_options.ban > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) {
				ban_ip(&(session->ip_address), toolkit_options.ban, session->config->kick_on_ban);
				log_system(session, "Client banned because of URL match in UrlToolkit rule");
#ifdef ENABLE_MONITOR
				if (session->config->monitor_enabled) {
					monitor_count_ban(session);
				}
#endif
				return 403;
			}

			session->toolkit_fastcgi = toolkit_options.fastcgi_server;
			if (toolkit_options.new_url != NULL) {
				if (register_tempdata(&(session->tempdata), toolkit_options.new_url, tc_data) == -1) {
					free(toolkit_options.new_url);
					log_error(session, "error registering temporary data");
					return 500;
				}
				session->uri = toolkit_options.new_url;
			}

			if (result == UT_REDIRECT) {
				if ((session->location = strdup(toolkit_options.new_url)) == NULL) {
					return -1;
				}
				session->cause_of_301 = location;
				return 301;
			}

			if (result == UT_DENY_ACCESS) {
				log_error(session, "access denied via URL toolkit rule");
				return 403;
			}

			if (toolkit_options.expire > -1) {
				session->expires = toolkit_options.expire;
				session->caco_private = toolkit_options.caco_private;
			}
		}
	}
#endif

	/* Find GET data
	 */
	if ((qmark = strchr(session->uri, '?')) != NULL) {
		*qmark = '\0';
		session->vars = qmark + 1;
	}

	url_decode(session->uri);
	session->uri_len = strlen(session->uri);

	if ((session->vars != NULL) && (session->host->secure_url)) {
		if (forbidden_chars_present(session->vars)) {
			log_error(session, "URL contains forbidden characters");
			return 403;
		}
	}

	if (validate_url(session) == false) {
		return -1;
	}

	if ((result = uri_to_path(session)) != 200) {
		return result;
	}

	/* Load configfile from directories
	 */
	if (session->host->ignore_dot_hiawatha == false) {
		if (load_user_config(session) == -1) {
			return 500;
		}
	}

	if ((result = copy_directory_settings(session)) != 200) {
		return result;
	}

	switch (access = allow_client(session)) {
		case deny:
			log_error(session, fb_accesslist);
			return 403;
		case allow:
			break;
		case pwd:
		case unspecified:
			if ((auth_result = http_authentication_result(session, access == unspecified)) != 200) {
				return auth_result;
			}
	}

	switch (is_directory(session->file_on_disk)) {
		case error:
			return 500;
		case yes:
			session->uri_is_dir = true;
			break;
		case no:
			if (((session->request_method != PUT) || session->host->webdav_app) && (session->host->enable_path_info)) {
				if ((result = get_path_info(session)) != 200) {
					return result;
				}
			}
			break;
		case no_access:
			log_error(session, fb_filesystem);
			return 403;
		case not_found:
			if (session->request_method == DELETE) {
				return 404;
			}
	}

#ifdef ENABLE_TOOLKIT
	if ((session->toolkit_fastcgi == NULL) && session->uri_is_dir) {
#else
	if (session->uri_is_dir) {
#endif
		length = strlen(session->file_on_disk);
		if (*(session->file_on_disk + length - 1) == '/') {
			strcpy(session->file_on_disk + length, session->host->start_file);
		} else {
			return 301;
		}
	}

	if (get_target_extension(session) == -1) {
		log_error(session, "error getting extension");
		return 500;
	}

	if (((session->request_method != PUT) && (session->request_method != DELETE)) || session->host->webdav_app) {
		check_target_is_cgi(session);
	}

	/* Handle request based on request method
	 */
	request_method = session->request_method;
	if (session->host->webdav_app) {
		if ((request_method == PUT) || (request_method == DELETE)) {
			request_method = POST;
		}
	}

	switch (request_method) {
		case GET:
		case HEAD:
			if (session->cgi_type != no_cgi) {
				session->body = NULL;
				result = execute_cgi(session);
#ifdef ENABLE_XSLT
			} else if ((xslt_file = find_xslt_file(session)) != NULL) {
				result = handle_xml_file(session, xslt_file);
				free(xslt_file);
#endif
			} else {
				result = send_file(session);
			}
			if (result == 404) {
#ifdef ENABLE_XSLT
				if ((session->host->show_index != NULL) && (session->uri[session->uri_len - 1] == '/')) {
					result = show_index(session);
				}
#endif
#ifdef ENABLE_MONITOR
			} else if (session->config->monitor_enabled) {
				if ((result == 200) && (session->host->monitor_host)) {
					unlink(session->file_on_disk);
				}
#endif
			}

			if ((session->request_method == GET) && (session->cgi_type == no_cgi) && (session->directory != NULL)) {
				if (session->directory->run_on_download != NULL) {
					run_program(session, session->directory->run_on_download, result);
				}
			}
			break;
		case POST:
		case unsupported:
			if (session->cgi_type != no_cgi) {
				result = execute_cgi(session);
#ifdef ENABLE_XSLT
			} else if ((xslt_file = find_xslt_file(session)) != NULL) {
				result = handle_xml_file(session, xslt_file);
				free(xslt_file);
#endif
			} else {
				result = 405;
			}
			break;
		case PUT:
			result = handle_put_request(session);
			if (((result == 201) || (result == 204)) && (session->host->run_on_alter != NULL)) {
				run_program(session, session->host->run_on_alter, result);
			}
			break;
		case DELETE:
			result = handle_delete_request(session);
			if ((result == 204) && (session->host->run_on_alter != NULL)) {
				run_program(session, session->host->run_on_alter, result);
			}
			break;
		case WHEN:
			send_code(session);
			break;
		default:
			result = 400;
	}

	return result;
}

/* Handle timeout upon sending request
 */
static void handle_timeout(t_session *session) {
	if ((session->config->ban_on_timeout > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) {
		ban_ip(&(session->ip_address), session->config->ban_on_timeout, session->config->kick_on_ban);
		log_system(session, "Client banned because of connection timeout");
#ifdef ENABLE_MONITOR
		if (session->config->monitor_enabled) {
			monitor_count_ban(session);
		}
#endif
	} else {
		log_system(session, "Timeout while waiting for first request");
	}
}

/* Request has been handled, handle the return code.
 */
static void handle_request_result(t_session *session, int result) {
	char *hostname;

#ifdef ENABLE_DEBUG
	session->current_task = "handle request result";
#endif

	if (result == -1) switch (session->error_cause) {
		case ec_MAX_REQUESTSIZE:
			log_system(session, "Maximum request size reached");
			session->return_code = 413;
			send_code(session);
			if ((session->config->ban_on_max_request_size > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) {
				ban_ip(&(session->ip_address), session->config->ban_on_max_request_size, session->config->kick_on_ban);
				log_system(session, "Client banned because of sending a too large request");
#ifdef ENABLE_MONITOR
				if (session->config->monitor_enabled) {
					monitor_count_ban(session);
				}
#endif
			}
			break;
		case ec_TIMEOUT:
			if (session->kept_alive == 0) {
				session->return_code = 408;
				send_code(session);
				handle_timeout(session);
			}
			break;
		case ec_CLIENT_DISCONNECTED:
			if (session->kept_alive == 0) {
				log_system(session, "Silent client disconnected");
			}
			break;
		case ec_SOCKET_READ_ERROR:
			if (errno != ECONNRESET) {
				log_system(session, "Error while reading request");
			}
			break;
		case ec_SOCKET_WRITE_ERROR:
			log_request(session);
			break;
		case ec_FORCE_QUIT:
			log_system(session, "Client kicked");
			break;
		case ec_SQL_INJECTION:
			if ((session->config->ban_on_sqli > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) {
				ban_ip(&(session->ip_address), session->config->ban_on_sqli, session->config->kick_on_ban);
				hostname = (session->hostname != NULL) ? session->hostname : unknown_host;
				log_system(session, "Client banned because of SQL injection on %s", hostname);
#ifdef ENABLE_MONITOR
				if (session->config->monitor_enabled) {
					monitor_count_ban(session);
				}
#endif
			}
			session->return_code = 441;
			send_code(session);
			log_request(session);
			break;
		case ec_XSS:
			session->return_code = 442;
			send_code(session);
			log_request(session);
			break;
		case ec_CSRF:
			session->return_code = 443;
			send_code(session);
			log_request(session);
			break;
		case ec_INVALID_URL:
			if ((session->config->ban_on_invalid_url > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) {
				ban_ip(&(session->ip_address), session->config->ban_on_invalid_url, session->config->kick_on_ban);
				hostname = (session->hostname != NULL) ? session->hostname : unknown_host;
				log_system(session, "Client banned because of invalid URL on %s", hostname);
#ifdef ENABLE_MONITOR
				if (session->config->monitor_enabled) {
					monitor_count_ban(session);
				}
#endif
			}
			send_code(session);
			break;
		default:
			if (session->data_sent == false) {
				session->return_code = 500;
				if (send_code(session) == -1) {
					session->keep_alive = false;
				}
			}
	} else switch (result) {
		case 200:
			break;
		case 201:
		case 204:
		case 304:
		case 412:
			if (session->data_sent == false) {
				session->return_code = result;
				if (send_header(session) == -1) {
					session->keep_alive = false;
				} else if (send_buffer(session, "Content-Length: 0\r\n\r\n", 21) == -1) {
					session->keep_alive = false;
				}
			}
			break;
		case 411:
		case 413:
			session->keep_alive = false;
			if (session->data_sent == false) {
				session->return_code = result;
				if (send_header(session) == -1) {
					session->keep_alive = false;
				} else if (send_buffer(session, "Content-Length: 0\r\n\r\n", 21) == -1) {
					session->keep_alive = false;
				}
			}
			break;
		case 400:
			log_garbage(session);
			if (session->data_sent == false) {
				session->return_code = 400;
				if (send_code(session) == -1) {
					session->keep_alive = false;
				}
			}
			if ((session->config->ban_on_garbage > 0) && (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny)) {
				ban_ip(&(session->ip_address), session->config->ban_on_garbage, session->config->kick_on_ban);
				log_system(session, "Client banned because of sending garbage");
#ifdef ENABLE_MONITOR
				if (session->config->monitor_enabled) {
					monitor_count_ban(session);
				}
#endif
			}
#ifdef ENABLE_MONITOR
			if (session->config->monitor_enabled) {
				monitor_count_bad_request(session);
			}
#endif
			break;
		case 401:
		case 403:
		case 404:
		case 501:
		case 503:
			if (session->data_sent == false) {
				switch (handle_error(session, result)) {
					case -1:
						session->keep_alive = false;
						break;
					case 200:
						break;
					default:
						if (session->data_sent == false) {
							session->return_code = result;
							if (send_code(session) == -1) {
								session->keep_alive = false;
							}
						}
				}
			}
			break;
		case 500:
			session->keep_alive = false;
		default:
			if (session->data_sent == false) {
				session->return_code = result;
				send_code(session);
			}
	}

	if ((result > 0) && (result != 400)) {
		log_request(session);
	} else {
		session->keep_alive = false;
	}
}
コード例 #10
0
ファイル: toolkit.c プロジェクト: NavinPanchu/hiawatha
int use_toolkit(char *url, char *toolkit_id, t_toolkit_options *options) {
	t_url_toolkit *toolkit;
	t_toolkit_rule *rule;
	bool condition_met, url_replaced = false;
	int result, skip = 0;
	char *file, *qmark, *header;
	regmatch_t pmatch[REGEXEC_NMATCH];
	struct stat fileinfo;
	t_http_header *headers;

	if (options == NULL) {
		return UT_ERROR;
	}

	options->new_url = NULL;

	if ((toolkit = select_toolkit(toolkit_id, options->url_toolkit)) == NULL) {
		return UT_ERROR;
	}

	rule = toolkit->toolkit_rule;
	while (rule != NULL) {
		condition_met = false;

		/* Skip lines
		 */
		if (skip > 0) {
			skip--;
			rule = rule->next;
			continue;
		}

		/* Condition
		 */
		switch (rule->condition) {
			case tc_none:
				/* None
				 */
				condition_met = true;
				break;
			case tc_match:
				/* Match
				 */
				if (regexec(&(rule->pattern), url, REGEXEC_NMATCH, pmatch, 0) == 0) {
					condition_met = true;
				}
				if (rule->neg_match) {
					condition_met = (condition_met == false);
				}
				break;
			case tc_header:
				/* Header
				 */
				if (rule->header == NULL) {
					headers = options->http_headers;
					while (headers != NULL) {
						if (regexec(&(rule->pattern), headers->data + headers->value_offset, REGEXEC_NMATCH, pmatch, 0) == 0) {
							condition_met = true;
						}
						if (rule->neg_match) {
							condition_met = (condition_met == false);
						}

						if (condition_met) {
							break;
						}

						headers = headers->next;
					}
				} else {
					if ((header = get_http_header(rule->header, options->http_headers)) == NULL) {
						break;
					}
					if (regexec(&(rule->pattern), header, REGEXEC_NMATCH, pmatch, 0) == 0) {
						condition_met = true;
					}
					if (rule->neg_match) {
						condition_met = (condition_met == false);
					}
				}
				break;
			case tc_method:
				/* Request method
				 */
				if (strcmp(options->method, rule->parameter) == 0) {
					condition_met = true;
				}
				if (rule->neg_match) {
					condition_met = (condition_met == false);
				}
				break;
			case tc_request_uri:
				/* Request URI
				 */
				if (valid_uri(url, false) == false) {
					break;
				}
				if ((file = make_path(options->website_root, url)) == NULL) {
					return UT_ERROR;
				}

				if ((qmark = strchr(file, '?')) != NULL) {
					*qmark = '\0';
				}
				url_decode(file);

				if (stat(file, &fileinfo) != -1) {
					switch (rule->value) {
						case IU_EXISTS:
							if (S_ISDIR(fileinfo.st_mode) || S_ISREG(fileinfo.st_mode)) {
								condition_met = true;
							}
							break;
						case IU_ISFILE:
							if (S_ISREG(fileinfo.st_mode)) {
								condition_met = true;
							}
							break;
						case IU_ISDIR:
							if (S_ISDIR(fileinfo.st_mode)) {
								condition_met = true;
							}
							break;
					}
				}

				free(file);
				break;
			case tc_total_connections:
				/* Total connections reached?
				 */
				condition_met = options->total_connections >= rule->value;
				break;
#ifdef ENABLE_TLS
			case tc_use_tls:
				/* Client connections uses TLS?
				 */
				condition_met = options->use_tls;
				break;
#endif
		}

		/* Condition not met
		 */
		if (condition_met == false) {
			rule = rule->next;
			continue;
		}

		/* Operation
		 */
		switch (rule->operation) {
			case to_none:
				/* None
				 */
				break;
			case to_ban:
				/* Ban client
				 */
				options->ban = rule->value;
				break;
			case to_deny_access:
				/* Deny access
				 */
				return UT_DENY_ACCESS;
			case to_omit_request_log:
				/* Omit requeest log
				 */
				options->log_request = false;
				break;
			case to_expire:
				/* Send Expire HTTP header
				 */
				options->expire = rule->value;
				options->caco_private = rule->caco_private;
				break;
			case to_fastcgi:
				/* Use FastCGI server
				 */
				options->fastcgi_server = rule->parameter;
				break;
			case to_redirect:
				/* Redirect client
				 */
				if (rule->neg_match) {
					if ((options->new_url = strdup(rule->parameter)) == NULL) {
						return UT_ERROR;
					}
				} else if (do_rewrite(url, &(rule->pattern), pmatch, rule->parameter, &(options->new_url), rule->match_loop) == -1) {
					if (options->new_url != NULL) {
						free(options->new_url);
						options->new_url = NULL;
					}
					return UT_ERROR;
				}
				if (options->new_url != NULL) {
					if (url_replaced) {
						free(url);
					}
					return UT_REDIRECT;
				} else if (url_replaced) {
					options->new_url = url;
				}
				break;
			case to_rewrite:
				/* Rewrite
				 */
				if (rule->neg_match) {
					if ((options->new_url = strdup(rule->parameter)) == NULL) {
						return UT_ERROR;
					}
				} else if (do_rewrite(url, &(rule->pattern), pmatch, rule->parameter, &(options->new_url), rule->match_loop) == -1) {
					if (options->new_url != NULL) {
						free(options->new_url);
						options->new_url = NULL;
					}
					return UT_ERROR;
				}
				if (options->new_url != NULL) {
					if (url_replaced) {
						free(url);
					}
					url = options->new_url;
					url_replaced = true;
				} else if (url_replaced) {
					options->new_url = url;
				}
				break;
			case to_skip:
				/* Skip
				 */
				skip = rule->value;
				break;
			case to_sub:
				/* Subroutine
				 */
				if (++(options->sub_depth) > MAX_SUB_DEPTH) {
					return UT_ERROR;
				}

				if ((result = use_toolkit(url, rule->parameter, options)) == UT_ERROR) {
					if (options->new_url != NULL) {
						free(options->new_url);
						options->new_url = NULL;
					}
					return UT_ERROR;
				}
				options->sub_depth--;

				if (options->new_url != NULL) {
					if (url_replaced) {
						free(url);
					}
					url = options->new_url;
					url_replaced = true;
				} else if (url_replaced) {
					options->new_url = url;
				}

				if (result != UT_RETURN) {
					return result;
				}
				break;
			case to_use:
				/* Replace URL
				 */
				if (url_replaced) {
					free(url);
				}
				if ((options->new_url = strdup(rule->parameter)) == NULL) {
					return UT_ERROR;
				}
				break;
		}

		/* Flow
		 */
		switch (rule->flow) {
			case tf_continue:
				/* Continue
				 */
				break;
			case tf_exit:
				/* Exit
				 */
				return UT_EXIT;
			case tf_return:
				/* Return
				 */
				return UT_RETURN;
		}

		rule = rule->next;
	}

	return UT_RETURN;
}
コード例 #11
0
ファイル: reqs.c プロジェクト: Yinzcn/Cutehttpd
int
reqs_parse(struct reqs_t *reqs)
{
    register char *a, *z, *p;
    char *reqs_head = reqs->conn->reqs_head;
    char *reqs_line;

    /*
    [ take reqs_line
    */
    a = reqs_head;
    while (*a == CR || *a == LF || *a == SP || *a == HT) {
        a++;
    }
    z = a;
    while (*z != CR && *z != LF && *z) {
        z++;
    }
    if (z == a) {
        return 0;
    }
    reqs_line = x_strndup(a, z - a);
    reqs->reqs_line = reqs_line;
    /*
    ]
    */

    /*
    [ method_name
    */
    reqs->method = HTTP_METHOD_UNKNOWN;

    a = reqs_line;
    z = a;
    while (*z != SP && *z) {
        z++;
    }

    switch (z - a) {
    case 0:
    case 1:
    case 2:
        break;

    case 3:
        if (str3equ(a, 'G', 'E', 'T')) {
            reqs->method = HTTP_METHOD_GET;
        } else
        if (str3equ(a, 'P', 'U', 'T')) {
            reqs->method = HTTP_METHOD_PUT;
        }
        break;

    case 4:
        if (str4equ(a, 'P', 'O', 'S', 'T')) {
            reqs->method = HTTP_METHOD_POST;
        } else
        if (str4equ(a, 'H', 'E', 'A', 'D')) {
            reqs->method = HTTP_METHOD_HEAD;
        }
        break;

    case 5:
        if (str5equ(a, 'T', 'R', 'A', 'C', 'E')) {
            reqs->method = HTTP_METHOD_TRACE;
        }
        break;

    case 6:
        if (str6equ(a, 'D', 'E', 'L', 'E', 'T', 'E')) {
            reqs->method = HTTP_METHOD_DELETE;
        }
        break;

    case 7:
        if (str7equ(a, 'O', 'P', 'T', 'I', 'O', 'N', 'S')) {
            reqs->method = HTTP_METHOD_OPTIONS;
        } else
        if (str7equ(a, 'C', 'O', 'N', 'N', 'E', 'C', 'T')) {
            reqs->method = HTTP_METHOD_CONNECT;
        }
        break;

    default:
        break;
    }
    reqs->method_name = http_method_names[reqs->method];
    if (reqs->method == HTTP_METHOD_UNKNOWN) {
        reqs_throw_status(reqs, 501, ""); /* "501 Method Not Implemented" */
        chtd_cry(reqs->htdx, "Method Not Implemented: [%s]", a);
        return 0;
    }
    /*
    ]
    */

    /*
    [ URI
    */
    #define is_valid_uri_char(c) ((c > 0x20) && (c != 0x7f) && (c != 0xff))
    a = z;
    while (*a == SP) {
        a++;
    }
    z = a;
    while (*z != SP && *z) {
        z++;
    }
    if (a == z) {
        return 0;
    }
    reqs->uri = x_strndup(a, z - a);
    p = reqs->uri;
    for ( ; *p; p++) {
        if (!is_valid_uri_char(*p)) {
            return 0;
        }
    }
    /*
    ]
    */

    /*
    [ http version
    */
    reqs->http_version = HTTP_VERSION_0_9;
    a = z;
    for ( ; *a == SP; a++);
    z = strchr(a, 0);
    if (z - a == 8) {
        if (str8equ(a, 'H', 'T', 'T', 'P', '/', '1', '.', '0')) {
            reqs->http_version = HTTP_VERSION_1_0;
        } else
        if (str8equ(a, 'H', 'T', 'T', 'P', '/', '1', '.', '1')) {
            reqs->http_version = HTTP_VERSION_1_1;
        }
    }
    reqs->http_version_name = http_version_names[reqs->http_version];
    /*
    ]
    */

    /*
    [ parse request_path
    */
    a = reqs->uri;
    z = a;
    while (*z != '?' && *z) {
        z++;
    }
    reqs->request_path = x_strndup(a, z - a);
    path_tidy(reqs->request_path);
    /*
    ]
    */

    /*
    [ parse query_string
    */
    a = strchr(reqs->uri, '?');
    if (a) {
        reqs->query_string = strdup(a + 1);
    } else {
        reqs->query_string = calloc(1 , 1);
    }
    /*
    ]
    */

    /*
    [ http headers
    */
    parse_header(&reqs->re_headers, strchr(reqs_head, LF) + 1);
    /*
    ]
    */

    reqs->content_length = atoi(get_http_header(reqs, "Content-Length"));

    reqs_parse_post(reqs);

    return 1;
}
コード例 #12
0
ファイル: reqs.c プロジェクト: Yinzcn/Cutehttpd
int
reqs_parse_post(struct reqs_t *reqs)
{
    char *content_type;
    char *charset = NULL;
    char *p;
    if (!reqs_read_post(reqs)) {
        return 0;
    }
    if (!reqs->post_size) {
        return 0;
    }
    content_type = strdup(get_http_header(reqs, "Content-Type"));
    p = content_type;
    while (1) {
        p = strchr(p, ';');
        if (!p) {
            break;
        }
        *p++ = '\0';
        while (*p == ' ') {
            p++;
        }
        if (strncmp(p, "charset=", 8) == 0) {
            charset = p + 8;
        }
    }
    charset = charset;
    if (strcasecmp(content_type, "application/x-www-form-urlencoded") != 0) {
        char *n_a, *n_z;
        char *v_a, *v_z;
        int n_l = 0, v_l = 0;
        struct namevalue_t *nv;
        char *p = reqs->post_data;
        while (*p) {
            n_a = p;
            while (*p && *p != '=' && *p != '&') {
                p++;
            }
            if (!*p) {
                break;
            }
            n_z = p;
            if (*p != '&') {
                p++;
            }
            v_a = p;
            while (*p && *p != '&') {
                p++;
            }
            v_z = p;
            n_l = n_z - n_a;
            v_l = v_z - v_a;
            if (n_l > 0) {
                nv = namevalues_add(&reqs->post_vars, n_a, n_l, v_a, v_l);
                if (nv) {
                    n_a = nv->n;
                    for ( ; *n_a; n_a++) {
                        if (strchr(" \t\r\n", *n_a)) {
                            *n_a = '_';
                        }
                    }
                }
            }
            p++;
        }
    }
    free(content_type);
    return 1;
}
コード例 #13
0
ファイル: log.c プロジェクト: wdlth/hiawatha
/* Log a HTTP request.
 */
void log_request(t_session *session) {
	char str[BUFFER_SIZE + 1], timestamp[TIMESTAMP_SIZE], ip_address[IP_ADDRESS_SIZE];
	char *user, *field, *uri, *vars, *path_info;
	t_http_header *http_header;
	int offset;
	time_t t;
	struct tm s;

	if (ip_allowed(&(session->ip_address), session->config->logfile_mask) == deny) {
		return;
	}

	str[BUFFER_SIZE] = '\0';

#ifdef ENABLE_TOOLKIT
	if (session->request_uri == NULL) {
#endif
		uri = secure_string(session->uri);
		path_info = secure_string(session->path_info);
		vars = secure_string(session->vars);
#ifdef ENABLE_TOOLKIT
	} else {
		uri = secure_string(session->request_uri);
		path_info = NULL;
		vars = NULL;
	}
#endif

	if ((user = session->remote_user) != NULL) {
		user = secure_string(user);
	}

	if (session->config->log_format == hiawatha) {
		/* Hiawatha log format
		 */
		if (session->config->anonymize_ip) {
			anonymized_ip_to_str(str, &(session->ip_address), IP_ADDRESS_SIZE);
		} else {
			ip_to_str(str, &(session->ip_address), IP_ADDRESS_SIZE);
		}

		strcat(str, "|");
		offset = strlen(str);
		print_timestamp(str + offset);
		offset += strlen(str + offset);

		if (user == NULL) {
			user = "";
		}

		snprintf(str + offset, BUFFER_SIZE - offset, "%d|%lld|%s|%s %s", session->return_code, (long long)session->bytes_sent, user, secure_string(session->method), uri);
		offset += strlen(str + offset);

		if ((offset < BUFFER_SIZE) && (path_info != NULL)) {
			snprintf(str + offset, BUFFER_SIZE - offset, "/%s", path_info);
			offset += strlen(str + offset);
		}
		if ((offset < BUFFER_SIZE) && (vars != NULL)) {
			snprintf(str + offset, BUFFER_SIZE - offset, "?%s", vars);
			offset += strlen(str + offset);
		}

		if (offset < BUFFER_SIZE) {
			snprintf(str + offset, BUFFER_SIZE - offset, " %s", secure_string(session->http_version));
			offset += strlen(str + offset);
		}

		if (offset < BUFFER_SIZE) {
			http_header = session->http_headers;
			while (http_header != NULL) {
				if ((strncasecmp("Cookie:", http_header->data, 7) != 0) && (strncasecmp("Authorization:", http_header->data, 14) != 0)) {
					snprintf(str + offset, BUFFER_SIZE - offset, "|%s", secure_string(http_header->data));
					if ((offset += strlen(str + offset)) >= BUFFER_SIZE) {
						break;
					}
				}
				http_header = http_header->next;
			}
		}
	} else {
		/* Common Log Format
		 */
		if (session->config->anonymize_ip) {
			anonymized_ip_to_str(ip_address, &(session->ip_address), IP_ADDRESS_SIZE);
		} else {
			ip_to_str(ip_address, &(session->ip_address), IP_ADDRESS_SIZE);
		}

		if (user == NULL) {
			user = "******";
		}

		time(&t);
		localtime_r(&t, &s);
		timestamp[TIMESTAMP_SIZE - 1] = '\0';
		strftime(timestamp, TIMESTAMP_SIZE - 1, "%d/%b/%Y:%T %z", &s);

		snprintf(str, BUFFER_SIZE, "%s - %s [%s] \"%s %s", ip_address, user, timestamp, secure_string(session->method), uri);
		offset = strlen(str);
		if ((offset < BUFFER_SIZE) && (path_info != NULL)) {
			snprintf(str + offset, BUFFER_SIZE - offset, "/%s", path_info);
			offset += strlen(str + offset);
		}
		if ((offset < BUFFER_SIZE) && (vars != NULL)) {
			snprintf(str + offset, BUFFER_SIZE - offset, "?%s", vars);
			offset += strlen(str + offset);
		}
		if (offset < BUFFER_SIZE) {
			snprintf(str + offset, BUFFER_SIZE - offset, " %s\" %d %lld", secure_string(session->http_version), session->return_code, (long long)session->bytes_sent);
		}

		if (session->config->log_format == extended) {
			/* Extended Common Log Format
			 */
			offset += strlen(str + offset);
			if (offset < BUFFER_SIZE) {
				if ((field = get_http_header("Referer:", session->http_headers)) != NULL) {
					snprintf(str + offset, BUFFER_SIZE - offset, " \"%s\"", secure_string(field));
				} else {
					snprintf(str + offset, BUFFER_SIZE - offset, " \"-\"");
				}
				offset += strlen(str + offset);
			}
			if (offset < BUFFER_SIZE) {
				if ((field = get_http_header("User-Agent:", session->http_headers)) != NULL) {
					snprintf(str + offset, BUFFER_SIZE - offset, " \"%s\"", secure_string(field));
				} else {
					snprintf(str + offset, BUFFER_SIZE - offset, " \"-\"");
				}
			}
		}
	}

	pthread_mutex_lock(&accesslog_mutex);
	if (*(session->host->access_fp) == NULL) {
		*(session->host->access_fp) = fopen(session->host->access_logfile, "a");
	}
	if (*(session->host->access_fp) != NULL) {
		fprintf(*(session->host->access_fp), "%s"EOL, str);
		fflush(*(session->host->access_fp));
	}
	pthread_mutex_unlock(&accesslog_mutex);
}