yes | yes | yes | yes
Arguments :
<code> is the HTTP status code. Currently, HAProxy is capable of
- generating codes 200, 400, 403, 408, 500, 502, 503, and 504.
+ generating codes 200, 400, 403, 405, 408, 429, 500, 502, 503, and
+ 504.
<file> designates a file containing the full HTTP response. It is
recommended to follow the common practice of appending ".http" to
HTTP_ERR_200 = 0,
HTTP_ERR_400,
HTTP_ERR_403,
+ HTTP_ERR_405,
HTTP_ERR_408,
+ HTTP_ERR_429,
HTTP_ERR_500,
HTTP_ERR_502,
HTTP_ERR_503,
struct list list;
struct acl_cond *cond; /* acl condition to meet */
unsigned int action; /* HTTP_REQ_* */
+ short deny_status; /* HTTP status to return to user when denying */
int (*action_ptr)(struct http_req_rule *rule, struct proxy *px, struct stream *s); /* ptr to custom action */
union {
struct {
unsigned int flags; /* transaction flags */
enum http_meth_t meth; /* HTTP method */
/* 1 unused byte here */
+ short rule_deny_status; /* HTTP status from rule when denying */
short status; /* HTTP status from the server, negative if from proxy */
char *uri; /* first line if log needed, NULL otherwise */
[HTTP_ERR_200] = 200, /* used by "monitor-uri" */
[HTTP_ERR_400] = 400,
[HTTP_ERR_403] = 403,
+ [HTTP_ERR_405] = 405,
[HTTP_ERR_408] = 408,
+ [HTTP_ERR_429] = 429,
[HTTP_ERR_500] = 500,
[HTTP_ERR_502] = 502,
[HTTP_ERR_503] = 503,
"\r\n"
"<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n",
+ [HTTP_ERR_405] =
+ "HTTP/1.0 405 Method Not Allowed\r\n"
+ "Cache-Control: no-cache\r\n"
+ "Connection: close\r\n"
+ "Content-Type: text/html\r\n"
+ "\r\n"
+ "<html><body><h1>405 Method Not Allowed</h1>\nA request was made of a resource using a request method not supported by that resource\n</body></html>\n",
+
[HTTP_ERR_408] =
"HTTP/1.0 408 Request Time-out\r\n"
"Cache-Control: no-cache\r\n"
"\r\n"
"<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n",
+ [HTTP_ERR_429] =
+ "HTTP/1.0 429 Too Many Requests\r\n"
+ "Cache-Control: no-cache\r\n"
+ "Connection: close\r\n"
+ "Content-Type: text/html\r\n"
+ "\r\n"
+ "<html><body><h1>429 Too Many Requests</h1>\nYou have sent too many requests in a given amount of time.\n</body></html>\n",
+
[HTTP_ERR_500] =
"HTTP/1.0 500 Server Error\r\n"
"Cache-Control: no-cache\r\n"
return HTTP_RULE_RES_STOP;
case HTTP_REQ_ACT_DENY:
+ txn->rule_deny_status = rule->deny_status;
return HTTP_RULE_RES_DENY;
case HTTP_REQ_ACT_TARPIT:
txn->flags |= TX_CLTARPIT;
+ txn->rule_deny_status = rule->deny_status;
return HTTP_RULE_RES_DENY;
case HTTP_REQ_ACT_AUTH:
deny: /* this request was blocked (denied) */
txn->flags |= TX_CLDENY;
- txn->status = 403;
+ txn->status = http_err_codes[txn->rule_deny_status];
s->logs.tv_request = now;
- stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_403));
+ stream_int_retnclose(&s->si[0], http_error_message(s, txn->rule_deny_status));
stream_inc_http_err_ctr(s);
sess->fe->fe_counters.denied_req++;
if (sess->fe != s->be)
goto out_err;
}
+ rule->deny_status = HTTP_ERR_403;
if (!strcmp(args[0], "allow")) {
rule->action = HTTP_REQ_ACT_ALLOW;
cur_arg = 1;
} else if (!strcmp(args[0], "deny") || !strcmp(args[0], "block")) {
+ int code;
+ int hc;
+
rule->action = HTTP_REQ_ACT_DENY;
cur_arg = 1;
+ if (strcmp(args[cur_arg], "deny_status") == 0) {
+ cur_arg++;
+ if (!args[cur_arg]) {
+ Alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : missing status code.\n",
+ file, linenum, proxy_type_str(proxy), proxy->id, args[0]);
+ goto out_err;
+ }
+
+ code = atol(args[cur_arg]);
+ cur_arg++;
+ for (hc = 0; hc < HTTP_ERR_SIZE; hc++) {
+ if (http_err_codes[hc] == code) {
+ rule->deny_status = hc;
+ break;
+ }
+ }
+
+ if (hc >= HTTP_ERR_SIZE) {
+ Warning("parsing [%s:%d] : status code %d not handled, using default code 403.\n",
+ file, linenum, code);
+ }
+ }
} else if (!strcmp(args[0], "tarpit")) {
rule->action = HTTP_REQ_ACT_TARPIT;
cur_arg = 1;