#include #include static void li_filter_stop(liFilter *filter); void li_vrequest_filters_init(liVRequest *vr) { vr->filters_in_last = vr->filters_out_last = NULL; vr->filters_in_first = vr->filters_out_first = NULL; vr->filters = g_ptr_array_new(); } void li_vrequest_filters_clear(liVRequest *vr) { li_vrequest_filters_reset(vr); g_ptr_array_free(vr->filters, TRUE); vr->filters = NULL; } void li_vrequest_filters_reset(liVRequest *vr) { while (vr->filters->len > 0) { li_filter_stop(g_ptr_array_index(vr->filters, vr->filters->len - 1)); } vr->filters_in_last = vr->filters_out_last = NULL; vr->filters_in_first = vr->filters_out_first = NULL; } static void filter_handle_data(liFilter *filter) { if (NULL != filter->handle_data) { goffset curoutlen = filter->stream.out->length; gboolean curout_closed = filter->stream.out->is_closed; LI_FORCE_ASSERT(NULL != filter->out); switch (filter->handle_data(filter->vr, filter)) { case LI_HANDLER_GO_ON: if (NULL != filter->stream.source && (0 != filter->stream.source->out->length)) { /* auto comeback */ li_stream_again(&filter->stream); } break; case LI_HANDLER_COMEBACK: li_stream_again(&filter->stream); break; case LI_HANDLER_WAIT_FOR_EVENT: break; case LI_HANDLER_ERROR: filter->in = NULL; if (NULL != filter->vr) li_vrequest_error(filter->vr); li_stream_reset(&filter->stream); break; } if (NULL != filter->stream.source && (0 == filter->stream.source->out->length) && filter->stream.source->out->is_closed) { li_stream_disconnect(&filter->stream); } if (curoutlen != filter->stream.out->length || curout_closed != filter->stream.out->is_closed) { li_stream_notify(&filter->stream); } } } static void filter_stream_cb(liStream *stream, liStreamEvent event) { liFilter *filter = LI_CONTAINER_OF(stream, liFilter, stream); switch (event) { case LI_STREAM_NEW_DATA: if (NULL != filter->handle_event) { filter->handle_event(filter->vr, filter, event); } filter_handle_data(filter); break; case LI_STREAM_NEW_CQLIMIT: if (NULL != filter->handle_event) { filter->handle_event(filter->vr, filter, event); } break; case LI_STREAM_CONNECTED_SOURCE: filter->in = (NULL != filter->stream.source) ? filter->stream.source->out : NULL; if (NULL != filter->handle_event) { filter->handle_event(filter->vr, filter, event); } else { li_stream_again(stream); } break; case LI_STREAM_CONNECTED_DEST: if (NULL != filter->handle_event) { filter->handle_event(filter->vr, filter, event); } break; case LI_STREAM_DISCONNECTED_SOURCE: filter->in = NULL; if (NULL != filter->handle_event) { filter->handle_event(filter->vr, filter, event); } else { if (!stream->out->is_closed) li_stream_again(stream); } break; case LI_STREAM_DISCONNECTED_DEST: if (NULL != filter->handle_event) { filter->handle_event(filter->vr, filter, event); } else { stream->out->is_closed = TRUE; li_chunkqueue_skip_all(stream->out); } break; case LI_STREAM_DESTROY: filter->out = NULL; if (NULL != filter->handle_event) { filter->handle_event(filter->vr, filter, event); } if (NULL != filter->handle_free) { filter->handle_free(filter->vr, filter); } g_slice_free(liFilter, filter); break; } } liFilter* li_filter_new(liVRequest* vr, liFilterHandlerCB handle_data, liFilterFreeCB handle_free, liFilterEventCB handle_event, gpointer param) { liFilter *f; f = g_slice_new0(liFilter); li_stream_init(&f->stream, &vr->wrk->loop, filter_stream_cb); f->out = f->stream.out; f->param = param; f->handle_data = handle_data; f->handle_free = handle_free; f->handle_event = handle_event; f->vr = vr; f->filter_ndx = vr->filters->len; g_ptr_array_add(vr->filters, f); return f; } static void li_filter_stop(liFilter *filter) { liVRequest *vr = filter->vr; /* remove from vr filters list */ LI_FORCE_ASSERT(vr->filters->len > 0); LI_FORCE_ASSERT(g_ptr_array_index(vr->filters, filter->filter_ndx) == filter); if (vr->filters->len - 1 != filter->filter_ndx) { /* not the last filter, swap: */ liFilter *last = g_ptr_array_index(vr->filters, vr->filters->len - 1); last->filter_ndx = filter->filter_ndx; g_ptr_array_index(vr->filters, filter->filter_ndx) = last; } g_ptr_array_set_size(vr->filters, vr->filters->len - 1); filter->vr = NULL; li_stream_release(&filter->stream); } liFilter* li_vrequest_add_filter_in(liVRequest *vr, liFilterHandlerCB handle_data, liFilterFreeCB handle_free, liFilterEventCB handle_event, gpointer param) { liFilter *f; /* as soon as we have a backend -> too late for in filters */ if (LI_VRS_READ_CONTENT <= vr->state) return NULL; f = li_filter_new(vr, handle_data, handle_free, handle_event, param); if (NULL == vr->filters_in_first) { LI_FORCE_ASSERT(NULL == vr->filters_in_last); vr->filters_in_first = &f->stream; vr->filters_in_last = &f->stream; } else { LI_FORCE_ASSERT(NULL != vr->filters_in_last); li_stream_connect(vr->filters_in_last, &f->stream); vr->filters_in_last = &f->stream; } return f; } liFilter* li_vrequest_add_filter_out(liVRequest *vr, liFilterHandlerCB handle_data, liFilterFreeCB handle_free, liFilterEventCB handle_event, gpointer param) { liFilter *f; /* as soon as we write the response it is too late for out filters */ if (LI_VRS_WRITE_CONTENT <= vr->state) return NULL; f = li_filter_new(vr, handle_data, handle_free, handle_event, param); if (NULL == vr->filters_out_first) { LI_FORCE_ASSERT(NULL == vr->filters_out_last); vr->filters_out_first = &f->stream; vr->filters_out_last = &f->stream; } else { LI_FORCE_ASSERT(NULL != vr->filters_out_last); li_stream_connect(vr->filters_out_last, &f->stream); vr->filters_out_last = &f->stream; } return f; }