Пример #1
0
void li_connection_reset(liConnection *con) {
	if (LI_CON_STATE_DEAD != con->state) {
		con->state = LI_CON_STATE_DEAD;

		con_iostream_close(con);
		li_stream_reset(&con->in);
		li_stream_reset(&con->out);

		li_vrequest_reset(con->mainvr, TRUE);
		li_stream_release(&con->in);
		li_stream_release(&con->out);

		con->info.keep_alive = TRUE;
		if (con->keep_alive_data.link) {
			g_queue_delete_link(&con->wrk->keep_alive_queue, con->keep_alive_data.link);
			con->keep_alive_data.link = NULL;
		}
		con->keep_alive_data.timeout = 0;
		con->keep_alive_data.max_idle = 0;
		li_event_stop(&con->keep_alive_data.watcher);
		con->keep_alive_requests = 0;
	}

	li_connection_update_io_wait(con);
	li_job_later(&con->wrk->loop.jobqueue, &con->job_reset);
}
Пример #2
0
static void proxy_connection_new(liVRequest *vr, liBackendConnection *bcon, proxy_context *ctx) {
	proxy_connection* scon = g_slice_new0(proxy_connection);
	liIOStream *iostream;
	liStream *outplug;
	liStream *http_out;

	proxy_context_acquire(ctx);
	scon->ctx = ctx;
	scon->bcon = bcon;
	iostream = li_iostream_new(vr->wrk, li_event_io_fd(&bcon->watcher), proxy_io_cb, scon);

	/* insert proxy header before actual data */
	outplug = li_stream_plug_new(&vr->wrk->loop);

	li_stream_connect(outplug, &iostream->stream_out);

	proxy_send_headers(vr, outplug->out);
	li_stream_notify_later(outplug);

	http_out = li_stream_http_response_handle(&iostream->stream_in, vr, TRUE, FALSE);

	li_vrequest_handle_indirect(vr, NULL);
	li_vrequest_indirect_connect(vr, outplug, http_out);

	li_iostream_release(iostream);
	li_stream_release(outplug);
	li_stream_release(http_out);
}
Пример #3
0
static void close_cb(liGnuTLSFilter *f, gpointer data) {
	mod_connection_ctx *conctx = data;
	liConnection *con = conctx->con;
	LI_FORCE_ASSERT(conctx->tls_filter == f);

	conctx->tls_filter = NULL;
	li_gnutls_filter_free(f);
	gnutls_deinit(conctx->session);

	if (NULL != conctx->ctx) {
		mod_gnutls_context_release(conctx->ctx);
		conctx->ctx = NULL;
	}

	if (NULL != conctx->con) {
		liStream *raw_out = con->con_sock.raw_out, *raw_in = con->con_sock.raw_in;
		LI_FORCE_ASSERT(con->con_sock.data == conctx);
		conctx->con = NULL;
		con->con_sock.data = NULL;
		con->con_sock.callbacks = NULL;
		li_stream_acquire(raw_in);
		li_stream_reset(raw_out);
		li_stream_reset(raw_in);
		li_stream_release(raw_in);
	}

#ifdef USE_SNI
	if (NULL != conctx->sni_db_wait) {
		li_fetch_cancel(&conctx->sni_db_wait);
	}
	if (NULL != conctx->sni_entry) {
		li_fetch_entry_release(conctx->sni_entry);
		conctx->sni_entry = NULL;
	}
#endif

	if (NULL != conctx->client_hello_stream) {
		li_ssl_client_hello_stream_ready(conctx->client_hello_stream);
		li_stream_release(conctx->client_hello_stream);
		conctx->client_hello_stream = NULL;
	}

#ifdef USE_SNI
	if (NULL != conctx->sni_jobref) {
		li_job_ref_release(conctx->sni_jobref);
		conctx->sni_jobref = NULL;
	}
	li_job_clear(&conctx->sni_job);

	if (NULL != conctx->sni_server_name) {
		g_string_free(conctx->sni_server_name, TRUE);
		conctx->sni_server_name = NULL;
	}
#endif

	LI_FORCE_ASSERT(NULL != conctx->sock_stream);
	li_iostream_safe_release(&conctx->sock_stream);
}
Пример #4
0
void li_gnutls_filter_free(liGnuTLSFilter *f) {
	LI_FORCE_ASSERT(NULL != f->callbacks);
	f->callbacks = NULL;
	f->callback_data = NULL;

	f_close_gnutls(f);

	li_stream_release(&f->crypt_source);
	li_stream_release(&f->crypt_drain);
	li_stream_release(&f->plain_source);
	li_stream_release(&f->plain_drain);
	f_release(f);
}
Пример #5
0
static void close_cb(liOpenSSLFilter *f, gpointer data) {
	openssl_connection_ctx *conctx = data;
	liConnection *con = conctx->con;
	assert(conctx->ssl_filter == f);

	conctx->ssl_filter = NULL;
	li_openssl_filter_free(f);

	if (NULL != conctx->con) {
		liStream *raw_out = con->con_sock.raw_out, *raw_in = con->con_sock.raw_in;
		assert(con->con_sock.data == conctx);
		conctx->con = NULL;
		con->con_sock.data = NULL;
		li_stream_acquire(raw_in);
		li_stream_reset(raw_out);
		li_stream_reset(raw_in);
		li_stream_release(raw_in);
	}

	if (NULL != conctx->sock_stream) {
		liIOStream *stream = conctx->sock_stream;
		conctx->sock_stream = NULL;
		li_iostream_release(stream);
	}
}
Пример #6
0
static gboolean do_gnutls_handshake(liGnuTLSFilter *f, gboolean writing) {
	int r;

	LI_FORCE_ASSERT(!f->initial_handshaked_finished);

	r = gnutls_handshake(f->session);
	if (GNUTLS_E_SUCCESS == r) {
		f->initial_handshaked_finished = 1;
		li_stream_acquire(&f->plain_source);
		li_stream_acquire(&f->plain_drain);
		f->callbacks->handshake_cb(f, f->callback_data, &f->plain_source, &f->plain_drain);
		li_stream_release(&f->plain_source);
		li_stream_release(&f->plain_drain);
		return TRUE;
	} else {
		do_handle_error(f, "gnutls_handshake", r, writing);
		return FALSE;
	}
}
Пример #7
0
static void openssl_tcp_finished(liConnection *con, gboolean aborted) {
	openssl_connection_ctx *conctx = con->con_sock.data;
	UNUSED(aborted);

	con->info.is_ssl = FALSE;
	con->con_sock.callbacks = NULL;

	if (NULL != conctx) {
		assert(con == conctx->con);
		close_cb(conctx->ssl_filter, conctx);
	}

	{
		liStream *raw_out = con->con_sock.raw_out, *raw_in = con->con_sock.raw_in;
		con->con_sock.raw_out = con->con_sock.raw_in = NULL;
		if (NULL != raw_out) { li_stream_reset(raw_out); li_stream_release(raw_out); }
		if (NULL != raw_in) { li_stream_reset(raw_in); li_stream_release(raw_in); }
	}
}
Пример #8
0
static void gnutls_tcp_finished(liConnection *con, gboolean aborted) {
	mod_connection_ctx *conctx = con->con_sock.data;
	UNUSED(aborted);

	con->info.is_ssl = FALSE;
	con->con_sock.callbacks = NULL;

	if (NULL != conctx) {
		LI_FORCE_ASSERT(con == conctx->con);
		close_cb(conctx->tls_filter, conctx);
		LI_FORCE_ASSERT(NULL == con->con_sock.data);
	}

	{
		liStream *raw_out = con->con_sock.raw_out, *raw_in = con->con_sock.raw_in;
		con->con_sock.raw_out = con->con_sock.raw_in = NULL;
		if (NULL != raw_out) { li_stream_reset(raw_out); li_stream_release(raw_out); }
		if (NULL != raw_in) { li_stream_reset(raw_in); li_stream_release(raw_in); }
	}
}
Пример #9
0
void li_filter_buffer_on_disk_stop(liStream *stream) {
	bod_state *state;

	if (NULL == stream) return;
	assert(bod_cb == stream->cb);

	li_stream_acquire(stream);
	state = LI_CONTAINER_OF(stream, bod_state, stream);
	bod_stop(state);
	li_stream_again_later(stream);
	li_stream_release(stream);
}
Пример #10
0
static void simple_tcp_finished(liConnection *con, gboolean aborted) {
	simple_tcp_connection *data = con->con_sock.data;
	liIOStream *stream;
	if (NULL == data) return;

	data->con = NULL;
	con->con_sock.data = NULL;
	con->con_sock.callbacks = NULL;

	stream = data->sock_stream;
	data->sock_stream = NULL;

	li_stream_simple_socket_close(stream, aborted);
	li_iostream_release(stream);

	{
		liStream *raw_out = con->con_sock.raw_out, *raw_in = con->con_sock.raw_in;
		con->con_sock.raw_out = con->con_sock.raw_in = NULL;
		if (NULL != raw_out) { li_stream_reset(raw_out); li_stream_release(raw_out); }
		if (NULL != raw_in) { li_stream_reset(raw_in); li_stream_release(raw_in); }
	}
}
Пример #11
0
static void check_response_header(liStreamHttpResponse* shr) {
	liResponse *resp = &shr->vr->response;
	GList *l;

	shr->transfer_encoding_chunked = FALSE;

	/* Transfer-Encoding: chunked */
	l = li_http_header_find_first(resp->headers, CONST_STR_LEN("transfer-encoding"));
	if (l) {
		for ( ; l ; l = li_http_header_find_next(l, CONST_STR_LEN("transfer-encoding")) ) {
			liHttpHeader *hh = (liHttpHeader*) l->data;
			if (0 == g_ascii_strcasecmp( LI_HEADER_VALUE(hh), "identity" )) {
				/* ignore */
				continue;
			} if (0 == g_ascii_strcasecmp( LI_HEADER_VALUE(hh), "chunked" )) {
				if (shr->transfer_encoding_chunked) {
					VR_ERROR(shr->vr, "%s", "Response is chunked encoded twice");
					li_vrequest_error(shr->vr);
					return;
				}
				shr->transfer_encoding_chunked = TRUE;
			} else {
				VR_ERROR(shr->vr, "Response has unsupported Transfer-Encoding: %s", LI_HEADER_VALUE(hh));
				li_vrequest_error(shr->vr);
				return;
			}
		}
		li_http_header_remove(resp->headers, CONST_STR_LEN("transfer-encoding"));
		/* any non trivial transfer-encoding overwrites content-length */
		if (shr->transfer_encoding_chunked) {
			li_http_header_remove(resp->headers, CONST_STR_LEN("content-length"));
		}
	}

	/* Upgrade: */
	l = li_http_header_find_first(resp->headers, CONST_STR_LEN("upgrade"));
	if (l) {
		gboolean have_connection_upgrade = FALSE;
		liHttpHeaderTokenizer header_tokenizer;
		GString *token;
		if (101 != resp->http_status) {
			VR_ERROR(shr->vr, "Upgrade but status is %i instead of 101 'Switching Protocols'", resp->http_status);
			li_vrequest_error(shr->vr);
			return;
		}
		if (shr->transfer_encoding_chunked) {
			VR_ERROR(shr->vr, "%s", "Upgrade with Transfer-Encoding: chunked");
			li_vrequest_error(shr->vr);
			return;
		}
		/* requires Connection: Upgrade header */
		token = g_string_sized_new(15);
		li_http_header_tokenizer_start(&header_tokenizer, resp->headers, CONST_STR_LEN("Connection"));
		while (li_http_header_tokenizer_next(&header_tokenizer, token)) {
			VR_ERROR(shr->vr, "Parsing header '%s'", ((liHttpHeader*)header_tokenizer.cur->data)->data->str);
			VR_ERROR(shr->vr, "Connection token '%s'", token->str);
			if (0 == g_ascii_strcasecmp(token->str, "Upgrade")) {
				have_connection_upgrade = TRUE;
				break;
			}
		}
		g_string_free(token, TRUE); token = NULL;
		if (!have_connection_upgrade) {
			VR_ERROR(shr->vr, "%s", "Upgrade without Connection: Upgrade Transfer");
			li_vrequest_error(shr->vr);
			return;
		}
		shr->response_headers_finished = TRUE;
		shr->vr->backend_drain->out->is_closed = FALSE;
		{
			/* li_vrequest_connection_upgrade releases vr->backend_drain; keep our own reference */
			liStream *backend_drain = shr->vr->backend_drain;
			shr->vr->backend_drain = NULL;
			li_vrequest_connection_upgrade(shr->vr, backend_drain, &shr->stream);
			li_stream_release(backend_drain);
		}
		return;
	}

	shr->response_headers_finished = TRUE;
	li_vrequest_indirect_headers_ready(shr->vr);

	return;
}