MINOR: http-ana: Use a dedicated function to send a response from an http reply
The http_reply_message() function may be used to send an http reply to a
client. This function is responsile to convert the reply in HTX, to push it in
the response buffer and to forward it to the client. It is also responsible to
terminate the transaction.
This function is used during evaluation of http return rules.
diff --git a/include/proto/http_ana.h b/include/proto/http_ana.h
index 62fd74d..f021cb0 100644
--- a/include/proto/http_ana.h
+++ b/include/proto/http_ana.h
@@ -52,6 +52,7 @@
void http_reply_and_close(struct stream *s, short status, const struct buffer *msg);
void http_return_srv_error(struct stream *s, struct stream_interface *si);
struct buffer *http_error_message(struct stream *s);
+int http_reply_message(struct stream *s, struct http_reply *reply);
int http_forward_proxy_resp(struct stream *s, int final);
struct http_txn *http_alloc_txn(struct stream *s);
diff --git a/src/http_act.c b/src/http_act.c
index b7a6603..61ffd52 100644
--- a/src/http_act.c
+++ b/src/http_act.c
@@ -1818,92 +1818,10 @@
struct session *sess, struct stream *s, int flags)
{
struct channel *req = &s->req;
- struct channel *res = &s->res;
- struct buffer *errmsg;
- struct htx *htx = htx_from_buf(&res->buf);
- struct htx_sl *sl;
- struct buffer *body = NULL;
- const char *status, *reason, *clen, *ctype;
- unsigned int slflags;
- enum act_return ret = ACT_RET_ABRT;
- s->txn->status = rule->arg.http_reply->status;
- channel_htx_truncate(res, htx);
+ if (http_reply_message(s, rule->arg.http_reply) == -1)
+ return ACT_RET_ERR;
- /* HTTP_REPLY_ERRFILES unexpected here. handled as no payload if so */
-
- if (rule->arg.http_reply->type == HTTP_REPLY_ERRMSG) {
- /* implicit or explicit error message*/
- errmsg = rule->arg.http_reply->body.errmsg;
- if (!errmsg) {
- /* get default error message */
- errmsg = http_error_message(s);
- }
- if (b_is_null(errmsg))
- goto end;
- if (!channel_htx_copy_msg(res, htx, errmsg))
- goto fail;
- }
- else {
- /* no payload, file or log-format string */
- if (rule->arg.http_reply->type == HTTP_REPLY_RAW) {
- /* file */
- body = &rule->arg.http_reply->body.obj;
- }
- else if (rule->arg.http_reply->type == HTTP_REPLY_LOGFMT) {
- /* log-format string */
- body = alloc_trash_chunk();
- if (!body)
- goto fail_alloc;
- body->data = build_logline(s, body->area, body->size, &rule->arg.http_reply->body.fmt);
- }
- /* else no payload */
-
- status = ultoa(rule->arg.http_reply->status);
- reason = http_get_reason(rule->arg.http_reply->status);
- slflags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11|HTX_SL_F_XFER_LEN|HTX_SL_F_CLEN);
- if (!body || !b_data(body))
- slflags |= HTX_SL_F_BODYLESS;
- sl = htx_add_stline(htx, HTX_BLK_RES_SL, slflags, ist("HTTP/1.1"), ist(status), ist(reason));
- if (!sl)
- goto fail;
- sl->info.res.status = rule->arg.http_reply->status;
-
- clen = (body ? ultoa(b_data(body)) : "0");
- ctype = rule->arg.http_reply->ctype;
-
- if (!LIST_ISEMPTY(&rule->arg.http_reply->hdrs)) {
- struct http_reply_hdr *hdr;
- struct buffer *value = alloc_trash_chunk();
-
- if (!value)
- goto fail;
-
- list_for_each_entry(hdr, &rule->arg.http_reply->hdrs, list) {
- chunk_reset(value);
- value->data = build_logline(s, value->area, value->size, &hdr->value);
- if (b_data(value) && !htx_add_header(htx, hdr->name, ist2(b_head(value), b_data(value)))) {
- free_trash_chunk(value);
- goto fail;
- }
- chunk_reset(value);
- }
- free_trash_chunk(value);
- }
-
- if (!htx_add_header(htx, ist("content-length"), ist(clen)) ||
- (body && b_data(body) && ctype && !htx_add_header(htx, ist("content-type"), ist(ctype))) ||
- !htx_add_endof(htx, HTX_BLK_EOH) ||
- (body && b_data(body) && !htx_add_data_atonce(htx, ist2(b_head(body), b_data(body)))) ||
- !htx_add_endof(htx, HTX_BLK_EOM))
- goto fail;
- }
-
- htx_to_buf(htx, &s->res.buf);
- if (!http_forward_proxy_resp(s, 1))
- goto fail;
-
- end:
if (rule->from == ACT_F_HTTP_REQ) {
/* let's log the request time */
s->logs.tv_request = now;
@@ -1918,25 +1836,7 @@
if (!(s->flags & SF_FINST_MASK))
s->flags |= ((rule->from == ACT_F_HTTP_REQ) ? SF_FINST_R : SF_FINST_H);
- leave:
- if (rule->arg.http_reply->type == HTTP_REPLY_LOGFMT)
- free_trash_chunk(body);
- return ret;
-
- fail_alloc:
- if (!(s->flags & SF_ERR_MASK))
- s->flags |= SF_ERR_RESOURCE;
- ret = ACT_RET_ERR;
- goto leave;
-
- fail:
- /* If an error occurred, remove the incomplete HTTP response from the
- * buffer */
- channel_htx_truncate(res, htx);
- ret = ACT_RET_ERR;
- if (!(s->flags & SF_ERR_MASK))
- s->flags |= SF_ERR_PRXCOND;
- goto leave;
+ return ACT_RET_ABRT;
}
/* Check an "http-request return" action. The function returns 1 in success
diff --git a/src/http_ana.c b/src/http_ana.c
index 7fd371e..0439377 100644
--- a/src/http_ana.c
+++ b/src/http_ana.c
@@ -4661,6 +4661,118 @@
return &http_err_chunks[msgnum];
}
+/* Produces a response from an http reply. Depending on the http reply type, a,
+ * errorfile, an raw file or a log-format string is used. On success, it returns
+ * 0. If an error occurs -1 is returned.
+ */
+int http_reply_message(struct stream *s, struct http_reply *reply)
+{
+ struct channel *res = &s->res;
+ struct buffer *errmsg;
+ struct htx *htx = htx_from_buf(&res->buf);
+ struct htx_sl *sl;
+ struct buffer *body = NULL;
+ const char *status, *reason, *clen, *ctype;
+ unsigned int slflags;
+ int ret = 0;
+
+ s->txn->status = reply->status;
+ channel_htx_truncate(res, htx);
+
+ /* HTTP_REPLY_ERRFILES unexpected here. handled as no payload if so */
+
+ if (reply->type == HTTP_REPLY_ERRMSG) {
+ /* implicit or explicit error message*/
+ errmsg = reply->body.errmsg;
+ if (!errmsg) {
+ /* get default error message */
+ errmsg = http_error_message(s);
+ }
+ if (b_is_null(errmsg))
+ goto leave;
+ if (!channel_htx_copy_msg(res, htx, errmsg))
+ goto fail;
+ }
+ else {
+ /* no payload, file or log-format string */
+ if (reply->type == HTTP_REPLY_RAW) {
+ /* file */
+ body = &reply->body.obj;
+ }
+ else if (reply->type == HTTP_REPLY_LOGFMT) {
+ /* log-format string */
+ body = alloc_trash_chunk();
+ if (!body)
+ goto fail_alloc;
+ body->data = build_logline(s, body->area, body->size, &reply->body.fmt);
+ }
+ /* else no payload */
+
+ status = ultoa(reply->status);
+ reason = http_get_reason(reply->status);
+ slflags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11|HTX_SL_F_XFER_LEN|HTX_SL_F_CLEN);
+ if (!body || !b_data(body))
+ slflags |= HTX_SL_F_BODYLESS;
+ sl = htx_add_stline(htx, HTX_BLK_RES_SL, slflags, ist("HTTP/1.1"), ist(status), ist(reason));
+ if (!sl)
+ goto fail;
+ sl->info.res.status = reply->status;
+
+ clen = (body ? ultoa(b_data(body)) : "0");
+ ctype = reply->ctype;
+
+ if (!LIST_ISEMPTY(&reply->hdrs)) {
+ struct http_reply_hdr *hdr;
+ struct buffer *value = alloc_trash_chunk();
+
+ if (!value)
+ goto fail;
+
+ list_for_each_entry(hdr, &reply->hdrs, list) {
+ chunk_reset(value);
+ value->data = build_logline(s, value->area, value->size, &hdr->value);
+ if (b_data(value) && !htx_add_header(htx, hdr->name, ist2(b_head(value), b_data(value)))) {
+ free_trash_chunk(value);
+ goto fail;
+ }
+ chunk_reset(value);
+ }
+ free_trash_chunk(value);
+ }
+
+ if (!htx_add_header(htx, ist("content-length"), ist(clen)) ||
+ (body && b_data(body) && ctype && !htx_add_header(htx, ist("content-type"), ist(ctype))) ||
+ !htx_add_endof(htx, HTX_BLK_EOH) ||
+ (body && b_data(body) && !htx_add_data_atonce(htx, ist2(b_head(body), b_data(body)))) ||
+ !htx_add_endof(htx, HTX_BLK_EOM))
+ goto fail;
+ }
+
+ htx_to_buf(htx, &s->res.buf);
+ if (!http_forward_proxy_resp(s, 1))
+ goto fail;
+
+ leave:
+ if (reply->type == HTTP_REPLY_LOGFMT)
+ free_trash_chunk(body);
+ return ret;
+
+ fail_alloc:
+ if (!(s->flags & SF_ERR_MASK))
+ s->flags |= SF_ERR_RESOURCE;
+ ret = -1;
+ goto leave;
+
+ fail:
+ /* If an error occurred, remove the incomplete HTTP response from the
+ * buffer */
+ channel_htx_truncate(res, htx);
+ ret = -1;
+ if (!(s->flags & SF_ERR_MASK))
+ s->flags |= SF_ERR_PRXCOND;
+ goto leave;
+}
+
/* Return the error message corresponding to si->err_type. It is assumed
* that the server side is closed. Note that err_type is actually a
* bitmask, where almost only aborts may be cumulated with other