示例#1
0
void li_request_copy(liRequest *dest, const liRequest *src) {
	GList *iter;

	dest->http_method = src->http_method;
	li_string_assign_len(dest->http_method_str, GSTR_LEN(src->http_method_str));
	dest->http_version = src->http_version;

	li_string_assign_len(dest->uri.raw, GSTR_LEN(src->uri.raw));
	li_string_assign_len(dest->uri.raw_path, GSTR_LEN(src->uri.raw_path));
	li_string_assign_len(dest->uri.raw_orig_path, GSTR_LEN(src->uri.raw_orig_path));
	li_string_assign_len(dest->uri.scheme, GSTR_LEN(src->uri.scheme));
	li_string_assign_len(dest->uri.authority, GSTR_LEN(src->uri.authority));
	li_string_assign_len(dest->uri.path, GSTR_LEN(src->uri.path));
	li_string_assign_len(dest->uri.query, GSTR_LEN(src->uri.query));
	li_string_assign_len(dest->uri.host, GSTR_LEN(src->uri.host));

	li_http_headers_reset(dest->headers);

	for (iter = g_queue_peek_head_link(&src->headers->entries); iter; iter = g_list_next(iter)) {
		liHttpHeader* header = (liHttpHeader*) iter->data;

		li_http_header_insert(dest->headers, LI_HEADER_KEY_LEN(header), LI_HEADER_VALUE_LEN(header));
	}

	dest->content_length = src->content_length;
}
示例#2
0
static GString* createFileName(liVRequest *vr, GString *path, liHttpHeader *etagheader) {
	GString *file = g_string_sized_new(255);
	gchar* etag_base64 = g_base64_encode((guchar*) LI_HEADER_VALUE_LEN(etagheader));
	g_string_append_len(file, GSTR_LEN(path));
	g_string_append_len(file, GSTR_LEN(vr->request.uri.path));
	g_string_append_len(file, CONST_STR_LEN("-"));
	g_string_append(file, etag_base64);
	g_free(etag_base64);
	return file;
}
示例#3
0
gboolean li_request_validate_header(liConnection *con) {
	liRequest *req = &con->mainvr->request;
	liHttpHeader *hh;
	GList *l;

	if (con->info.is_ssl) {
		g_string_append_len(req->uri.scheme, CONST_STR_LEN("https"));
	} else {
		g_string_append_len(req->uri.scheme, CONST_STR_LEN("http"));
	}

	switch (req->http_version) {
	case LI_HTTP_VERSION_1_0:
		if (!li_http_header_is(req->headers, CONST_STR_LEN("connection"), CONST_STR_LEN("keep-alive")))
			con->info.keep_alive = FALSE;
		break;
	case LI_HTTP_VERSION_1_1:
		if (li_http_header_is(req->headers, CONST_STR_LEN("connection"), CONST_STR_LEN("close")))
			con->info.keep_alive = FALSE;
		break;
	case LI_HTTP_VERSION_UNSET:
		bad_request(con, 505); /* Version not Supported */
		return FALSE;
	}

	if (req->uri.raw->len == 0) {
		bad_request(con, 400); /* bad request */
		return FALSE;
	}

	/* get hostname */
	l = li_http_header_find_first(req->headers, CONST_STR_LEN("host"));
	if (NULL != l) {
		if (NULL != li_http_header_find_next(l, CONST_STR_LEN("host"))) {
			/* more than one "host" header */
			bad_request(con, 400); /* bad request */
			return FALSE;
		}

		hh = (liHttpHeader*) l->data;
		g_string_append_len(req->uri.authority, LI_HEADER_VALUE_LEN(hh));
		/* check header after we parsed the url, as it may override uri.authority */
	}

	/* Need hostname in HTTP/1.1 */
	if (req->uri.authority->len == 0 && req->http_version == LI_HTTP_VERSION_1_1) {
		bad_request(con, 400); /* bad request */
		return FALSE;
	}

	/* may override hostname */
	if (!request_parse_url(con->mainvr)) {
		bad_request(con, 400); /* bad request */
		return FALSE;
	}

	if (req->uri.host->len == 0 && req->uri.authority->len != 0) {
		if (!li_parse_hostname(&req->uri)) {
			bad_request(con, 400); /* bad request */
			return FALSE;
		}
	}

	/* remove trailing dots from hostname */
	{
		guint i = req->uri.host->len;
		while (i > 0 && req->uri.host->str[i-1] == '.') i--;
		g_string_truncate(req->uri.host, i);
	}

	/* content-length */
	hh = li_http_header_lookup(req->headers, CONST_STR_LEN("content-length"));
	if (hh) {
		const gchar *val = LI_HEADER_VALUE(hh);
		gint64 r;
		char *err;

		r = g_ascii_strtoll(val, &err, 10);
		if (*err != '\0') {
			_VR_DEBUG(con->srv, con->mainvr, "content-length is not a number: %s (Status: 400)", err);
			bad_request(con, 400); /* bad request */
			return FALSE;
		}

		/**
			* negative content-length is not supported
			* and is a bad request
			*/
		if (r < 0) {
			bad_request(con, 400); /* bad request */
			return FALSE;
		}

		/**
			* check if we had a over- or underrun in the string conversion
			*/
		if (r == G_MININT64 || r == G_MAXINT64) {
			if (errno == ERANGE) {
				bad_request(con, 413); /* Request Entity Too Large */
				return FALSE;
			}
		}

		con->mainvr->request.content_length = r;
	}

	/* Expect: 100-continue */
	l = li_http_header_find_first(req->headers, CONST_STR_LEN("expect"));
	if (l) {
		gboolean expect_100_cont = FALSE;

		for ( ; l ; l = li_http_header_find_next(l, CONST_STR_LEN("expect")) ) {
			hh = (liHttpHeader*) l->data;
			if (0 == g_ascii_strcasecmp( LI_HEADER_VALUE(hh), "100-continue" )) {
				expect_100_cont = TRUE;
			} else {
				/* we only support 100-continue */
				bad_request(con, 417); /* Expectation Failed */
				return FALSE;
			}
		}

		if (expect_100_cont && req->http_version == LI_HTTP_VERSION_1_0) {
			/* only HTTP/1.1 clients can send us this header */
			bad_request(con, 417); /* Expectation Failed */
			return FALSE;
		}
		con->expect_100_cont = expect_100_cont;
	}

	/* TODO: headers:
	 * - If-Modified-Since (different duplicate check)
	 * - If-None-Match (different duplicate check)
	 * - Range (duplicate check)
	 */

	switch(con->mainvr->request.http_method) {
	case LI_HTTP_METHOD_GET:
	case LI_HTTP_METHOD_HEAD:
		/* content-length is forbidden for those */
		if (con->mainvr->request.content_length > 0) {
			VR_ERROR(con->mainvr, "%s", "GET/HEAD with content-length -> 400");

			bad_request(con, 400); /* bad request */
			return FALSE;
		}
		con->mainvr->request.content_length = 0;
		break;
	case LI_HTTP_METHOD_POST:
		/* content-length is required for them */
		if (con->mainvr->request.content_length == -1) {
			/* content-length is missing */
			VR_ERROR(con->mainvr, "%s", "POST-request, but content-length missing -> 411");

			bad_request(con, 411); /* Length Required */
			return FALSE;
		}
		break;
	default:
		if (con->mainvr->request.content_length == -1)
			con->mainvr->request.content_length = 0;
		/* the may have a content-length */
		break;
	}

	return TRUE;
}