]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: http: custom status reason.
authorRobin H. Johnson <robbat2@gentoo.org>
Sun, 1 Jan 2017 21:10:52 +0000 (13:10 -0800)
committerWilly Tarreau <w@1wt.eu>
Fri, 6 Jan 2017 10:57:44 +0000 (11:57 +0100)
The older 'rsprep' directive allows modification of the status reason.

Extend 'http-response set-status' to take an optional string of the new
status reason.

  http-response set-status 418 reason "I'm a coffeepot"

Matching updates in Lua code:
- AppletHTTP.set_status
- HTTP.res_set_status

Signed-off-by: Robin H. Johnson <robbat2@gentoo.org>
doc/configuration.txt
doc/lua-api/index.rst
include/proto/proto_http.h
include/types/action.h
include/types/applet.h
src/hlua.c
src/proto_http.c

index 2a5f7dc062d16cc68e008a364feb2581fb1fb831..132873d7d3cd7176f1aa09dd2381ba1a5e6d8d99 100644 (file)
@@ -4122,7 +4122,7 @@ http-response { allow | deny | add-header <name> <fmt> | set-nice <nice> |
                 set-header <name> <fmt> | del-header <name> |
                 replace-header <name> <regex-match> <replace-fmt> |
                 replace-value <name> <regex-match> <replace-fmt> |
-                set-status <status> |
+                set-status <status> [reason <str>] |
                 set-log-level <level> | set-mark <mark> | set-tos <tos> |
                 add-acl(<file name>) <key fmt> |
                 del-acl(<file name>) <key fmt> |
@@ -4215,13 +4215,16 @@ http-response { allow | deny | add-header <name> <fmt> | set-nice <nice> |
         Cache-Control: max-age=3600, private
 
     - "set-status" replaces the response status code with <status> which must
-      be an integer between 100 and 999. Note that the reason is automatically
-      adapted to the new code.
+      be an integer between 100 and 999. Optionally, a custom reason text can be
+      provided defined by <str>, or the default reason for the specified code
+      will be used as a fallback.
 
       Example:
 
         # return "431 Request Header Fields Too Large"
         http-response set-status 431
+        # return "503 Slow Down", custom reason
+        http-response set-status 503 reason "Slow Down".
 
     - "set-nice" sets the "nice" factor of the current request being processed.
       It only has effect against the other requests being processed at the same
index f930277dfc4af0750e7df0e2f4ba00d09904baca..e04c5b5a75a7b2f7a14c399669cf5e8ca5c3841c 100644 (file)
@@ -1443,13 +1443,15 @@ HTTP class
   :param class_http http: The related http object.
   :param string uri: The new uri.
 
-.. js:function:: HTTP.res_set_status(http, status)
+.. js:function:: HTTP.res_set_status(http, status [, reason])
 
-  Rewrites the response status code with the parameter "code". Note that the
-  reason is automatically adapted to the new code.
+  Rewrites the response status code with the parameter "code".
+
+  If no custom reason is provided, it will be generated from the status.
 
   :param class_http http: The related http object.
   :param integer status: The new response status code.
+  :param string reason: The new response reason (optional).
 
 .. _txn_class:
 
@@ -2080,13 +2082,14 @@ AppletHTTP class
   AppletHTTP.headers["accept"][2] = "*/*, q=0.1"
 ..
 
-.. js:function:: AppletHTTP.set_status(applet, code)
+.. js:function:: AppletHTTP.set_status(applet, code [, reason])
 
   This function sets the HTTP status code for the response. The allowed code are
   from 100 to 599.
 
   :param class_AppletHTTP applet: An :ref:`applethttp_class`
   :param integer code: the status code returned to the client.
+  :param string reason: the status reason returned to the client (optional).
 
 .. js:function:: AppletHTTP.add_header(applet, name, value)
 
index 5ee2e2fa4c39381caa56e60aaa5fbb367e72a807..6c81766aa5c9c7b8e8fca6cdc1140ae28f04cb0c 100644 (file)
@@ -108,7 +108,7 @@ int http_header_match2(const char *hdr, const char *end, const char *name, int l
 int http_remove_header2(struct http_msg *msg, struct hdr_idx *idx, struct hdr_ctx *ctx);
 int http_header_add_tail2(struct http_msg *msg, struct hdr_idx *hdr_idx, const char *text, int len);
 int http_replace_req_line(int action, const char *replace, int len, struct proxy *px, struct stream *s);
-void http_set_status(unsigned int status, struct stream *s);
+void http_set_status(unsigned int status, const char *reason, struct stream *s);
 int http_transform_header_str(struct stream* s, struct http_msg *msg, const char* name,
                               unsigned int name_len, const char *str, struct my_regex *re,
                               int action);
index 5a70db06cf3fda5372c1bfa37414459eace98245..1c1715492d199c44aea520aeef07ba653398003e 100644 (file)
@@ -135,6 +135,7 @@ struct act_rule {
                } cap;
                struct {
                        unsigned int code;     /* HTTP status code */
+                       const char *reason;    /* HTTP status reason */
                } status;
                struct {
                        struct sample_expr *expr;
index 759b905b3f5723ab8f0e3fddf928cc435c0dc4c0..642c7931b98433e0e3a62bdb5d5f62110aff3cac 100644 (file)
@@ -80,6 +80,7 @@ struct appctx {
                        int left_bytes;         /* The max amount of bytes that we can read. */
                        int flags;
                        int status;
+                       const char *reason;
                        struct task *task;
                } hlua_apphttp;                 /* used by the Lua HTTP services */
                struct {
index c343a7b39e696734d0ce27e0219da1db9f79e5c6..48fcf1af02cbfe44c83ec626784122680578ce01 100644 (file)
@@ -3591,6 +3591,7 @@ static int hlua_applet_http_new(lua_State *L, struct appctx *ctx)
        lua_rawseti(L, -2, 0);
        appctx->appctx = ctx;
        appctx->appctx->ctx.hlua_apphttp.status = 200; /* Default status code returned. */
+       appctx->appctx->ctx.hlua_apphttp.reason = NULL; /* Use default reason based on status */
        appctx->htxn.s = s;
        appctx->htxn.p = px;
 
@@ -4119,6 +4120,7 @@ __LJMP static int hlua_applet_http_status(lua_State *L)
 {
        struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1));
        int status = MAY_LJMP(luaL_checkinteger(L, 2));
+       const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
 
        if (status < 100 || status > 599) {
                lua_pushboolean(L, 0);
@@ -4126,6 +4128,7 @@ __LJMP static int hlua_applet_http_status(lua_State *L)
        }
 
        appctx->appctx->ctx.hlua_apphttp.status = status;
+       appctx->appctx->ctx.hlua_apphttp.reason = reason;
        lua_pushboolean(L, 1);
        return 1;
 }
@@ -4178,12 +4181,16 @@ __LJMP static int hlua_applet_http_start_response(lua_State *L)
        int hdr_connection = 0;
        int hdr_contentlength = -1;
        int hdr_chunked = 0;
+       const char *reason = appctx->appctx->ctx.hlua_apphttp.reason;
+
+       if (reason == NULL)
+               reason = get_reason(appctx->appctx->ctx.hlua_apphttp.status);
 
        /* Use the same http version than the request. */
        chunk_appendf(tmp, "HTTP/1.%c %d %s\r\n",
                      appctx->appctx->ctx.hlua_apphttp.flags & APPLET_HTTP11 ? '1' : '0',
                      appctx->appctx->ctx.hlua_apphttp.status,
-                     get_reason(appctx->appctx->ctx.hlua_apphttp.status));
+                     reason);
 
        /* Get the array associated to the field "response" in the object AppletHTTP. */
        lua_pushvalue(L, 0);
@@ -4737,17 +4744,18 @@ static int hlua_http_req_set_uri(lua_State *L)
        return 1;
 }
 
-/* This function set the response code. */
+/* This function set the response code & optionally reason. */
 static int hlua_http_res_set_status(lua_State *L)
 {
        struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
        unsigned int code = MAY_LJMP(luaL_checkinteger(L, 2));
+       const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
 
        /* Check if a valid response is parsed */
        if (unlikely(htxn->s->txn->rsp.msg_state < HTTP_MSG_BODY))
                return 0;
 
-       http_set_status(code, htxn->s);
+       http_set_status(code, reason, htxn->s);
        return 0;
 }
 
index 15070012aa00c1cf2a0216a6d9cf0e5e3ec903d8..f7f7545107a19582fca9a6e89862b3504c9f54ea 100644 (file)
@@ -12454,14 +12454,14 @@ int http_replace_req_line(int action, const char *replace, int len,
 /* This function replace the HTTP status code and the associated message. The
  * variable <status> contains the new status code. This function never fails.
  */
-void http_set_status(unsigned int status, struct stream *s)
+void http_set_status(unsigned int status, const char *reason, struct stream *s)
 {
        struct http_txn *txn = s->txn;
        char *cur_ptr, *cur_end;
        int delta;
        char *res;
        int c_l;
-       const char *msg;
+       const char *msg = reason;
        int msg_len;
 
        chunk_reset(&trash);
@@ -12472,9 +12472,10 @@ void http_set_status(unsigned int status, struct stream *s)
        trash.str[c_l] = ' ';
        trash.len = c_l + 1;
 
-       msg = get_reason(status);
+       /* Do we have a custom reason format string? */
+       if (msg == NULL)
+               msg = get_reason(status);
        msg_len = strlen(msg);
-
        strncpy(&trash.str[trash.len], msg, trash.size - trash.len);
        trash.len += msg_len;
 
@@ -12520,7 +12521,7 @@ enum act_return http_action_set_req_line(struct act_rule *rule, struct proxy *px
 enum act_return action_http_set_status(struct act_rule *rule, struct proxy *px,
                                        struct session *sess, struct stream *s, int flags)
 {
-       http_set_status(rule->arg.status.code, s);
+       http_set_status(rule->arg.status.code, rule->arg.status.reason, s);
        return ACT_RET_CONT;
 }
 
@@ -12596,7 +12597,7 @@ enum act_parse_ret parse_http_set_status(const char **args, int *orig_arg, struc
 
        /* Check if an argument is available */
        if (!*args[*orig_arg]) {
-               memprintf(err, "expects exactly 1 argument <status>");
+               memprintf(err, "expects 1 argument: <status>; or 3 arguments: <status> reason <fmt>");
                return ACT_RET_PRS_ERR;
        }
 
@@ -12608,6 +12609,16 @@ enum act_parse_ret parse_http_set_status(const char **args, int *orig_arg, struc
        }
 
        (*orig_arg)++;
+
+       /* set custom reason string */
+       rule->arg.status.reason = NULL; // If null, we use the default reason for the status code.
+       if (*args[*orig_arg] && strcmp(args[*orig_arg], "reason") == 0 &&
+           (*args[*orig_arg + 1] && strcmp(args[*orig_arg + 1], "if") != 0 && strcmp(args[*orig_arg + 1], "unless") != 0)) {
+               (*orig_arg)++;
+               rule->arg.status.reason = strdup(args[*orig_arg]);
+               (*orig_arg)++;
+       }
+
        return ACT_RET_PRS_OK;
 }