static void stream_http_response_data(liStreamHttpResponse* shr) { if (NULL == shr->stream.source) return; if (!shr->response_headers_finished) { switch (li_http_response_parse(shr->vr, &shr->parse_response_ctx)) { case LI_HANDLER_GO_ON: check_response_header(shr); if (NULL == shr->stream.source) return; break; case LI_HANDLER_ERROR: VR_ERROR(shr->vr, "%s", "Parsing response header failed"); li_vrequest_error(shr->vr); return; case LI_HANDLER_WAIT_FOR_EVENT: if (shr->stream.source->out->is_closed) { VR_ERROR(shr->vr, "%s", "Parsing response header failed (eos)"); li_vrequest_error(shr->vr); } return; default: return; } } if (shr->transfer_encoding_chunked) { if (!li_filter_chunked_decode(shr->vr, shr->stream.out, shr->stream.source->out, &shr->chunked_decode_state)) { if (NULL != shr->vr) { VR_ERROR(shr->vr, "%s", "Decoding chunks failed"); li_vrequest_error(shr->vr); } else { li_stream_reset(&shr->stream); } } if (shr->stream.source->out->is_closed) { li_stream_disconnect(&shr->stream); } } else { li_chunkqueue_steal_all(shr->stream.out, shr->stream.source->out); if (shr->stream.source->out->is_closed) { shr->stream.out->is_closed = TRUE; li_stream_disconnect(&shr->stream); } } li_stream_notify(&shr->stream); }
static void proxy_fd_cb(struct ev_loop *loop, ev_io *w, int revents) { proxy_connection *pcon = (proxy_connection*) w->data; if (pcon->state == SS_CONNECTING) { if (LI_HANDLER_GO_ON != proxy_statemachine(pcon->vr, pcon)) { li_vrequest_error(pcon->vr); } return; } if (revents & EV_READ) { if (pcon->proxy_in->is_closed) { li_ev_io_rem_events(loop, w, EV_READ); } else { switch (li_network_read(pcon->vr, w->fd, pcon->proxy_in, &pcon->proxy_in_buffer)) { case LI_NETWORK_STATUS_SUCCESS: break; case LI_NETWORK_STATUS_FATAL_ERROR: VR_ERROR(pcon->vr, "(%s) network read fatal error", pcon->ctx->socket_str->str); li_vrequest_error(pcon->vr); return; case LI_NETWORK_STATUS_CONNECTION_CLOSE: pcon->proxy_in->is_closed = TRUE; ev_io_stop(loop, w); close(pcon->fd); pcon->fd = -1; li_vrequest_backend_finished(pcon->vr); break; case LI_NETWORK_STATUS_WAIT_FOR_EVENT: break; } } } if (pcon->fd != -1 && (revents & EV_WRITE)) { if (pcon->proxy_out->length > 0) { switch (li_network_write(pcon->vr, w->fd, pcon->proxy_out, 256*1024)) { case LI_NETWORK_STATUS_SUCCESS: break; case LI_NETWORK_STATUS_FATAL_ERROR: VR_ERROR(pcon->vr, "(%s) network write fatal error", pcon->ctx->socket_str->str); li_vrequest_error(pcon->vr); return; case LI_NETWORK_STATUS_CONNECTION_CLOSE: pcon->proxy_in->is_closed = TRUE; ev_io_stop(loop, w); close(pcon->fd); pcon->fd = -1; li_vrequest_backend_finished(pcon->vr); break; case LI_NETWORK_STATUS_WAIT_FOR_EVENT: break; } } if (pcon->proxy_out->length == 0) { li_ev_io_rem_events(loop, w, EV_WRITE); } } if (!pcon->response_headers_finished && LI_HANDLER_GO_ON == li_http_response_parse(pcon->vr, &pcon->parse_response_ctx)) { /* "ignore" 1xx response headers */ if (!(pcon->vr->response.http_status >= 100 && pcon->vr->response.http_status < 200)) { pcon->response_headers_finished = TRUE; li_vrequest_handle_response_headers(pcon->vr); } } if (pcon->response_headers_finished) { li_chunkqueue_steal_all(pcon->vr->out, pcon->proxy_in); pcon->vr->out->is_closed = pcon->proxy_in->is_closed; li_vrequest_handle_response_body(pcon->vr); } /* only possible if we didn't found a header */ if (pcon->proxy_in->is_closed && !pcon->vr->out->is_closed) { VR_ERROR(pcon->vr, "(%s) unexpected end-of-file (perhaps the proxy process died)", pcon->ctx->socket_str->str); li_vrequest_error(pcon->vr); } }
static void fastcgi_fd_cb(struct ev_loop *loop, ev_io *w, int revents) { fastcgi_connection *fcon = (fastcgi_connection*) w->data; if (fcon->state == FS_CONNECTING) { if (LI_HANDLER_GO_ON != fastcgi_statemachine(fcon->vr, fcon)) { li_vrequest_error(fcon->vr); } return; } if (revents & EV_READ) { if (fcon->fcgi_in->is_closed) { li_ev_io_rem_events(loop, w, EV_READ); } else { switch (li_network_read(fcon->vr, w->fd, fcon->fcgi_in, &fcon->fcgi_in_buffer)) { case LI_NETWORK_STATUS_SUCCESS: break; case LI_NETWORK_STATUS_FATAL_ERROR: VR_ERROR(fcon->vr, "(%s) network read fatal error", fcon->ctx->socket_str->str); li_vrequest_error(fcon->vr); return; case LI_NETWORK_STATUS_CONNECTION_CLOSE: fcon->fcgi_in->is_closed = TRUE; ev_io_stop(loop, w); close(fcon->fd); fcon->fd = -1; li_vrequest_backend_finished(fcon->vr); break; case LI_NETWORK_STATUS_WAIT_FOR_EVENT: break; } } } if (fcon->fd != -1 && (revents & EV_WRITE)) { if (fcon->fcgi_out->length > 0) { switch (li_network_write(fcon->vr, w->fd, fcon->fcgi_out, 256*1024)) { case LI_NETWORK_STATUS_SUCCESS: break; case LI_NETWORK_STATUS_FATAL_ERROR: VR_ERROR(fcon->vr, "(%s) network write fatal error", fcon->ctx->socket_str->str); li_vrequest_error(fcon->vr); return; case LI_NETWORK_STATUS_CONNECTION_CLOSE: fcon->fcgi_in->is_closed = TRUE; ev_io_stop(loop, w); close(fcon->fd); fcon->fd = -1; li_vrequest_backend_finished(fcon->vr); break; case LI_NETWORK_STATUS_WAIT_FOR_EVENT: break; } } if (fcon->fcgi_out->length == 0) { li_ev_io_rem_events(loop, w, EV_WRITE); } } if (!fastcgi_parse_response(fcon)) return; if (!fcon->response_headers_finished) { switch (li_http_response_parse(fcon->vr, &fcon->parse_response_ctx)) { case LI_HANDLER_GO_ON: fcon->response_headers_finished = TRUE; li_vrequest_handle_response_headers(fcon->vr); break; case LI_HANDLER_ERROR: VR_ERROR(fcon->vr, "Parsing response header failed for: %s", fcon->ctx->socket_str->str); li_vrequest_error(fcon->vr); break; default: break; } } if (fcon->response_headers_finished) { li_chunkqueue_steal_all(fcon->vr->out, fcon->stdout); fcon->vr->out->is_closed = fcon->stdout->is_closed; li_vrequest_handle_response_body(fcon->vr); } if (fcon->fcgi_in->is_closed && !fcon->vr->out->is_closed) { VR_ERROR(fcon->vr, "(%s) unexpected end-of-file (perhaps the fastcgi process died)", fcon->ctx->socket_str->str); li_vrequest_error(fcon->vr); } }