#define HS_ST_OPT_RANDOM_RES 0x0200 /* random response (?R=1) */
#define HS_ST_OPT_NO_CACHE 0x0400 /* non-cacheable response (?c=0) */
#define HS_ST_OPT_NO_SPLICING 0x0800 /* no splicing (?S=1) */
+#define HS_ST_HTTP_EOM_RCVD 0x1000 /* EOM received */
+#define HS_ST_HTTP_EOM_SENT 0x2000 /* EOM sent */
const char *HTTP_HELP =
"HAProxy's dummy HTTP server for benchmarks - version " HAPROXY_VERSION ".\n"
task_wakeup(hs->task, TASK_WOKEN_IO);
}
- if (((!(hs->flags & HS_ST_OPT_REQ_AFTER_RES) || !hs->to_write) && hs->req_body) ||
- !htx_is_empty(htxbuf(&hs->req))) {
+ if ((hs->flags & (HS_ST_HTTP_EOM_SENT|HS_ST_HTTP_EOM_RCVD)) != (HS_ST_HTTP_EOM_SENT|HS_ST_HTTP_EOM_RCVD) ||
+ !htx_is_empty(htxbuf(&hs->req)) || !htx_is_empty(htxbuf(&hs->res))) {
TRACE_STATE("waking up task", HS_EV_HSTRM_IO_CB, hs);
task_wakeup(hs->task, TASK_WOKEN_IO);
}
- else if (hs->to_write || !htx_is_empty(htxbuf(&hs->res))) {
- TRACE_STATE("waking up task", HS_EV_HSTRM_IO_CB, hs);
- task_wakeup(hs->task, TASK_WOKEN_IO);
- }
-
TRACE_LEAVE(HS_EV_HSTRM_IO_CB, hs);
return t;
}
cur_read += read;
if (!htx_expect_more(htxbuf(&hs->req))) {
fin = 1;
+ hs->flags |= HS_ST_HTTP_EOM_RCVD;
break;
}
sd->iobuf.pipe->data += ret;
hs->to_write -= ret;
}
- if (!hs->to_write)
+ if (!hs->to_write) {
sd->iobuf.flags |= IOBUF_FL_EOI;
+ hs->flags |= HS_ST_HTTP_EOM_SENT;
+ }
goto done;
}
#endif
hs->to_write -= hstream_add_ff_data(hs, sd, len);
- if (!hs->to_write)
+ if (!hs->to_write) {
sd->iobuf.flags |= IOBUF_FL_EOI;
+ hs->flags |= HS_ST_HTTP_EOM_SENT;
+ }
done:
if (se_done_ff(sd) != 0 || !(sd->iobuf.flags & (IOBUF_FL_FF_BLOCKED|IOBUF_FL_FF_WANT_ROOM))) {
TRACE_DEVEL("data not fully sent, wait", HS_EV_HSTRM_SEND, hs);
conn->mux->subscribe(hs->sc, SUB_RETRY_SEND, &hs->sc->wait_event);
}
- else if (hs->to_write) {
+ else if (!(hs->flags & HS_ST_HTTP_EOM_SENT)) {
TRACE_STATE("waking up task", HS_EV_HSTRM_IO_CB, hs);
task_wakeup(hs->task, TASK_WOKEN_IO);
}
/* The HTX data are not fully sent if the last HTX data
* were not fully transferred or if there are remaining data
- * to send (->to_write > 0).
+ * to send (HS_ST_HTTP_EOM_SENT flag set).
*/
if (!htx_is_empty(htxbuf(&hs->res))) {
TRACE_DEVEL("data not fully sent, wait", HS_EV_HSTRM_SEND, hs);
conn->mux->subscribe(sc, SUB_RETRY_SEND, &sc->wait_event);
}
- else if (hs->to_write) {
+ else if (!(hs->flags & HS_ST_HTTP_EOM_SENT)) {
TRACE_STATE("waking up task", HS_EV_HSTRM_IO_CB, hs);
task_wakeup(hs->task, TASK_WOKEN_IO);
}
}
htx->flags |= HTX_FL_EOM;
+ hs->flags |= HS_ST_HTTP_EOM_SENT;
htx_to_buf(htx, buf);
sl->info.res.status = 200;
ret = 1;
if (hs->to_write > 0)
hs->to_write -= hstream_add_htx_data(hs, htx, hs->to_write);
- if (hs->to_write <= 0)
+ if (hs->to_write <= 0) {
htx->flags |= HTX_FL_EOM;
+ hs->flags |= HS_ST_HTTP_EOM_SENT;
+ }
htx_to_buf(htx, buf);
sl->info.res.status = hs->req_code;
* drained asap before sending. Return 1 if this is the case, 0 if not.
* This is the case by default before sending the response except if
* the contrary has been asked with flag HS_ST_OPT_REQ_AFTER_RES.
- * Return true if the body request has not been fully drained (->hs->req_body>0)
- * and if the response has been sent (hs->to_write=0 &&
- * htx_is_empty(htxbuf(&hs->res) or if it must not be drained after having
- * sent the response (HS_ST_OPT_REQ_AFTER_RES not set) or
+ * Return 1 if there is not error and the request was not fully drained
+ * (HS_ST_HTTP_EOM_RCVD flag not set) and if it must not be drained after
+ * having sent the response (HS_ST_OPT_REQ_AFTER_RES not set) or the response
+ * was sent (HS_ST_HTTP_EOM_SENT flag set)
*/
static inline int hstream_must_drain(struct hstream *hs)
{
int ret;
TRACE_ENTER(HS_EV_PROCESS_HSTRM, hs);
- ret = !(hs->flags & HS_ST_CONN_ERROR) && hs->req_body > 0 &&
- ((!hs->to_write && htx_is_empty(htxbuf(&hs->res))) || !(hs->flags & HS_ST_OPT_REQ_AFTER_RES));
+ ret = !(hs->flags & HS_ST_CONN_ERROR) && !(hs->flags & HS_ST_HTTP_EOM_RCVD) &&
+ (!(hs->flags & HS_ST_OPT_REQ_AFTER_RES) || (hs->flags & HS_ST_HTTP_EOM_SENT));
TRACE_LEAVE(HS_EV_PROCESS_HSTRM, hs);
return ret;
/* The request body has always been fully received */
TRACE_STATE("no more expected data", HS_EV_HSTRM_RESP, hs);
hs->req_body = 0;
+ hs->flags |= HS_ST_HTTP_EOM_RCVD;
}
if (hstream_must_drain(hs)) {
/* fallback to regular send */
}
- if (!hs->to_write && htx_is_empty(htxbuf(&hs->res)))
+ if ((hs->flags & HS_ST_HTTP_EOM_SENT) && htx_is_empty(htxbuf(&hs->res)))
goto out;
buf = hstream_get_buf(hs, &hs->res);
htx = htx_from_buf(buf);
if (hs->to_write > 0)
hs->to_write -= hstream_add_htx_data(hs, htx, hs->to_write);
- if (hs->to_write <= 0)
+ if (hs->to_write <= 0) {
htx->flags |= HTX_FL_EOM;
+ hs->flags |= HS_ST_HTTP_EOM_SENT;
+ }
htx_to_buf(htx, &hs->res);
flush_res_buf:
hstream_htx_buf_snd(conn, hs);
+ }
send_done:
- if (hs->req_body && (hs->flags & HS_ST_OPT_REQ_AFTER_RES) && !hs->to_write) {
- /* Response sending has just completed. The body will be drained upon
- * next wakeup.
- */
- TRACE_STATE("waking up task", HS_EV_HSTRM_IO_CB, hs);
- task_wakeup(hs->task, TASK_WOKEN_IO);
- goto out;
- }
+ if ((hs->flags & (HS_ST_HTTP_EOM_SENT|HS_ST_HTTP_EOM_RCVD|HS_ST_OPT_REQ_AFTER_RES)) == (HS_ST_HTTP_EOM_SENT|HS_ST_OPT_REQ_AFTER_RES)) {
+ /* Response sending has just completed. The body will be drained upon
+ * next wakeup.
+ */
+ TRACE_STATE("waking up task", HS_EV_HSTRM_IO_CB, hs);
+ task_wakeup(hs->task, TASK_WOKEN_IO);
+ goto out;
}
out:
- if (!hs->to_write && !hs->req_body && htx_is_empty(htxbuf(&hs->res)) && !se_have_ff_data(hs->sc->sedesc)) {
+ if (hs->flags & HS_ST_CONN_ERROR ||
+ ((hs->flags & (HS_ST_HTTP_EOM_SENT|HS_ST_HTTP_EOM_RCVD)) == (HS_ST_HTTP_EOM_SENT|HS_ST_HTTP_EOM_RCVD) &&
+ htx_is_empty(htxbuf(&hs->res)) && !se_have_ff_data(hs->sc->sedesc))) {
TRACE_DEVEL("shutting down stream", HS_EV_HSTRM_SEND, hs);
- CALL_MUX_NO_RET(conn->mux, shut(hs->sc, SE_SHW_SILENT|SE_SHW_NORMAL, NULL));
- }
+ se_shutdown(hs->sc->sedesc,SE_SHW_SILENT|SE_SHW_NORMAL);
- if (hs->flags & HS_ST_CONN_ERROR ||
- (!hs->to_write && !hs->req_body && htx_is_empty(htxbuf(&hs->res)))) {
TRACE_STATE("releasing hstream", HS_EV_PROCESS_HSTRM, hs);
hstream_free(hs);
hs = NULL;