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); } } }
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); }