From 34167407fa2c912c8d3f701503a54443f7439e06 Mon Sep 17 00:00:00 2001 From: lijunlong Date: Thu, 19 Sep 2024 09:36:56 +0800 Subject: [PATCH] feature: add ngx.resp.set_status(status, reason). --- src/ngx_http_lua_misc.c | 32 +++++++++++++++++++++++- t/015-status.t | 54 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_misc.c b/src/ngx_http_lua_misc.c index 4e93f68f1e..2fed53f7ad 100644 --- a/src/ngx_http_lua_misc.c +++ b/src/ngx_http_lua_misc.c @@ -64,8 +64,11 @@ ngx_http_lua_ffi_get_resp_status(ngx_http_request_t *r) int -ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int status) +ngx_http_lua_ffi_set_resp_status_and_reason(ngx_http_request_t *r, int status, + const char *reason, size_t reason_len) { + u_char *buf; + if (r->connection->fd == (ngx_socket_t) -1) { return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } @@ -77,6 +80,14 @@ ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int status) return NGX_DECLINED; } + /* per RFC-7230 sec 3.1.2, the status line must be 3 digits, it also makes + * buffer size calculation easier */ + if (status < 100 || status > 999) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid HTTP status code %d", status); + return NGX_DECLINED; + } + r->headers_out.status = status; if (r->err_status) { @@ -91,6 +102,18 @@ ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int status) ngx_str_set(&r->headers_out.status_line, "101 Switching Protocols"); + } else if (reason != NULL && reason_len > 0) { + reason_len += 5; /* "ddd \0" */ + buf = ngx_palloc(r->pool, reason_len); + if (buf == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no memory"); + return NGX_DECLINED; + } + + ngx_snprintf(buf, reason_len, "%d %s", status, reason); + r->headers_out.status_line.len = reason_len; + r->headers_out.status_line.data = buf; + } else { r->headers_out.status_line.len = 0; } @@ -99,6 +122,13 @@ ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int status) } +int +ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int status) +{ + return ngx_http_lua_ffi_set_resp_status_and_reason(r, status, NULL, 0); +} + + int ngx_http_lua_ffi_req_is_internal(ngx_http_request_t *r) { diff --git a/t/015-status.t b/t/015-status.t index aa816c08d6..c768aebcea 100644 --- a/t/015-status.t +++ b/t/015-status.t @@ -9,7 +9,7 @@ log_level('warn'); #repeat_each(120); repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 9); +plan tests => repeat_each() * (blocks() * 2 + 10); #no_diff(); #no_long_string(); @@ -293,3 +293,55 @@ ngx.status: 654 --- no_error_log [error] --- error_code: 654 + + + +=== TEST 17: set status and reason +--- config +location = /upstream { + content_by_lua_block { + local resp = require "ngx.resp" + resp.set_status(500, "user defined reason") + ngx.say("set_status_and_reason") + } +} + +location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + local port = ngx.var.server_port + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local req = "GET /upstream HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + local found = false + while true do + local line, err, part = sock:receive() + if line then + if ngx.re.find(line, "HTTP/1.1 500 user defined reason") then + ngx.say("match") + end + else + break + end + end + + sock:close() + } +} +--- request +GET /t +--- response_body +match +--- no_error_log +[error]