Exemple #1
0
static void mainvr_connection_upgrade(liVRequest *vr, liStream *backend_drain, liStream *backend_source) {
	liConnection* con = li_connection_from_vrequest(vr);
	LI_FORCE_ASSERT(NULL != con);

	if (con->response_headers_sent || NULL != con->out.source) {
		li_connection_error(con);
		return;
	}
	if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
		VR_DEBUG(vr, "%s", "connection upgrade: write response headers");
	}
	con->response_headers_sent = TRUE;
	con->info.keep_alive = FALSE;
	li_response_send_headers(vr, con->out.out, NULL, TRUE);
	con->state = LI_CON_STATE_UPGRADED;
	vr->response.transfer_encoding = 0;
	li_connection_update_io_wait(con);

	li_stream_disconnect_dest(&con->in);
	con->in.out->is_closed = FALSE;

	li_stream_connect(&con->in, backend_drain);
	li_stream_connect(backend_source, &con->out);

	li_vrequest_reset(con->mainvr, TRUE);

	if (NULL != con->in.source) {
		li_chunkqueue_steal_all(con->out.out, backend_drain->out);
	}
	con->info.out_queue_length = con->out.out->length;

	li_stream_notify(&con->out);
	li_stream_notify(&con->in);
}
static void stream_http_response_cb(liStream *stream, liStreamEvent event) {
	liStreamHttpResponse* shr = LI_CONTAINER_OF(stream, liStreamHttpResponse, stream);

	switch (event) {
	case LI_STREAM_NEW_DATA:
		stream_http_response_data(shr);
		break;
	case LI_STREAM_DISCONNECTED_DEST:
		shr->vr = NULL;
		li_stream_disconnect(stream);
		break;
	case LI_STREAM_DISCONNECTED_SOURCE:
		shr->vr = NULL;
		if (!stream->out->is_closed) {
			/* "abort" */
			li_stream_disconnect_dest(stream);
		}
		break;
	case LI_STREAM_DESTROY:
		li_http_response_parser_clear(&shr->parse_response_ctx);
		g_slice_free(liStreamHttpResponse, shr);
		break;
	default:
		break;
	}
}
static void bod_cb(liStream *stream, liStreamEvent event) {
	bod_state *state = LI_CONTAINER_OF(stream, bod_state, stream);

	switch (event) {
	case LI_STREAM_NEW_DATA:
		bod_handle_data(state);
		break;
	case LI_STREAM_NEW_CQLIMIT:
		break;
	case LI_STREAM_CONNECTED_DEST:
		break;
	case LI_STREAM_CONNECTED_SOURCE:
		break;
	case LI_STREAM_DISCONNECTED_DEST:
		if (!state->stream.out->is_closed || 0 != state->stream.out->length) {
			li_stream_disconnect(stream);
			bod_close(state);
		}
		break;
	case LI_STREAM_DISCONNECTED_SOURCE:
		if (!state->stream.out->is_closed) {
			li_stream_disconnect_dest(stream);
			bod_close(state);
		}
		break;
	case LI_STREAM_DESTROY:
		bod_close(state);
		g_slice_free(bod_state, state);
		break;
	}
}
static void f_abort_gnutls(liGnuTLSFilter *f) {
	if (f->aborted) return;
	f->aborted = TRUE;
	f_acquire(f);
	f_close_gnutls(f);
	li_stream_disconnect(&f->crypt_source); /* plain in -> crypt out */
	li_stream_disconnect(&f->crypt_drain); /* io -> crypt in */
	li_stream_disconnect_dest(&f->crypt_source); /* crypt out -> io */
	f_release(f);
}
static void f_close_gnutls(liGnuTLSFilter *f) {
	if (NULL != f->session && !f->closing) {
		liCQLimit *limit;
		f->closing = TRUE;
		f->session = NULL;

		LI_FORCE_ASSERT(NULL != f->crypt_source.out);
		LI_FORCE_ASSERT(NULL != f->crypt_source.out->limit);
		limit = f->crypt_source.out->limit;
		limit->notify = NULL;
		limit->context = NULL;

		li_stream_disconnect(&f->plain_source); /* crypt in -> plain out */

		li_stream_disconnect(&f->plain_drain); /* app -> plain in */
		li_stream_disconnect_dest(&f->plain_source); /* plain out -> app */

		f->log_context = NULL;
		if (NULL != f->callbacks && NULL != f->callbacks->closed_cb) {
			f->callbacks->closed_cb(f, f->callback_data);
		}
	}
}
Exemple #6
0
static void li_connection_reset_keep_alive(liConnection *con) {
	liVRequest *vr = con->mainvr;

	if (NULL == con->con_sock.raw_in || NULL == con->con_sock.raw_out || con->in.source != con->con_sock.raw_in) {
		li_connection_reset(con);
		return;
	}

	/* only start keep alive watcher if there isn't more input data already */
	if (con->con_sock.raw_in->out->length == 0) {
		li_event_stop(&con->keep_alive_data.watcher);
		{
			con->keep_alive_data.max_idle = CORE_OPTION(LI_CORE_OPTION_MAX_KEEP_ALIVE_IDLE).number;
			if (con->keep_alive_data.max_idle == 0) {
				con->state = LI_CON_STATE_CLOSE;
				con_iostream_shutdown(con);
				li_connection_reset(con);
				return;
			}

			con->keep_alive_data.timeout = li_cur_ts(con->wrk) + con->keep_alive_data.max_idle;

			if (con->keep_alive_data.max_idle == con->srv->keep_alive_queue_timeout) {
				/* queue is sorted by con->keep_alive_data.timeout */
				gboolean need_start = (0 == con->wrk->keep_alive_queue.length);
				con->keep_alive_data.timeout = li_cur_ts(con->wrk) + con->srv->keep_alive_queue_timeout;
				g_queue_push_tail(&con->wrk->keep_alive_queue, con);
				con->keep_alive_data.link = g_queue_peek_tail_link(&con->wrk->keep_alive_queue);
				if (need_start)
					li_worker_check_keepalive(con->wrk);
			} else {
				li_event_timer_once(&con->keep_alive_data.watcher, con->keep_alive_data.max_idle);
			}
		}
	} else {
		li_stream_again_later(&con->in);
	}

	con->state = LI_CON_STATE_KEEP_ALIVE;
	con->response_headers_sent = FALSE;
	con->expect_100_cont = FALSE;
	con->out_has_all_data = FALSE;

	con->info.keep_alive = TRUE;

	li_connection_update_io_wait(con);

	li_vrequest_reset(con->mainvr, TRUE);
	li_http_request_parser_reset(&con->req_parser_ctx);

	li_stream_disconnect(&con->out);
	li_stream_disconnect_dest(&con->in);
	con->out.out->is_closed = FALSE;

	memset(&con->in_chunked_decode_state, 0, sizeof(con->in_chunked_decode_state));

	/* restore chunkqueue limits */
	li_chunkqueue_use_limit(con->con_sock.raw_in->out, LI_CONNECTION_DEFAULT_CHUNKQUEUE_LIMIT);
	li_chunkqueue_use_limit(con->con_sock.raw_out->out, LI_CONNECTION_DEFAULT_CHUNKQUEUE_LIMIT);

	/* reset stats */
	con->info.stats.bytes_in = G_GUINT64_CONSTANT(0);
	con->info.stats.bytes_in_5s = G_GUINT64_CONSTANT(0);
	con->info.stats.bytes_in_5s_diff = G_GUINT64_CONSTANT(0);
	con->info.stats.bytes_out = G_GUINT64_CONSTANT(0);
	con->info.stats.bytes_out_5s = G_GUINT64_CONSTANT(0);
	con->info.stats.bytes_out_5s_diff = G_GUINT64_CONSTANT(0);
	con->info.stats.last_avg = 0;
}
static void do_gnutls_read(liGnuTLSFilter *f) {
	const ssize_t blocksize = 16*1024; /* 16k */
	off_t max_read = 4 * blocksize; /* 64k */
	ssize_t r;
	off_t len = 0;
	liChunkQueue *cq = f->plain_source.out;

	f_acquire(f);

	if (NULL != f->session && !f->initial_handshaked_finished && !do_gnutls_handshake(f, FALSE)) goto out;
	if (NULL == f->session) {
		f_abort_gnutls(f);
		goto out;
	}

	do {
		liBuffer *buf;
		gboolean cq_buf_append;

		buf = li_chunkqueue_get_last_buffer(cq, 1024);
		cq_buf_append = (buf != NULL);

		if (buf != NULL) {
			/* use last buffer as raw_in_buffer; they should be the same anyway */
			if (G_UNLIKELY(buf != f->raw_in_buffer)) {
				li_buffer_acquire(buf);
				li_buffer_release(f->raw_in_buffer);
				f->raw_in_buffer = buf;
			}
		} else {
			buf = f->raw_in_buffer;
			if (buf != NULL && buf->alloc_size - buf->used < 1024) {
				/* release *buffer */
				li_buffer_release(buf);
				f->raw_in_buffer = buf = NULL;
			}
			if (buf == NULL) {
				f->raw_in_buffer = buf = li_buffer_new(blocksize);
			}
		}
		LI_FORCE_ASSERT(f->raw_in_buffer == buf);

		r = gnutls_record_recv(f->session, buf->addr + buf->used, buf->alloc_size - buf->used);
		if (r < 0) {
			do_handle_error(f, "gnutls_record_recv", r, FALSE);
			goto out;
		} else if (r == 0) {
			/* clean shutdown? */
			f->plain_source.out->is_closed = TRUE;
			f->plain_drain.out->is_closed = TRUE;
			f->crypt_source.out->is_closed = TRUE;
			f->crypt_drain.out->is_closed = TRUE;
			li_stream_disconnect(&f->crypt_drain); /* io -> crypt in */
			li_stream_disconnect_dest(&f->crypt_source); /* crypt out -> io */
			li_stream_disconnect(&f->crypt_source); /* plain in -> crypt out */
			f_close_gnutls(f);
			goto out;
		}

		if (cq_buf_append) {
			li_chunkqueue_update_last_buffer_size(cq, r);
		} else {
			gsize offset;

			li_buffer_acquire(buf);

			offset = buf->used;
			buf->used += r;
			li_chunkqueue_append_buffer2(cq, buf, offset, r);
		}
		if (buf->alloc_size - buf->used < 1024) {
			/* release *buffer */
			li_buffer_release(buf);
			f->raw_in_buffer = buf = NULL;
		}
		len += r;
	} while (len < max_read);

out:
	f_release(f);
}