Commit b1f87256 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Turn the guts of http1_wait() into a more general and protocol

independent SES_RxReq() function.

Eliminate timeout_req and rely on timeout_idle to do the job.
(Length of this timeout still under debate on -dev)
parent 80dbd458
...@@ -677,6 +677,10 @@ struct sess { ...@@ -677,6 +677,10 @@ struct sess {
/* Prototypes etc ----------------------------------------------------*/ /* Prototypes etc ----------------------------------------------------*/
/* Cross file typedefs */
typedef enum htc_status_e htc_complete_f(struct http_conn *);
/* cache_acceptor.c */ /* cache_acceptor.c */
void VCA_Init(void); void VCA_Init(void);
void VCA_Shutdown(void); void VCA_Shutdown(void);
...@@ -853,7 +857,7 @@ enum sess_close http_DoConnection(struct http *hp); ...@@ -853,7 +857,7 @@ enum sess_close http_DoConnection(struct http *hp);
/* cache_http1_proto.c */ /* cache_http1_proto.c */
enum htc_status_e HTTP1_Complete(struct http_conn *htc); htc_complete_f HTTP1_Complete;
uint16_t HTTP1_DissectRequest(struct http_conn *htc, struct http *hp); uint16_t HTTP1_DissectRequest(struct http_conn *htc, struct http *hp);
uint16_t HTTP1_DissectResponse(struct http *sp, struct http_conn *htc); uint16_t HTTP1_DissectResponse(struct http *sp, struct http_conn *htc);
unsigned HTTP1_Write(const struct worker *w, const struct http *hp, const int*); unsigned HTTP1_Write(const struct worker *w, const struct http *hp, const int*);
...@@ -985,18 +989,22 @@ task_func_t SES_Proto_Sess; ...@@ -985,18 +989,22 @@ task_func_t SES_Proto_Sess;
task_func_t SES_Proto_Req; task_func_t SES_Proto_Req;
enum htc_status_e { enum htc_status_e {
HTC_S_EMPTY = -4, HTC_S_CLOSE = -4,
HTC_S_TIMEOUT = -3, HTC_S_TIMEOUT = -3,
HTC_S_OVERFLOW = -2, HTC_S_OVERFLOW = -2,
HTC_S_EOF = -1, HTC_S_EOF = -1,
HTC_S_OK = 0, HTC_S_EMPTY = 0,
HTC_S_COMPLETE = 1 HTC_S_MORE = 1,
HTC_S_COMPLETE = 2,
HTC_S_IDLE = 3,
}; };
void SES_RxInit(struct http_conn *htc, struct ws *ws, void SES_RxInit(struct http_conn *htc, struct ws *ws,
unsigned maxbytes, unsigned maxhdr); unsigned maxbytes, unsigned maxhdr);
void SES_RxReInit(struct http_conn *htc); void SES_RxReInit(struct http_conn *htc);
enum htc_status_e SES_Rx(struct http_conn *htc, double tmo); enum htc_status_e SES_Rx(struct http_conn *htc, double tmo);
enum htc_status_e SES_RxReq(const struct worker *, struct req *,
htc_complete_f *func);
#define SESS_ATTR(UP, low, typ, len) \ #define SESS_ATTR(UP, low, typ, len) \
int SES_Get_##low(const struct sess *sp, typ *dst); \ int SES_Get_##low(const struct sess *sp, typ *dst); \
......
...@@ -234,7 +234,65 @@ SES_Rx(struct http_conn *htc, double tmo) ...@@ -234,7 +234,65 @@ SES_Rx(struct http_conn *htc, double tmo)
return (HTC_S_EOF); return (HTC_S_EOF);
htc->rxbuf_e += i; htc->rxbuf_e += i;
*htc->rxbuf_e = '\0'; *htc->rxbuf_e = '\0';
return (HTC_S_OK); return (HTC_S_MORE);
}
/*----------------------------------------------------------------------
* Receive a request/packet/whatever, with timeouts
*/
enum htc_status_e
SES_RxReq(const struct worker *wrk, struct req *req, htc_complete_f *func)
{
double tmo;
double now, when;
struct sess *sp;
enum htc_status_e hs;
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
sp = req->sp;
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
AZ(isnan(sp->t_idle));
assert(isnan(req->t_first));
when = sp->t_idle + cache_param->timeout_idle;
tmo = cache_param->timeout_linger;
while (1) {
hs = SES_Rx(req->htc, tmo);
now = VTIM_real();
if (hs == HTC_S_EOF) {
WS_ReleaseP(req->htc->ws, req->htc->rxbuf_b);
return (HTC_S_CLOSE);
}
if (hs == HTC_S_OVERFLOW) {
WS_ReleaseP(req->htc->ws, req->htc->rxbuf_b);
return (HTC_S_OVERFLOW);
}
hs = func(req->htc);
if (hs == HTC_S_COMPLETE) {
/* Got it, run with it */
if (isnan(req->t_first))
req->t_first = now;
req->t_req = now;
return (HTC_S_COMPLETE);
}
if (when < now)
return (HTC_S_TIMEOUT);
if (hs == HTC_S_MORE) {
/* Working on it */
if (isnan(req->t_first))
req->t_first = now;
tmo = when - now;
continue;
}
assert(hs == HTC_S_EMPTY);
/* Nothing but whitespace */
tmo = sp->t_idle + cache_param->timeout_linger - now;
if (tmo < 0)
return (HTC_S_IDLE);
}
} }
/*-------------------------------------------------------------------- /*--------------------------------------------------------------------
...@@ -422,13 +480,16 @@ SES_Wait(struct sess *sp) ...@@ -422,13 +480,16 @@ SES_Wait(struct sess *sp)
* XXX: waiter_epoll prevents us from zeroing the struct because * XXX: waiter_epoll prevents us from zeroing the struct because
* XXX: it keeps state across calls. * XXX: it keeps state across calls.
*/ */
if (VTCP_nonblocking(sp->fd)) {
SES_Delete(sp, SC_REM_CLOSE, NAN);
return;
}
sp->waited.magic = WAITED_MAGIC; sp->waited.magic = WAITED_MAGIC;
sp->waited.fd = sp->fd; sp->waited.fd = sp->fd;
sp->waited.ptr = sp; sp->waited.ptr = sp;
sp->waited.idle = sp->t_idle; sp->waited.idle = sp->t_idle;
if (Wait_Enter(pp->http1_waiter, &sp->waited)) { if (Wait_Enter(pp->http1_waiter, &sp->waited))
SES_Delete(sp, SC_PIPE_OVERFLOW, NAN); SES_Delete(sp, SC_PIPE_OVERFLOW, NAN);
}
} }
/*-------------------------------------------------------------------- /*--------------------------------------------------------------------
......
...@@ -111,7 +111,6 @@ struct params { ...@@ -111,7 +111,6 @@ struct params {
double timeout_linger; double timeout_linger;
double timeout_idle; double timeout_idle;
double timeout_req;
double pipe_timeout; double pipe_timeout;
double send_timeout; double send_timeout;
double idle_send_timeout; double idle_send_timeout;
......
...@@ -154,7 +154,7 @@ V1F_fetch_hdr(struct worker *wrk, struct busyobj *bo, const char *def_host) ...@@ -154,7 +154,7 @@ V1F_fetch_hdr(struct worker *wrk, struct busyobj *bo, const char *def_host)
first = 1; first = 1;
do { do {
hs = SES_Rx(htc, 0); hs = SES_Rx(htc, 0);
if (hs == HTC_S_OK) if (hs == HTC_S_MORE)
hs = HTTP1_Complete(htc); hs = HTTP1_Complete(htc);
if (hs == HTC_S_OVERFLOW) { if (hs == HTC_S_OVERFLOW) {
WS_ReleaseP(htc->ws, htc->rxbuf_b); WS_ReleaseP(htc->ws, htc->rxbuf_b);
......
...@@ -51,89 +51,39 @@ ...@@ -51,89 +51,39 @@
static enum req_fsm_nxt static enum req_fsm_nxt
http1_wait(struct sess *sp, struct worker *wrk, struct req *req) http1_wait(struct sess *sp, struct worker *wrk, struct req *req)
{ {
double tmo;
double now, when;
enum sess_close why = SC_NULL;
enum htc_status_e hs; enum htc_status_e hs;
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
assert(req->sp == sp);
AZ(req->vcl);
AZ(req->esi_level);
AZ(isnan(sp->t_idle));
assert(isnan(req->t_first));
assert(isnan(req->t_prev)); assert(isnan(req->t_prev));
assert(isnan(req->t_req)); assert(isnan(req->t_req));
AZ(req->vcl);
AZ(req->esi_level);
tmo = cache_param->timeout_linger; hs = SES_RxReq(wrk, req, HTTP1_Complete);
while (1) { if (hs < HTC_S_EMPTY) {
hs = SES_Rx(req->htc, tmo); req->acct.req_hdrbytes += req->htc->rxbuf_e - req->htc->rxbuf_b;
now = VTIM_real(); CNT_AcctLogCharge(wrk->stats, req);
if (hs == HTC_S_EOF) { SES_ReleaseReq(req);
WS_ReleaseP(req->htc->ws, req->htc->rxbuf_b); switch(hs) {
why = SC_REM_CLOSE; case HTC_S_CLOSE: SES_Delete(sp, SC_REM_CLOSE, 0.0); break;
break; case HTC_S_TIMEOUT: SES_Delete(sp, SC_RX_TIMEOUT, 0.0); break;
} case HTC_S_OVERFLOW: SES_Delete(sp, SC_RX_OVERFLOW, 0.0); break;
if (hs == HTC_S_OVERFLOW) { case HTC_S_EOF: SES_Delete(sp, SC_REM_CLOSE, 0.0); break;
WS_ReleaseP(req->htc->ws, req->htc->rxbuf_b); default: WRONG("htc_status (bad)");
why = SC_RX_OVERFLOW;
break;
}
hs = HTTP1_Complete(req->htc);
if (hs == HTC_S_OK) {
/* Working on it */
if (isnan(req->t_first))
/* Record first byte received time stamp */
req->t_first = now;
when = req->t_first + cache_param->timeout_req;
tmo = when - now;
if (tmo <= 0) {
why = SC_RX_TIMEOUT;
break;
}
continue;
}
if (hs == HTC_S_COMPLETE) {
/* Got it, run with it */
if (isnan(req->t_first))
req->t_first = now;
if (isnan(req->t_req))
req->t_req = now;
req->acct.req_hdrbytes +=
req->htc->rxbuf_e - req->htc->rxbuf_b;
return (REQ_FSM_MORE);
}
assert(hs == HTC_S_EMPTY);
/* Nothing but whitespace */
when = sp->t_idle + cache_param->timeout_idle;
if (when < now) {
why = SC_RX_TIMEOUT;
break;
} }
when = sp->t_idle + cache_param->timeout_linger; return (REQ_FSM_DONE);
tmo = when - now; }
if (tmo > 0) if (hs == HTC_S_COMPLETE) {
continue; req->acct.req_hdrbytes +=
req->htc->rxbuf_e - req->htc->rxbuf_b;
return (REQ_FSM_MORE);
}
if (hs == HTC_S_IDLE) {
wrk->stats->sess_herd++; wrk->stats->sess_herd++;
SES_ReleaseReq(req); SES_ReleaseReq(req);
if (VTCP_nonblocking(sp->fd)) {
why = SC_REM_CLOSE;
break;
}
SES_Wait(sp); SES_Wait(sp);
return (REQ_FSM_DONE); return (REQ_FSM_DONE);
} }
req->acct.req_hdrbytes += req->htc->rxbuf_e - req->htc->rxbuf_b; WRONG("htc_status (nonbad)");
CNT_AcctLogCharge(wrk->stats, req);
SES_ReleaseReq(req);
assert(why != SC_NULL);
SES_Delete(sp, why, now);
return (REQ_FSM_DONE);
} }
/*---------------------------------------------------------------------- /*----------------------------------------------------------------------
......
...@@ -61,7 +61,7 @@ const int HTTP1_Resp[3] = { ...@@ -61,7 +61,7 @@ const int HTTP1_Resp[3] = {
* Check if we have a complete HTTP request or response yet * Check if we have a complete HTTP request or response yet
*/ */
enum htc_status_e enum htc_status_e __match_proto__(htc_complete_f)
HTTP1_Complete(struct http_conn *htc) HTTP1_Complete(struct http_conn *htc)
{ {
char *p; char *p;
...@@ -85,7 +85,7 @@ HTTP1_Complete(struct http_conn *htc) ...@@ -85,7 +85,7 @@ HTTP1_Complete(struct http_conn *htc)
while (1) { while (1) {
p = strchr(p, '\n'); p = strchr(p, '\n');
if (p == NULL) if (p == NULL)
return (HTC_S_OK); return (HTC_S_MORE);
p++; p++;
if (*p == '\r') if (*p == '\r')
p++; p++;
......
...@@ -172,16 +172,10 @@ struct parspec mgt_parspec[] = { ...@@ -172,16 +172,10 @@ struct parspec mgt_parspec[] = {
{ "timeout_idle", tweak_timeout, &mgt_param.timeout_idle, { "timeout_idle", tweak_timeout, &mgt_param.timeout_idle,
"0", NULL, "0", NULL,
"Idle timeout for client connections.\n" "Idle timeout for client connections.\n"
"A connection is considered idle, until we receive" "A connection is considered idle, until we have"
" a non-white-space character on it.", "received the full request headers.",
0, 0,
"5", "seconds" }, "5", "seconds" },
{ "timeout_req", tweak_timeout, &mgt_param.timeout_req,
"0", NULL,
"Max time to receive clients request headers, measured"
" from first non-white-space character to double CRNL.",
0,
"2", "seconds" },
{ "pipe_timeout", tweak_timeout, &mgt_param.pipe_timeout, { "pipe_timeout", tweak_timeout, &mgt_param.pipe_timeout,
"0", NULL, "0", NULL,
"Idle timeout for PIPE sessions. " "Idle timeout for PIPE sessions. "
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment