*/
#include <common/config.h>
+#include <common/cfgparse.h>
#include <common/http.h>
+#include <proto/h1.h>
#include <proto/http_htx.h>
#include <proto/htx.h>
+struct buffer htx_err_chunks[HTTP_ERR_SIZE];
+
/* Finds the start line in the HTX message stopping at the first
* end-of-message. It returns NULL when not found, otherwise, it returns the
* pointer on the htx_sl structure. The HTX message may be updated if the
*vlen = val_hist[hist_idx].len;
return 1;
}
+
+static struct htx *http_str_to_htx(struct buffer *buf, struct ist raw)
+{
+ struct htx *htx;
+ struct htx_sl *sl;
+ struct h1m h1m;
+ struct http_hdr hdrs[MAX_HTTP_HDR];
+ union h1_sl h1sl;
+ unsigned int flags = HTX_SL_F_IS_RESP;
+ int ret = 0;
+
+ buf->size = global.tune.bufsize;
+ buf->area = (char *)malloc(buf->size);
+ if (!buf->area)
+ goto error;
+ b_reset(buf);
+
+ h1m_init_res(&h1m);
+ h1m.flags |= H1_MF_NO_PHDR;
+ ret = h1_headers_to_hdr_list(raw.ptr, raw.ptr + raw.len,
+ hdrs, sizeof(hdrs)/sizeof(hdrs[0]), &h1m, &h1sl);
+ if (ret <= 0)
+ goto error;
+
+ if (unlikely(h1sl.st.v.len != 8))
+ goto error;
+ if ((*(h1sl.st.v.ptr + 5) > '1') ||
+ ((*(h1sl.st.v.ptr + 5) == '1') && (*(h1sl.st.v.ptr + 7) >= '1')))
+ h1m.flags |= H1_MF_VER_11;
+
+ if (h1m.flags & H1_MF_VER_11)
+ flags |= HTX_SL_F_VER_11;
+ if (h1m.flags & H1_MF_XFER_ENC)
+ flags |= HTX_SL_F_XFER_ENC;
+ if (h1m.flags & H1_MF_XFER_LEN) {
+ flags |= HTX_SL_F_XFER_LEN;
+ if (h1m.flags & H1_MF_CHNK)
+ goto error; /* Unsupported because there is no body parsing */
+ else if (h1m.flags & H1_MF_CLEN) {
+ flags |= HTX_SL_F_CLEN;
+ if (h1m.body_len == 0)
+ flags |= HTX_SL_F_BODYLESS;
+ }
+ }
+
+ htx = htx_from_buf(buf);
+ sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, h1sl.st.v, h1sl.st.c, h1sl.st.r);
+ if (!sl || !htx_add_all_headers(htx, hdrs))
+ goto error;
+ sl->info.res.status = h1sl.st.status;
+
+ if (raw.len > ret) {
+ if (!htx_add_data(htx, ist2(raw.ptr + ret, raw.len - ret)))
+ goto error;
+ }
+ if (!htx_add_endof(htx, HTX_BLK_EOM))
+ goto error;
+
+ b_set_data(buf, b_size(buf));
+ return htx;
+
+error:
+ if (buf->size)
+ free(buf->area);
+ return NULL;
+}
+
+static int http_htx_init(void)
+{
+ struct proxy *px;
+ struct buffer chk;
+ struct ist raw;
+ int rc;
+ int err_code = 0;
+
+ for (px = proxies_list; px; px = px->next) {
+ if (!(px->options2 & PR_O2_USE_HTX))
+ continue;
+
+ for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
+ if (!b_data(&px->errmsg[rc]))
+ continue;
+
+ raw = ist2(b_head(&px->errmsg[rc]), b_data(&px->errmsg[rc]));
+ if (!http_str_to_htx(&chk, raw)) {
+ ha_alert("config: %s '%s': Unable to convert message in HTX for HTTP return code %d.\n",
+ proxy_type_str(px), px->id, http_err_codes[rc]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ }
+ chunk_destroy(&px->errmsg[rc]);
+ px->errmsg[rc] = chk;
+ }
+ }
+
+ for (rc = 0; rc < HTTP_ERR_SIZE; rc++) {
+ if (!http_err_msgs[rc]) {
+ ha_alert("Internal error: no message defined for HTTP return code %d", rc);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ continue;
+ }
+
+ raw = ist2(http_err_msgs[rc], strlen(http_err_msgs[rc]));
+ if (!http_str_to_htx(&chk, raw)) {
+ ha_alert("Internal error: Unable to convert message in HTX for HTTP return code %d.\n",
+ http_err_codes[rc]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ }
+ htx_err_chunks[rc] = chk;
+ }
+end:
+ return err_code;
+}
+
+REGISTER_CONFIG_POSTPARSER("http_htx", http_htx_init);
txn->status = 408;
msg->err_state = msg->msg_state;
msg->msg_state = HTTP_MSG_ERROR;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
req->analysers &= AN_REQ_FLT_END;
if (!(s->flags & SF_FINST_MASK))
txn->status = 400;
msg->err_state = msg->msg_state;
msg->msg_state = HTTP_MSG_ERROR;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
req->analysers &= AN_REQ_FLT_END;
if (!(s->flags & SF_FINST_MASK))
if (ret) {
/* we fail this request, let's return 503 service unavail */
txn->status = 503;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_LOCAL; /* we don't want a real error here */
goto return_prx_cond;
/* nothing to fail, let's reply normaly */
txn->status = 200;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_LOCAL; /* we don't want a real error here */
goto return_prx_cond;
txn->status = 400;
txn->req.err_state = txn->req.msg_state;
txn->req.msg_state = HTTP_MSG_ERROR;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
HA_ATOMIC_ADD(&sess->fe->fe_counters.failed_req, 1);
if (sess->listener->counters)
HA_ATOMIC_ADD(&sess->listener->counters->failed_req, 1);
if (unlikely(!stream_int_register_handler(&s->si[1], objt_applet(s->target)))) {
txn->status = 500;
s->logs.tv_request = now;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_RESOURCE;
txn->flags |= TX_CLDENY;
txn->status = http_err_codes[deny_status];
s->logs.tv_request = now;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
stream_inc_http_err_ctr(s);
HA_ATOMIC_ADD(&sess->fe->fe_counters.denied_req, 1);
if (sess->fe != s->be)
txn->req.err_state = txn->req.msg_state;
txn->req.msg_state = HTTP_MSG_ERROR;
txn->status = 400;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
HA_ATOMIC_ADD(&sess->fe->fe_counters.failed_req, 1);
if (sess->listener->counters)
txn->req.msg_state = HTTP_MSG_ERROR;
txn->status = 500;
req->analysers &= AN_REQ_FLT_END;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_RESOURCE;
txn->req.msg_state = HTTP_MSG_ERROR;
txn->status = 400;
req->analysers &= AN_REQ_FLT_END;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
HA_ATOMIC_ADD(&sess->fe->fe_counters.failed_req, 1);
if (sess->listener->counters)
s->logs.t_queue = tv_ms_elapsed(&s->logs.tv_accept, &now);
if (!(req->flags & CF_READ_ERROR))
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
req->analysers &= AN_REQ_FLT_END;
req->analyse_exp = TICK_ETERNITY;
if ((req->flags & CF_READ_TIMEOUT) || tick_is_expired(req->analyse_exp, now_ms)) {
txn->status = 408;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_CLITO;
txn->req.err_state = txn->req.msg_state;
txn->req.msg_state = HTTP_MSG_ERROR;
txn->status = 400;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_PRXCOND;
htx_reply_and_close(s, txn->status, NULL);
} else {
txn->status = 400;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
}
req->analysers &= AN_REQ_FLT_END;
s->res.analysers &= AN_RES_FLT_END; /* we're in data phase, we want to abort both directions */
htx_reply_and_close(s, txn->status, NULL);
} else {
txn->status = 502;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
}
req->analysers &= AN_REQ_FLT_END;
s->res.analysers &= AN_RES_FLT_END; /* we're in data phase, we want to abort both directions */
}
s->si[1].flags |= SI_FL_NOLINGER;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_SRVCL;
rep->analysers &= AN_RES_FLT_END;
txn->status = 504;
s->si[1].flags |= SI_FL_NOLINGER;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_SRVTO;
rep->analysers &= AN_RES_FLT_END;
txn->status = 400;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_CLICL;
rep->analysers &= AN_RES_FLT_END;
txn->status = 502;
s->si[1].flags |= SI_FL_NOLINGER;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_SRVCL;
}
txn->status = 502;
s->si[1].flags |= SI_FL_NOLINGER;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
rep->analysers &= AN_RES_FLT_END;
if (!(s->flags & SF_ERR_MASK))
txn->status = 502;
s->logs.t_data = -1; /* was not a valid response */
s->si[1].flags |= SI_FL_NOLINGER;
- htx_reply_and_close(s, txn->status, http_error_message(s));
+ htx_reply_and_close(s, txn->status, htx_error_message(s));
if (!(s->flags & SF_ERR_MASK))
s->flags |= SF_ERR_PRXCOND;
if (!(s->flags & SF_FINST_MASK))
channel_erase(si_oc(si));
channel_auto_close(si_ic(si));
channel_auto_read(si_ic(si));
+
+ /* <msg> is an HTX structure. So we copy it in the response's
+ * channel */
if (msg) {
struct channel *chn = si_ic(si);
struct htx *htx;
- htx = htx_from_buf(&chn->buf);
- htx_add_oob(htx, ist2(msg->area, msg->data));
//FLT_STRM_CB(s, flt_htx_reply(s, s->txn->status, htx));
+ chn->buf.data = msg->data;
+ memcpy(chn->buf.area, msg->area, msg->data);
+ htx = htx_from_buf(&chn->buf);
b_set_data(&chn->buf, b_size(&chn->buf));
c_adv(chn, htx->data);
chn->total += htx->data;
channel_truncate(&s->res);
s->txn->flags &= ~TX_WAIT_NEXT_RQ;
+
+ /* <msg> is an HTX structure. So we copy it in the response's
+ * channel */
+ /* FIXME: It is a problem for now if there is some outgoing data */
if (msg) {
struct channel *chn = &s->res;
struct htx *htx;
- htx = htx_from_buf(&chn->buf);
- htx_add_oob(htx, ist2(msg->area, msg->data));
//FLT_STRM_CB(s, flt_htx_reply(s, s->txn->status, htx));
+ chn->buf.data = msg->data;
+ memcpy(chn->buf.area, msg->area, msg->data);
+ htx = htx_from_buf(&chn->buf);
b_set_data(&chn->buf, b_size(&chn->buf));
c_adv(chn, htx->data);
chn->total += htx->data;
channel_shutr_now(&s->res);
}
+struct buffer *htx_error_message(struct stream *s)
+{
+ const int msgnum = http_get_status_idx(s->txn->status);
+
+ if (s->be->errmsg[msgnum].area)
+ return &s->be->errmsg[msgnum];
+ else if (strm_fe(s)->errmsg[msgnum].area)
+ return &strm_fe(s)->errmsg[msgnum];
+ else
+ return &htx_err_chunks[msgnum];
+}
+
+
/* Send a 100-Continue response to the client. It returns 0 on success and -1
* on error. The response channel is updated accordingly.
*/