#define HS_ST_HTTP_HELP 0x0010
#define HS_ST_HTTP_EXPECT 0x0020
#define HS_ST_HTTP_RESP_SL_SENT 0x0040
+#define HS_ST_OPT_CHUNK_RES 0x0080 /* chunk-encoded response (?k=1) */
+#define HS_ST_OPT_REQ_AFTER_RES 0x0100 /* drain the request payload after the response (?A=1) */
+#define HS_ST_OPT_RANDOM_RES 0x0200 /* random response (?R=1) */
+#define HS_ST_OPT_NO_CACHE 0x0400 /* non-cacheable resposne (?c=0) */
const char *HTTP_HELP =
"HAProxy's dummy HTTP server for benchmarks - version " HAPROXY_VERSION ".\n"
" E.g. /?K=1\n"
" - /?t=<time> wait <time> milliseconds before responding.\n"
" E.g. /?t=500\n"
- " - /?k=<enable> Enable transfer encoding chunked with only one chunk if >0 (disable fast-forward and splicing).\n"
+ " - /?k=<enable> Enable transfer encoding chunked with only one chunk if >0.\n"
" - /?S=<enable> Disable use of splice() to send data if <1.\n"
" - /?R=<enable> Enable sending random data if >0.\n"
"\n"
task_wakeup(hs->task, TASK_WOKEN_IO);
}
- if (((!hs->req_after_res || !hs->to_write) && hs->req_body) ||
+ if (((!(hs->flags & HS_ST_OPT_REQ_AFTER_RES) || !hs->to_write) && hs->req_body) ||
!htx_is_empty(htxbuf(&hs->req))) {
TRACE_STATE("waking up task", HS_EV_HSTRM_IO_CB, hs);
task_wakeup(hs->task, TASK_WOKEN_IO);
if (!htxbuf(&hs->res)->data) {
/* This is possible after having drained the body, so after
- * having sent the response here when req_after_res=1.
+ * having sent the response here when HS_ST_OPT_REQ_AFTER_RES flag is set.
*/
ret = 1;
goto out;
TRACE_ENTER(HS_EV_HSTRM_ADD_DATA, hs);
b_add(sd->iobuf.buf, sd->iobuf.offset);
- if (hs->req_random) {
+ if (hs->flags & HS_ST_OPT_RANDOM_RES) {
buffer = random_resp;
buffer_len = random_resp_len;
modulo = random_resp_len;
TRACE_ENTER(HS_EV_HSTRM_ADD_DATA, hs);
- if (hs->req_chunked) {
+ if (hs->flags & HS_ST_OPT_CHUNK_RES) {
buffer = common_chunk_resp;
buffer_len = sizeof(common_chunk_resp);
modulo = sizeof(common_chunk_resp);
}
- else if (hs->req_random) {
+ else if (hs->flags & HS_ST_OPT_RANDOM_RES) {
buffer = random_resp;
buffer_len = random_resp_len;
modulo = random_resp_len;
int ret = 0;
struct buffer *buf;
struct htx *htx;
- unsigned int flags = HTX_SL_F_IS_RESP | HTX_SL_F_XFER_LEN | (!hs->req_chunked ? HTX_SL_F_CLEN : 0);
+ unsigned int flags = HTX_SL_F_IS_RESP | HTX_SL_F_XFER_LEN | (!(hs->flags & HS_ST_OPT_CHUNK_RES) ? HTX_SL_F_CLEN : 0);
struct htx_sl *sl;
char *end;
}
}
- if (!hs->req_chunked && (hs->ka & 1)) {
+ if (!(hs->flags & HS_ST_OPT_CHUNK_RES) && (hs->ka & 1)) {
char *end = ultoa_o(hs->req_size, trash.area, trash.size);
if (!htx_add_header(htx, ist("Content-Length"), ist2(trash.area, end - trash.area))) {
TRACE_ERROR("could not add content-length HTX header", HS_EV_HSTRM_RESP, hs);
}
}
- if (!hs->req_cache && !htx_add_header(htx, ist("Cache-control"), ist("no-cache"))) {
+ if ((hs->flags & HS_ST_OPT_NO_CACHE) && !htx_add_header(htx, ist("Cache-control"), ist("no-cache"))) {
TRACE_ERROR("could not add cache-control HTX header", HS_EV_HSTRM_RESP, hs);
goto err;
}
if (!end)
goto err;
trash.data = end - trash.area;
- if (!chunk_strcat(&trash, ", cache=")) {
+ if (!chunk_strcat(&trash, ((hs->flags & HS_ST_OPT_NO_CACHE) ? ", cache=0" : ", cache=1"))) {
TRACE_ERROR("could not build x-rsp HTX header", HS_EV_HSTRM_RESP, hs);
goto err;
}
- end = ultoa_o(hs->req_cache, trash.area + trash.data, trash.size - trash.data);
- if (!end)
- goto err;
- trash.data = end - trash.area;
- if (hs->req_chunked && !chunk_strcat(&trash, ", chunked,")) {
+ if ((hs->flags & HS_ST_OPT_CHUNK_RES) && !chunk_strcat(&trash, ", chunked,")) {
TRACE_ERROR("could not build x-rsp HTX header", HS_EV_HSTRM_RESP, hs);
goto err;
}
hs->res_wait = MS_TO_TICKS(result << mult);
break;
case 'c':
- hs->req_cache = result << mult;
+ if (result < 1)
+ hs->flags |= HS_ST_OPT_NO_CACHE;
+ else
+ hs->flags &= ~HS_ST_OPT_NO_CACHE;
break;
case 'A':
- hs->req_after_res = result;
+ if (result > 0)
+ hs->flags |= HS_ST_OPT_REQ_AFTER_RES;
+ else
+ hs->flags &= ~HS_ST_OPT_REQ_AFTER_RES;
break;
case 'C':
hs->ka = (hs->ka & 4) | 2 | !result; // forced OFF
hs->ka = (hs->ka & 4) | 2 | !!result; // forced ON
break;
case 'k':
- hs->req_chunked = result;
+ if (result > 0)
+ hs->flags |= HS_ST_OPT_CHUNK_RES;
+ else
+ hs->flags &= ~HS_ST_OPT_CHUNK_RES;
break;
case 'R':
- hs->req_random = result;
+ if (result > 0)
+ hs->flags |= HS_ST_OPT_RANDOM_RES;
+ else
+ hs->flags &= ~HS_ST_OPT_RANDOM_RES;
break;
}
arg = next;
/* Must be called before sending to determine if the body request must be
* 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 ->req_after_res=0.
+ * 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 (->req_after_res=0) or
+ * sent the response (HS_ST_OPT_REQ_AFTER_RES not set) or
*/
static inline int hstream_must_drain(struct hstream *hs)
{
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->req_after_res);
+ ((!hs->to_write && htx_is_empty(htxbuf(&hs->res))) || !(hs->flags & HS_ST_OPT_REQ_AFTER_RES));
TRACE_LEAVE(HS_EV_PROCESS_HSTRM, hs);
return ret;
return (!(global.tune.no_zero_copy_fwd & NO_ZERO_COPY_FWD) &&
sc_ep_test(hs->sc, SE_FL_MAY_FASTFWD_CONS) &&
!(hs->sc->sedesc->iobuf.flags & IOBUF_FL_NO_FF) &&
- !hs->req_chunked && hs->to_write);
+ !(hs->flags & HS_ST_OPT_CHUNK_RES) && hs->to_write);
}
/* haterm stream processing task */
}
if (hstream_must_drain(hs)) {
- /* The request must be drained before sending the response (hs->req_after_res=0).
+ /* The request must be drained before sending the response (HS_ST_OPT_REQ_AFTER_RES not set).
* The body will be drained upon next wakeup.
*/
TRACE_STATE("waking up task", HS_EV_HSTRM_IO_CB, hs);
goto err;
if (hstream_must_drain(hs)) {
- /* The request must be drained before sending the response (hs->req_after_res=0).
+ /* The request must be drained before sending the response (HS_ST_OPT_REQ_AFTER_RES not set).
* The body will be drained upon next wakeup.
*/
TRACE_STATE("waking up task", HS_EV_HSTRM_IO_CB, hs);
hstream_htx_buf_snd(conn, hs);
send_done:
- if (hs->req_body && hs->req_after_res && !hs->to_write) {
+ if (hs->req_body && (hs->flags & HS_ST_OPT_REQ_AFTER_RES) && !hs->to_write) {
/* Response sending has just complete. The body will be drained upon
* next wakeup.
*/
hs->flags = 0;
hs->ka = 0;
- hs->req_cache = 1;
hs->req_size = 0;
hs->req_body = 0;
hs->req_code = 200;
hs->res_wait = TICK_ETERNITY;
hs->res_time = TICK_ETERNITY;
- hs->req_chunked = 0;
- hs->req_random = 0;
- hs->req_after_res = 0;
hs->req_meth = HTTP_METH_OTHER;
if (sc_conn(sc)) {