]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: http-ana: Use a dedicated function to send a response from an http reply
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 13 May 2020 14:38:37 +0000 (16:38 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 20 May 2020 16:27:13 +0000 (18:27 +0200)
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.

include/proto/http_ana.h
src/http_act.c
src/http_ana.c

index 62fd74d7e0cbfc727c7dc6979d741231a6f1d7bb..f021cb0b9ac5be656664b2e1c0b8dafa486141fb 100644 (file)
@@ -52,6 +52,7 @@ void http_server_error(struct stream *s, struct stream_interface *si, int err, i
 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);
index b7a6603c9fb433bce62fe214b242827021d48e46..61ffd5261c4924664f5eed7229b0bb836855802a 100644 (file)
@@ -1818,92 +1818,10 @@ static enum act_return http_action_return(struct act_rule *rule, struct proxy *p
                                          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);
-
-       /* 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;
+       if (http_reply_message(s, rule->arg.http_reply) == -1)
+               return ACT_RET_ERR;
 
-  end:
        if (rule->from == ACT_F_HTTP_REQ) {
                /* let's log the request time */
                s->logs.tv_request = now;
@@ -1918,25 +1836,7 @@ static enum act_return http_action_return(struct act_rule *rule, struct proxy *p
        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
index 7fd371ea562bf73f7da8eebc1dd31b0d7c20bee1..04393776083d817baf1f96a044791f1996cb62c9 100644 (file)
@@ -4661,6 +4661,118 @@ struct buffer *http_error_message(struct stream *s)
                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