MINOR: http-rules: Use an action function to eval http-request auth rules

Now http-request auth rules are evaluated in a dedicated function and no longer
handled "in place" during the HTTP rules evaluation. Thus the action name
ACT_HTTP_REQ_AUTH is removed. In additionn, http_reply_40x_unauthorized() is
also removed. This part is now handled in the new action_ptr callback function.
diff --git a/include/types/action.h b/include/types/action.h
index b01380c..00c37fa 100644
--- a/include/types/action.h
+++ b/include/types/action.h
@@ -89,7 +89,6 @@
 
 	/* http request actions. */
 	ACT_HTTP_REQ_TARPIT,
-	ACT_HTTP_REQ_AUTH,
 
 	/* tcp actions */
 	ACT_TCP_EXPECT_PX,
diff --git a/src/http_act.c b/src/http_act.c
index ab4a8bb..b18da61 100644
--- a/src/http_act.c
+++ b/src/http_act.c
@@ -25,6 +25,7 @@
 #include <common/initcall.h>
 #include <common/memory.h>
 #include <common/standard.h>
+#include <common/uri_auth.h>
 #include <common/version.h>
 
 #include <types/capture.h>
@@ -884,6 +885,85 @@
 	return ACT_RET_PRS_OK;
 }
 
+
+/* This function executes a auth action. It builds an 401/407 HTX message using
+ * the corresponding proxy's error message. On success, it returns
+ * ACT_RET_ABRT. If an error occurs ACT_RET_ERR is returned.
+ */
+static enum act_return http_action_auth(struct act_rule *rule, struct proxy *px,
+					struct session *sess, struct stream *s, int flags)
+{
+	struct channel *req = &s->req;
+	struct channel *res = &s->res;
+	struct htx *htx = htx_from_buf(&res->buf);
+	struct http_reply *reply;
+	const char *auth_realm;
+	struct http_hdr_ctx ctx;
+	struct ist hdr;
+
+	/* Auth might be performed on regular http-req rules as well as on stats */
+	auth_realm = rule->arg.http.str.ptr;
+	if (!auth_realm) {
+		if (px->uri_auth && s->current_rule_list == &px->uri_auth->http_req_rules)
+			auth_realm = STATS_DEFAULT_REALM;
+		else
+			auth_realm = px->id;
+	}
+
+	if (!(s->txn->flags & TX_USE_PX_CONN)) {
+		s->txn->status = 401;
+		hdr = ist("WWW-Authenticate");
+	}
+	else {
+		s->txn->status = 407;
+		hdr = ist("Proxy-Authenticate");
+	}
+	reply = http_error_message(s);
+	channel_htx_truncate(res, htx);
+
+	if (chunk_printf(&trash, "Basic realm=\"%s\"", auth_realm) == -1)
+		goto fail;
+
+	/* Write the generic 40x message */
+	if (http_reply_to_htx(s, htx, reply) == -1)
+		goto fail;
+
+	/* Remove all existing occurrences of the XXX-Authenticate header */
+	ctx.blk = NULL;
+	while (http_find_header(htx, hdr, &ctx, 1))
+		http_remove_header(htx, &ctx);
+
+	/* Now a the right XXX-Authenticate header */
+	if (!http_add_header(htx, hdr, ist2(b_orig(&trash), b_data(&trash))))
+		goto fail;
+
+	/* Finally forward the reply */
+	htx_to_buf(htx, &res->buf);
+	if (!http_forward_proxy_resp(s, 1))
+		goto fail;
+
+	/* Note: Only eval on the request */
+	s->logs.tv_request = now;
+	req->analysers &= AN_REQ_FLT_END;
+
+	if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
+		_HA_ATOMIC_ADD(&s->sess->fe->fe_counters.intercepted_req, 1);
+
+	if (!(s->flags & SF_ERR_MASK))
+		s->flags |= SF_ERR_LOCAL;
+	if (!(s->flags & SF_FINST_MASK))
+		s->flags |= SF_FINST_R;
+
+	stream_inc_http_err_ctr(s);
+	return ACT_RET_ABRT;
+
+  fail:
+	/* If an error occurred, remove the incomplete HTTP response from the
+	 * buffer */
+	channel_htx_truncate(res, htx);
+	return ACT_RET_ERR;
+}
+
 /* Parse a "auth" action. It may take 2 optional arguments to define a "realm"
  * parameter. It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
  */
@@ -892,8 +972,9 @@
 {
 	int cur_arg;
 
-	rule->action = ACT_HTTP_REQ_AUTH;
+	rule->action = ACT_CUSTOM;
 	rule->flags |= ACT_FLAG_FINAL;
+	rule->action_ptr = http_action_auth;
 	rule->release_ptr = release_http_action;
 
 	cur_arg = *orig_arg;
diff --git a/src/http_ana.c b/src/http_ana.c
index e239f7c..cf9570c 100644
--- a/src/http_ana.c
+++ b/src/http_ana.c
@@ -63,7 +63,6 @@
 
 static int http_handle_expect_hdr(struct stream *s, struct htx *htx, struct http_msg *msg);
 static int http_reply_100_continue(struct stream *s);
-static int http_reply_40x_unauthorized(struct stream *s, const char *auth_realm);
 
 /* This stream analyser waits for a complete HTTP request. It returns 1 if the
  * processing can continue on next analysers, or zero if it either needs more
@@ -2824,7 +2823,6 @@
 	struct htx *htx;
 	struct act_rule *rule;
 	struct http_hdr_ctx ctx;
-	const char *auth_realm;
 	enum rule_result rule_ret = HTTP_RULE_RES_CONT;
 	int act_opts = 0;
 
@@ -2920,25 +2918,6 @@
 				rule_ret = HTTP_RULE_RES_DENY;
 				goto end;
 
-			case ACT_HTTP_REQ_AUTH:
-				/* Auth might be performed on regular http-req rules as well as on stats */
-				auth_realm = rule->arg.http.str.ptr;
-				if (!auth_realm) {
-					if (px->uri_auth && rules == &px->uri_auth->http_req_rules)
-						auth_realm = STATS_DEFAULT_REALM;
-					else
-						auth_realm = px->id;
-				}
-				/* send 401/407 depending on whether we use a proxy or not. We still
-				 * count one error, because normal browsing won't significantly
-				 * increase the counter but brute force attempts will.
-				 */
-				rule_ret = HTTP_RULE_RES_ABRT;
-				if (http_reply_40x_unauthorized(s, auth_realm) == -1)
-					rule_ret = HTTP_RULE_RES_ERROR;
-				stream_inc_http_err_ctr(s);
-				goto end;
-
 			case ACT_HTTP_REDIR:
 				rule_ret = HTTP_RULE_RES_ABRT;
 				if (!http_apply_redirect_rule(rule->arg.redir, s, txn))
@@ -4902,71 +4881,6 @@
 }
 
 
-/* Send a 401-Unauthorized or 407-Unauthorized response to the client, depending
- * ont whether we use a proxy or not. It returns 0 on success and -1 on
- * error. The response channel is updated accordingly.
- */
-static int http_reply_40x_unauthorized(struct stream *s, const char *auth_realm)
-{
-	struct channel *res = &s->res;
-	struct htx *htx = htx_from_buf(&res->buf);
-	struct http_reply *reply;
-	struct http_hdr_ctx ctx;
-	struct ist hdr;
-
-	if (!(s->txn->flags & TX_USE_PX_CONN)) {
-		s->txn->status = 401;
-		hdr = ist("WWW-Authenticate");
-	}
-	else {
-		s->txn->status = 407;
-		hdr = ist("Proxy-Authenticate");
-	}
-	reply = http_error_message(s);
-	channel_htx_truncate(res, htx);
-
-	if (chunk_printf(&trash, "Basic realm=\"%s\"", auth_realm) == -1)
-		goto fail;
-
-	/* Write the generic 40x message */
-	if (http_reply_to_htx(s, htx, reply) == -1)
-		goto fail;
-
-	/* Remove all existing occurrences of the XXX-Authenticate header */
-	ctx.blk = NULL;
-	while (http_find_header(htx, hdr, &ctx, 1))
-		http_remove_header(htx, &ctx);
-
-	/* Now a the right XXX-Authenticate header */
-	if (!http_add_header(htx, hdr, ist2(b_orig(&trash), b_data(&trash))))
-		goto fail;
-
-	/* Finally forward the reply */
-	htx_to_buf(htx, &res->buf);
-	if (!http_forward_proxy_resp(s, 1))
-		goto fail;
-
-	/* Note: Only eval on the request */
-	s->logs.tv_request = now;
-	s->req.analysers &= AN_REQ_FLT_END;
-
-	if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
-		_HA_ATOMIC_ADD(&s->sess->fe->fe_counters.intercepted_req, 1);
-
-	if (!(s->flags & SF_ERR_MASK))
-		s->flags |= SF_ERR_LOCAL;
-	if (!(s->flags & SF_FINST_MASK))
-		s->flags |= SF_FINST_R;
-
-	return 0;
-
-  fail:
-	/* If an error occurred, remove the incomplete HTTP response from the
-	 * buffer */
-	channel_htx_truncate(res, htx);
-	return -1;
-}
-
 /*
  * Capture headers from message <htx> according to header list <cap_hdr>, and
  * fill the <cap> pointers appropriately.