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 liHandlerResult proxy_statemachine(liVRequest *vr, proxy_connection *pcon) { liPlugin *p = pcon->ctx->plugin; switch (pcon->state) { case SS_WAIT_FOR_REQUEST: /* do *not* wait until we have all data */ pcon->state = SS_CONNECT; /* fall through */ case SS_CONNECT: do { pcon->fd = socket(pcon->ctx->socket.addr->plain.sa_family, SOCK_STREAM, 0); } while (-1 == pcon->fd && errno == EINTR); if (-1 == pcon->fd) { if (errno == EMFILE) { li_server_out_of_fds(vr->wrk->srv); } VR_ERROR(vr, "Couldn't open socket: %s", g_strerror(errno)); return LI_HANDLER_ERROR; } li_fd_init(pcon->fd); ev_io_set(&pcon->fd_watcher, pcon->fd, EV_READ | EV_WRITE); ev_io_start(vr->wrk->loop, &pcon->fd_watcher); /* fall through */ case SS_CONNECTING: if (-1 == connect(pcon->fd, &pcon->ctx->socket.addr->plain, pcon->ctx->socket.len)) { switch (errno) { case EINPROGRESS: case EALREADY: case EINTR: pcon->state = SS_CONNECTING; return LI_HANDLER_GO_ON; case EAGAIN: /* backend overloaded */ proxy_close(vr, p); li_vrequest_backend_overloaded(vr); return LI_HANDLER_GO_ON; case EISCONN: break; default: VR_ERROR(vr, "Couldn't connect to '%s': %s", li_sockaddr_to_string(pcon->ctx->socket, vr->wrk->tmp_str, TRUE)->str, g_strerror(errno)); proxy_close(vr, p); li_vrequest_backend_dead(vr); return LI_HANDLER_GO_ON; } } pcon->state = SS_CONNECTED; /* prepare stream */ proxy_send_headers(vr, pcon); /* fall through */ case SS_CONNECTED: proxy_forward_request(vr, pcon); break; case SS_DONE: break; } return LI_HANDLER_GO_ON; }