static liHandlerResult proxy_handle(liVRequest *vr, gpointer param, gpointer *context) { liBackendWait *bwait = (liBackendWait*) *context; liBackendConnection *bcon = NULL; proxy_context *ctx = (proxy_context*) param; liBackendResult bres; if (li_vrequest_is_handled(vr)) return LI_HANDLER_GO_ON; LI_VREQUEST_WAIT_FOR_REQUEST_BODY(vr); if (vr->request.content_length < 0) { VR_ERROR(vr, "%s", "proxy can't handle progressive uploads yet. enable request body buffering!"); return LI_HANDLER_ERROR; } bres = li_backend_get(vr, ctx->pool, &bcon, &bwait); *context = bwait; switch (bres) { case LI_BACKEND_SUCCESS: LI_FORCE_ASSERT(NULL == bwait); LI_FORCE_ASSERT(NULL != bcon); break; case LI_BACKEND_WAIT: LI_FORCE_ASSERT(NULL != bwait); return LI_HANDLER_WAIT_FOR_EVENT; case LI_BACKEND_TIMEOUT: li_vrequest_backend_dead(vr); return LI_HANDLER_GO_ON; } proxy_connection_new(vr, bcon, ctx); return LI_HANDLER_GO_ON; }
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; }
static liHandlerResult fastcgi_statemachine(liVRequest *vr, fastcgi_connection *fcon) { liPlugin *p = fcon->ctx->plugin; switch (fcon->state) { case FS_WAIT_FOR_REQUEST: /* wait until we have either all data or the cqlimit is full */ if (-1 == vr->request.content_length || vr->request.content_length != vr->in->length) { if (0 != li_chunkqueue_limit_available(vr->in)) return LI_HANDLER_GO_ON; } fcon->state = FS_CONNECT; /* fall through */ case FS_CONNECT: do { fcon->fd = socket(fcon->ctx->socket.addr->plain.sa_family, SOCK_STREAM, 0); } while (-1 == fcon->fd && errno == EINTR); if (-1 == fcon->fd) { if (errno == EMFILE) { li_server_out_of_fds(vr->wrk->srv); } else if (errno != g_atomic_int_get(&fcon->ctx->last_errno)) { g_atomic_int_set(&fcon->ctx->last_errno, errno); VR_ERROR(vr, "Couldn't open socket: %s", g_strerror(errno)); } return LI_HANDLER_ERROR; } li_fd_init(fcon->fd); ev_io_set(&fcon->fd_watcher, fcon->fd, EV_READ | EV_WRITE); ev_io_start(vr->wrk->loop, &fcon->fd_watcher); /* fall through */ case FS_CONNECTING: if (-1 == connect(fcon->fd, &fcon->ctx->socket.addr->plain, fcon->ctx->socket.len)) { switch (errno) { case EINPROGRESS: case EALREADY: case EINTR: fcon->state = FS_CONNECTING; return LI_HANDLER_GO_ON; case EAGAIN: /* backend overloaded */ fastcgi_close(vr, p); li_vrequest_backend_overloaded(vr); return LI_HANDLER_GO_ON; case EISCONN: break; default: if (errno != g_atomic_int_get(&fcon->ctx->last_errno)) { g_atomic_int_set(&fcon->ctx->last_errno, errno); VR_ERROR(vr, "Couldn't connect to '%s': %s", li_sockaddr_to_string(fcon->ctx->socket, vr->wrk->tmp_str, TRUE)->str, g_strerror(errno)); } fastcgi_close(vr, p); li_vrequest_backend_dead(vr); return LI_HANDLER_GO_ON; } } g_atomic_int_set(&fcon->ctx->last_errno, 0); fcon->state = FS_CONNECTED; /* prepare stream */ fastcgi_send_begin(fcon); fastcgi_send_env(vr, fcon); /* fall through */ case FS_CONNECTED: fastcgi_forward_request(vr, fcon); break; case FS_DONE: break; } return LI_HANDLER_GO_ON; }