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