Beispiel #1
0
static void proxy_send_headers(liVRequest *vr, proxy_connection *pcon) {
	GString *head = g_string_sized_new(4095);
	liHttpHeader *header;
	GList *iter;
	gchar *enc_path;

	g_string_append_len(head, GSTR_LEN(vr->request.http_method_str));
	g_string_append_len(head, CONST_STR_LEN(" "));

	enc_path = g_uri_escape_string(vr->request.uri.path->str, "/", FALSE);
	g_string_append(head, enc_path);
	g_free(enc_path);

	if (vr->request.uri.query->len > 0) {
		g_string_append_len(head, CONST_STR_LEN("?"));
		g_string_append_len(head, GSTR_LEN(vr->request.uri.query));
	}

	switch (vr->request.http_version) {
	case LI_HTTP_VERSION_1_1:
		/* g_string_append_len(head, CONST_STR_LEN(" HTTP/1.1\r\n")); */
		g_string_append_len(head, CONST_STR_LEN(" HTTP/1.0\r\n"));
		break;
	case LI_HTTP_VERSION_1_0:
	default:
		g_string_append_len(head, CONST_STR_LEN(" HTTP/1.0\r\n"));
		break;
	}

	for (iter = g_queue_peek_head_link(&vr->request.headers->entries); iter; iter = g_list_next(iter)) {
		header = (liHttpHeader*) iter->data;
		if (li_http_header_key_is(header, CONST_STR_LEN("Connection"))) continue;
		if (li_http_header_key_is(header, CONST_STR_LEN("Proxy-Connection"))) continue;
		if (li_http_header_key_is(header, CONST_STR_LEN("X-Forwarded-Proto"))) continue;
		g_string_append_len(head, GSTR_LEN(header->data));
		g_string_append_len(head, CONST_STR_LEN("\r\n"));
	}

	g_string_append_len(head, CONST_STR_LEN("X-Forwarded-For: "));
	g_string_append_len(head, GSTR_LEN(vr->coninfo->remote_addr_str));
	g_string_append_len(head, CONST_STR_LEN("\r\n"));

	if (vr->coninfo->is_ssl) {
		g_string_append_len(head, CONST_STR_LEN("X-Forwarded-Proto: https\r\n"));
	} else {
		g_string_append_len(head, CONST_STR_LEN("X-Forwarded-Proto: http\r\n"));
	}

	/* terminate http header */
	g_string_append_len(head, CONST_STR_LEN("\r\n"));

	li_chunkqueue_append_string(pcon->proxy_out, head);
}
Beispiel #2
0
static void proxy_send_headers(liVRequest *vr, liChunkQueue *out) {
	GString *head = g_string_sized_new(4095);
	liHttpHeader *header;
	GList *iter;
	liHttpHeaderTokenizer header_tokenizer;
	GString *tmp_str = vr->wrk->tmp_str;

	g_string_append_len(head, GSTR_LEN(vr->request.http_method_str));
	g_string_append_len(head, CONST_STR_LEN(" "));

	g_string_append_len(head, GSTR_LEN(vr->request.uri.raw_path));

	switch (vr->request.http_version) {
	case LI_HTTP_VERSION_1_1:
		/* g_string_append_len(head, CONST_STR_LEN(" HTTP/1.1\r\n")); */
		g_string_append_len(head, CONST_STR_LEN(" HTTP/1.0\r\n"));
		break;
	case LI_HTTP_VERSION_1_0:
	default:
		g_string_append_len(head, CONST_STR_LEN(" HTTP/1.0\r\n"));
		break;
	}

	li_http_header_tokenizer_start(&header_tokenizer, vr->request.headers, CONST_STR_LEN("Connection"));
	while (li_http_header_tokenizer_next(&header_tokenizer, tmp_str)) {
		if (0 == g_ascii_strcasecmp(tmp_str->str, "Upgrade")) {
			g_string_append_len(head, CONST_STR_LEN("Connection: Upgrade\r\n"));
		}
	}

	if (LI_HTTP_METHOD_GET != vr->request.http_method && LI_HTTP_METHOD_HEAD != vr->request.http_method) {
		g_string_append_printf(head, "Content-Length: %" LI_GOFFSET_MODIFIER "i\r\n", vr->request.content_length);
	}

	for (iter = g_queue_peek_head_link(&vr->request.headers->entries); iter; iter = g_list_next(iter)) {
		header = (liHttpHeader*) iter->data;
		if (li_http_header_key_is(header, CONST_STR_LEN("Content-Length"))) continue;
		if (li_http_header_key_is(header, CONST_STR_LEN("Transfer-Encoding"))) continue;
		if (li_http_header_key_is(header, CONST_STR_LEN("TE"))) continue;
		if (li_http_header_key_is(header, CONST_STR_LEN("Connection"))) continue;
		if (li_http_header_key_is(header, CONST_STR_LEN("Proxy-Connection"))) continue;
		if (li_http_header_key_is(header, CONST_STR_LEN("X-Forwarded-Proto"))) continue;
		if (li_http_header_key_is(header, CONST_STR_LEN("X-Forwarded-For"))) continue;
		g_string_append_len(head, GSTR_LEN(header->data));
		g_string_append_len(head, CONST_STR_LEN("\r\n"));
	}

	g_string_append_len(head, CONST_STR_LEN("X-Forwarded-For: "));
	g_string_append_len(head, GSTR_LEN(vr->coninfo->remote_addr_str));
	g_string_append_len(head, CONST_STR_LEN("\r\n"));

	if (vr->coninfo->is_ssl) {
		g_string_append_len(head, CONST_STR_LEN("X-Forwarded-Proto: https\r\n"));
	} else {
		g_string_append_len(head, CONST_STR_LEN("X-Forwarded-Proto: http\r\n"));
	}

	/* terminate http header */
	g_string_append_len(head, CONST_STR_LEN("\r\n"));

	li_chunkqueue_append_string(out, head);
}
Beispiel #3
0
gboolean li_response_send_headers(liConnection *con) {
	GString *head;
	liVRequest *vr = con->mainvr;

	if (vr->response.http_status < 100 || vr->response.http_status > 999) {
		VR_ERROR(vr, "wrong status: %i", vr->response.http_status);
		return FALSE;
	}

	head = g_string_sized_new(8*1024-1);

	if (0 == con->out->length && con->mainvr->backend == NULL
		&& vr->response.http_status >= 400 && vr->response.http_status < 600) {
		li_response_send_error_page(con);
	}

	if ((vr->response.http_status >= 100 && vr->response.http_status < 200) ||
	     vr->response.http_status == 204 ||
	     vr->response.http_status == 205 ||
	     vr->response.http_status == 304) {
		/* They never have a content-body/length */
		li_chunkqueue_reset(con->out);
		con->out->is_closed = TRUE;
		con->raw_out->is_closed = TRUE;
	} else if (con->out->is_closed) {
		if (vr->request.http_method != LI_HTTP_METHOD_HEAD || con->out->length > 0) {
			/* do not send content-length: 0 if backend already skipped content generation for HEAD */
			g_string_printf(con->wrk->tmp_str, "%"L_GOFFSET_FORMAT, con->out->length);
			li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Content-Length"), GSTR_LEN(con->wrk->tmp_str));
		}
	} else if (con->info.keep_alive && vr->request.http_version == LI_HTTP_VERSION_1_1) {
		/* TODO: maybe someone set a content length header? */
		if (!(vr->response.transfer_encoding & LI_HTTP_TRANSFER_ENCODING_CHUNKED)) {
			vr->response.transfer_encoding |= LI_HTTP_TRANSFER_ENCODING_CHUNKED;
			li_http_header_append(vr->response.headers, CONST_STR_LEN("Transfer-Encoding"), CONST_STR_LEN("chunked"));
		}
	} else {
		/* Unknown content length, no chunked encoding */
		con->info.keep_alive = FALSE;
	}

	if (vr->request.http_method == LI_HTTP_METHOD_HEAD) {
		/* content-length is set, but no body */
		li_chunkqueue_reset(con->out);
		con->out->is_closed = TRUE;
		con->raw_out->is_closed = TRUE;
	}

	/* Status line */
	if (vr->request.http_version == LI_HTTP_VERSION_1_1) {
		g_string_append_len(head, CONST_STR_LEN("HTTP/1.1 "));
		if (!con->info.keep_alive)
			li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Connection"), CONST_STR_LEN("close"));
	} else {
		g_string_append_len(head, CONST_STR_LEN("HTTP/1.0 "));
		if (con->info.keep_alive)
			li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Connection"), CONST_STR_LEN("keep-alive"));
	}

	{
		guint len;
		gchar status_str[4];
		gchar *str = li_http_status_string(vr->response.http_status, &len);
		li_http_status_to_str(vr->response.http_status, status_str);
		status_str[3] = ' ';
		g_string_append_len(head, status_str, 4);
		g_string_append_len(head, str, len);
		g_string_append_len(head, CONST_STR_LEN("\r\n"));
	}

	/* Append headers */
	{
		liHttpHeader *header;
		GList *iter;
		gboolean have_date = FALSE, have_server = FALSE;

		for (iter = g_queue_peek_head_link(&vr->response.headers->entries); iter; iter = g_list_next(iter)) {
			header = (liHttpHeader*) iter->data;
			g_string_append_len(head, GSTR_LEN(header->data));
			g_string_append_len(head, CONST_STR_LEN("\r\n"));
			if (!have_date && li_http_header_key_is(header, CONST_STR_LEN("date"))) have_date = TRUE;
			if (!have_server && li_http_header_key_is(header, CONST_STR_LEN("server"))) have_server = TRUE;
		}

		if (!have_date) {
			GString *d = li_worker_current_timestamp(con->wrk, LI_GMTIME, LI_TS_FORMAT_HEADER);
			/* HTTP/1.1 requires a Date: header */
			g_string_append_len(head, CONST_STR_LEN("Date: "));
			g_string_append_len(head, GSTR_LEN(d));
			g_string_append_len(head, CONST_STR_LEN("\r\n"));
		}

		if (!have_server) {
			GString *tag = CORE_OPTIONPTR(LI_CORE_OPTION_SERVER_TAG).string;

			if (tag->len) {
				g_string_append_len(head, CONST_STR_LEN("Server: "));
				g_string_append_len(head, GSTR_LEN(tag));
				g_string_append_len(head, CONST_STR_LEN("\r\n"));
			}
		}
	}

	g_string_append_len(head, CONST_STR_LEN("\r\n"));
	li_chunkqueue_append_string(con->raw_out, head);

	return TRUE;
}