kong/kong/pdk/request.lua (306 lines of code) (raw):
--- Client request module.
--
-- This module provides a set of functions to retrieve information about the
-- incoming requests made by clients.
--
-- @module kong.request
local cjson = require "cjson.safe".new()
local multipart = require "multipart"
local phase_checker = require "kong.pdk.private.phases"
local normalize = require("kong.tools.uri").normalize
local ngx = ngx
local var = ngx.var
local req = ngx.req
local sub = string.sub
local find = string.find
local lower = string.lower
local type = type
local error = error
local tonumber = tonumber
local check_phase = phase_checker.check
local check_not_phase = phase_checker.check_not
local PHASES = phase_checker.phases
cjson.decode_array_with_array_mt(true)
local function new(self)
local _REQUEST = {}
local HOST_PORTS = self.configuration.host_ports or {}
local MIN_HEADERS = 1
local MAX_HEADERS_DEFAULT = 100
local MAX_HEADERS = 1000
local MIN_QUERY_ARGS = 1
local MAX_QUERY_ARGS_DEFAULT = 100
local MAX_QUERY_ARGS = 1000
local MIN_POST_ARGS = 1
local MAX_POST_ARGS_DEFAULT = 100
local MAX_POST_ARGS = 1000
local MIN_PORT = 1
local MAX_PORT = 65535
local CONTENT_TYPE = "Content-Type"
local CONTENT_TYPE_POST = "application/x-www-form-urlencoded"
local CONTENT_TYPE_JSON = "application/json"
local CONTENT_TYPE_FORM_DATA = "multipart/form-data"
local X_FORWARDED_PROTO = "X-Forwarded-Proto"
local X_FORWARDED_HOST = "X-Forwarded-Host"
local X_FORWARDED_PORT = "X-Forwarded-Port"
local X_FORWARDED_PATH = "X-Forwarded-Path"
local X_FORWARDED_PREFIX = "X-Forwarded-Prefix"
---
-- Returns the scheme component of the request's URL. The returned value is
-- normalized to lowercase form.
--
-- @function kong.request.get_scheme
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @treturn string A string like `"http"` or `"https"`.
-- @usage
-- -- Given a request to https://example.com:1234/v1/movies
--
-- kong.request.get_scheme() -- "https"
function _REQUEST.get_scheme()
check_phase(PHASES.request)
return var.scheme
end
---
-- Returns the host component of the request's URL, or the value of the
-- "Host" header. The returned value is normalized to lowercase form.
--
-- @function kong.request.get_host
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @treturn string The hostname.
-- @usage
-- -- Given a request to https://example.com:1234/v1/movies
--
-- kong.request.get_host() -- "example.com"
function _REQUEST.get_host()
check_phase(PHASES.request)
return var.host
end
---
-- Returns the port component of the request's URL. The value is returned
-- as a Lua number.
--
-- @function kong.request.get_port
-- @phases certificate, rewrite, access, header_filter, response, body_filter, log, admin_api
-- @treturn number The port.
-- @usage
-- -- Given a request to https://example.com:1234/v1/movies
--
-- kong.request.get_port() -- 1234
function _REQUEST.get_port()
check_not_phase(PHASES.init_worker)
return tonumber(var.server_port)
end
---
-- Returns the scheme component of the request's URL, but also considers
-- `X-Forwarded-Proto` if it comes from a trusted source. The returned
-- value is normalized to lowercase.
--
-- Whether this function considers `X-Forwarded-Proto` or not depends on
-- several Kong configuration parameters:
--
-- * [trusted\_ips](https://docs.konghq.com/gateway/latest/reference/configuration/#trusted_ips)
-- * [real\_ip\_header](https://docs.konghq.com/gateway/latest/reference/configuration/#real_ip_header)
-- * [real\_ip\_recursive](https://docs.konghq.com/gateway/latest/reference/configuration/#real_ip_recursive)
--
-- **Note**: Kong does not offer support for the Forwarded HTTP Extension
-- (RFC 7239) since it is not supported by ngx_http_realip_module.
--
-- @function kong.request.get_forwarded_scheme
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @treturn string The forwarded scheme.
-- @usage
-- kong.request.get_forwarded_scheme() -- "https"
function _REQUEST.get_forwarded_scheme()
check_phase(PHASES.request)
if self.ip.is_trusted(self.client.get_ip()) then
local scheme = _REQUEST.get_header(X_FORWARDED_PROTO)
if scheme then
return lower(scheme)
end
end
return _REQUEST.get_scheme()
end
---
-- Returns the host component of the request's URL or the value of the "host"
-- header. Unlike `kong.request.get_host()`, this function also considers
-- `X-Forwarded-Host` if it comes from a trusted source. The returned value
-- is normalized to lowercase.
--
-- Whether this function considers `X-Forwarded-Host` or not depends on
-- several Kong configuration parameters:
--
-- * [trusted\_ips](https://docs.konghq.com/gateway/latest/reference/configuration/#trusted_ips)
-- * [real\_ip\_header](https://docs.konghq.com/gateway/latest/reference/configuration/#real_ip_header)
-- * [real\_ip\_recursive](https://docs.konghq.com/gateway/latest/reference/configuration/#real_ip_recursive)
--
-- **Note**: Kong does not offer support for the Forwarded HTTP Extension
-- (RFC 7239) since it is not supported by ngx_http_realip_module.
--
-- @function kong.request.get_forwarded_host
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @treturn string The forwarded host.
-- @usage
-- kong.request.get_forwarded_host() -- "example.com"
function _REQUEST.get_forwarded_host()
check_phase(PHASES.request)
if self.ip.is_trusted(self.client.get_ip()) then
local host = _REQUEST.get_header(X_FORWARDED_HOST)
if host then
local s = find(host, "@", 1, true)
if s then
host = sub(host, s + 1)
end
s = find(host, ":", 1, true)
return s and lower(sub(host, 1, s - 1)) or lower(host)
end
end
return _REQUEST.get_host()
end
---
-- Returns the port component of the request's URL, but also considers
-- `X-Forwarded-Host` if it comes from a trusted source. The value
-- is returned as a Lua number.
--
-- Whether this function considers `X-Forwarded-Proto` or not depends on
-- several Kong configuration parameters:
--
-- * [trusted\_ips](https://docs.konghq.com/gateway/latest/reference/configuration/#trusted_ips)
-- * [real\_ip\_header](https://docs.konghq.com/gateway/latest/reference/configuration/#real_ip_header)
-- * [real\_ip\_recursive](https://docs.konghq.com/gateway/latest/reference/configuration/#real_ip_recursive)
--
-- **Note**: Kong does not offer support for the Forwarded HTTP Extension
-- (RFC 7239) since it is not supported by ngx_http_realip_module.
--
-- When running Kong behind the L4 port mapping (or forwarding), you can also
-- configure:
-- * [port\_maps](https://docs.konghq.com/gateway/latest/reference/configuration/#port_maps)
--
-- The `port_maps` configuration parameter enables this function to return the
-- port to which the port Kong is listening to is mapped to (in case they differ).
--
-- @function kong.request.get_forwarded_port
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @treturn number The forwarded port.
-- @usage
-- kong.request.get_forwarded_port() -- 1234
function _REQUEST.get_forwarded_port()
check_phase(PHASES.request)
if self.ip.is_trusted(self.client.get_ip()) then
local port = tonumber(_REQUEST.get_header(X_FORWARDED_PORT))
if port and port >= MIN_PORT and port <= MAX_PORT then
return port
end
local host = _REQUEST.get_header(X_FORWARDED_HOST)
if host then
local s = find(host, "@", 1, true)
if s then
host = sub(host, s + 1)
end
s = find(host, ":", 1, true)
if s then
port = tonumber(sub(host, s + 1))
if port and port >= MIN_PORT and port <= MAX_PORT then
return port
end
end
end
end
local host_port = ngx.ctx.host_port
if host_port then
return host_port
end
local port = _REQUEST.get_port()
return HOST_PORTS[port] or port
end
---
-- Returns the path component of the request's URL, but also considers
-- `X-Forwarded-Path` if it comes from a trusted source. The value
-- is returned as a Lua string.
--
-- Whether this function considers `X-Forwarded-Path` or not depends on
-- several Kong configuration parameters:
--
-- * [trusted\_ips](https://docs.konghq.com/gateway/latest/reference/configuration/#trusted_ips)
-- * [real\_ip\_header](https://docs.konghq.com/gateway/latest/reference/configuration/#real_ip_header)
-- * [real\_ip\_recursive](https://docs.konghq.com/gateway/latest/reference/configuration/#real_ip_recursive)
--
-- **Note**: Kong does not do any normalization on the request path.
--
-- @function kong.request.get_forwarded_path
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @treturn string The forwarded path.
-- @usage
-- kong.request.get_forwarded_path() -- /path
function _REQUEST.get_forwarded_path()
check_phase(PHASES.request)
if self.ip.is_trusted(self.client.get_ip()) then
local path = _REQUEST.get_header(X_FORWARDED_PATH)
if path then
return path
end
end
local path = _REQUEST.get_path()
return path
end
---
-- Returns the prefix path component of the request's URL that Kong stripped
-- before proxying to upstream. It also checks if `X-Forwarded-Prefix` comes
-- from a trusted source, and uses it as-is when given. The value is returned
-- as a Lua string.
--
-- If a trusted `X-Forwarded-Prefix` is not passed, this function must be
-- called after Kong has run its router (`access` phase),
-- as the Kong router may strip the prefix of the request path. That stripped
-- path becomes the return value of this function, unless there is already
-- a trusted `X-Forwarded-Prefix` header in the request.
--
-- Whether this function considers `X-Forwarded-Prefix` or not depends on
-- several Kong configuration parameters:
--
-- * [trusted\_ips](https://docs.konghq.com/gateway/latest/reference/configuration/#trusted_ips)
-- * [real\_ip\_header](https://docs.konghq.com/gateway/latest/reference/configuration/#real_ip_header)
-- * [real\_ip\_recursive](https://docs.konghq.com/gateway/latest/reference/configuration/#real_ip_recursive)
--
-- **Note**: Kong does not do any normalization on the request path prefix.
--
-- @function kong.request.get_forwarded_prefix
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @treturn string|nil The forwarded path prefix or `nil` if the prefix was
-- not stripped.
-- @usage
-- kong.request.get_forwarded_prefix() -- /prefix
function _REQUEST.get_forwarded_prefix()
check_phase(PHASES.request)
local prefix
if self.ip.is_trusted(self.client.get_ip()) then
prefix = _REQUEST.get_header(X_FORWARDED_PREFIX)
if prefix then
return prefix
end
end
return var.upstream_x_forwarded_prefix
end
---
-- Returns the HTTP version used by the client in the request as a Lua
-- number, returning values such as `1`, `1.1`, `2.0`, or `nil` for
-- unrecognized values.
--
-- @function kong.request.get_http_version
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @treturn number|nil The HTTP version as a Lua number.
-- @usage
-- kong.request.get_http_version() -- 1.1
function _REQUEST.get_http_version()
check_phase(PHASES.request)
return req.http_version()
end
---
-- Returns the HTTP method of the request. The value is normalized to
-- uppercase.
--
-- @function kong.request.get_method
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @treturn string The request method.
-- @usage
-- kong.request.get_method() -- "GET"
function _REQUEST.get_method()
check_phase(PHASES.request)
if ngx.ctx.KONG_UNEXPECTED and _REQUEST.get_http_version() < 2 then
local req_line = var.request
local idx = find(req_line, " ", 1, true)
if idx then
return sub(req_line, 1, idx - 1)
end
end
return req.get_method()
end
---
-- Returns the normalized path component of the request's URL. The return
-- value is the same as `kong.request.get_raw_path()` but normalized according
-- to RFC 3986 section 6:
--
-- * Percent-encoded values of unreserved characters are decoded (`%20`
-- becomes ` `).
-- * Percent-encoded values of reserved characters have their hexidecimal
-- value uppercased (`%2f` becomes `%2F`).
-- * Relative path elements (`/.` and `/..`) are dereferenced.
-- * Duplicate slashes are consolidated (`//` becomes `/`).
--
-- @function kong.request.get_path
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @treturn string the path
-- @usage
-- -- Given a request to https://example.com/t/Abc%20123%C3%B8%2f/parent/..//test/./
--
-- kong.request.get_path() -- "/t/Abc 123ø%2F/test/"
function _REQUEST.get_path()
return normalize(_REQUEST.get_raw_path(), true)
end
---
-- Returns the path component of the request's URL. It is not normalized in
-- any way and does not include the query string.
--
-- **NOTE:** Using the raw path to perform string comparision during request
-- handling (such as in routing, ACL/authorization checks, setting rate-limit
-- keys, etc) is widely regarded as insecure, as it can leave plugin code
-- vulnerable to path traversal attacks. Prefer `kong.request.get_path()` for
-- such use cases.
--
-- @function kong.request.get_raw_path
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @treturn string The path.
-- @usage
-- -- Given a request to https://example.com/t/Abc%20123%C3%B8%2f/parent/..//test/./?movie=foo
--
-- kong.request.get_raw_path() -- "/t/Abc%20123%C3%B8%2f/parent/..//test/./"
function _REQUEST.get_raw_path()
check_phase(PHASES.request)
local uri = var.request_uri or ""
local s = find(uri, "?", 2, true)
return s and sub(uri, 1, s - 1) or uri
end
---
-- Returns the path, including the query string if any. No
-- transformations or normalizations are done.
--
-- @function kong.request.get_path_with_query
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @treturn string The path with the query string.
-- @usage
-- -- Given a request to https://example.com:1234/v1/movies?movie=foo
--
-- kong.request.get_path_with_query() -- "/v1/movies?movie=foo"
function _REQUEST.get_path_with_query()
check_phase(PHASES.request)
return var.request_uri or ""
end
---
-- Returns the query component of the request's URL. It is not normalized in
-- any way (not even URL-decoding of special characters) and does not
-- include the leading `?` character.
--
-- @function kong.request.get_raw_query
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @treturn string The query component of the request's URL.
-- @usage
-- -- Given a request to https://example.com/foo?msg=hello%20world&bla=&bar
--
-- kong.request.get_raw_query() -- "msg=hello%20world&bla=&bar"
function _REQUEST.get_raw_query()
check_phase(PHASES.request)
return var.args or ""
end
---
-- Returns the value of the specified argument, obtained from the query
-- arguments of the current request.
--
-- The returned value is either a `string`, a boolean `true` if an
-- argument was not given a value, or `nil` if no argument with `name` was
-- found.
--
-- If an argument with the same name is present multiple times in the
-- query string, this function returns the value of the first occurrence.
--
-- @function kong.request.get_query_arg
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @treturn string|boolean|nil The value of the argument.
-- @usage
-- -- Given a request GET /test?foo=hello%20world&bar=baz&zzz&blo=&bar=bla&bar
--
-- kong.request.get_query_arg("foo") -- "hello world"
-- kong.request.get_query_arg("bar") -- "baz"
-- kong.request.get_query_arg("zzz") -- true
-- kong.request.get_query_arg("blo") -- ""
function _REQUEST.get_query_arg(name)
check_phase(PHASES.request)
if type(name) ~= "string" then
error("query argument name must be a string", 2)
end
local arg_value = _REQUEST.get_query()[name]
if type(arg_value) == "table" then
return arg_value[1]
end
return arg_value
end
---
-- Returns the table of query arguments obtained from the query string. Keys
-- are query argument names. Values are either a string with the argument
-- value, a boolean `true` if an argument was not given a value, or an array
-- if an argument was given in the query string multiple times. Keys and
-- values are unescaped according to URL-encoded escaping rules.
--
-- Note that a query string `?foo&bar` translates to two boolean `true`
-- arguments, and `?foo=&bar=` translates to two string arguments containing
-- empty strings.
--
-- By default, this function returns up to **100** arguments. The optional
-- `max_args` argument can be specified to customize this limit, but must be
-- greater than **1** and not greater than **1000**.
--
-- @function kong.request.get_query
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @tparam[opt] number max_args Sets a limit on the maximum number of parsed
-- arguments.
-- @treturn table A table representation of the query string.
-- @usage
-- -- Given a request GET /test?foo=hello%20world&bar=baz&zzz&blo=&bar=bla&bar
--
-- for k, v in pairs(kong.request.get_query()) do
-- kong.log.inspect(k, v)
-- end
--
-- -- Will print
-- -- "foo" "hello world"
-- -- "bar" {"baz", "bla", true}
-- -- "zzz" true
-- -- "blo" ""
function _REQUEST.get_query(max_args)
check_phase(PHASES.request)
if max_args == nil then
max_args = MAX_QUERY_ARGS_DEFAULT
else
if type(max_args) ~= "number" then
error("max_args must be a number", 2)
end
if max_args < MIN_QUERY_ARGS then
error("max_args must be >= " .. MIN_QUERY_ARGS, 2)
end
if max_args > MAX_QUERY_ARGS then
error("max_args must be <= " .. MAX_QUERY_ARGS, 2)
end
end
if ngx.ctx.KONG_UNEXPECTED and _REQUEST.get_http_version() < 2 then
local req_line = var.request
local qidx = find(req_line, "?", 1, true)
if not qidx then
return {}
end
local eidx = find(req_line, " ", qidx + 1, true)
if not eidx then
-- HTTP 414, req_line is too long
return {}
end
return ngx.decode_args(sub(req_line, qidx + 1, eidx - 1), max_args)
end
return req.get_uri_args(max_args)
end
---
-- Returns the value of the specified request header.
--
-- The returned value is either a `string`, or can be `nil` if a header with
-- `name` was not found in the request. If a header with the same name is
-- present multiple times in the request, this function returns the value
-- of the first occurrence of this header.
--
-- Header names in are case-insensitive and are normalized to lowercase, and
-- dashes (`-`) can be written as underscores (`_`); that is, the header
-- `X-Custom-Header` can also be retrieved as `x_custom_header`.
--
-- @function kong.request.get_header
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @tparam string name the name of the header to be returned
-- @treturn string|nil the value of the header or nil if not present
-- @usage
-- -- Given a request with the following headers:
--
-- -- Host: foo.com
-- -- X-Custom-Header: bla
-- -- X-Another: foo bar
-- -- X-Another: baz
--
-- kong.request.get_header("Host") -- "foo.com"
-- kong.request.get_header("x-custom-header") -- "bla"
-- kong.request.get_header("X-Another") -- "foo bar"
function _REQUEST.get_header(name)
check_phase(PHASES.request)
if type(name) ~= "string" then
error("header name must be a string", 2)
end
-- Do not localize ngx.re.gsub! It will crash because ngx.re is monkey patched.
local header_value = var["http_" .. ngx.re.gsub(name, "-", "_", "jo")]
return header_value
end
---
-- Returns a Lua table holding the request headers. Keys are header names.
-- Values are either a string with the header value, or an array of strings
-- if a header was sent multiple times. Header names in this table are
-- case-insensitive and are normalized to lowercase, and dashes (`-`) can be
-- written as underscores (`_`); that is, the header `X-Custom-Header` can
-- also be retrieved as `x_custom_header`.
--
-- By default, this function returns up to **100** headers. The optional
-- `max_headers` argument can be specified to customize this limit, but must
-- be greater than **1** and not greater than **1000**.
--
-- @function kong.request.get_headers
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @tparam[opt] number max_headers Sets a limit on the maximum number of
-- parsed headers.
-- @treturn table The request headers in table form.
-- @usage
-- -- Given a request with the following headers:
--
-- -- Host: foo.com
-- -- X-Custom-Header: bla
-- -- X-Another: foo bar
-- -- X-Another: baz
-- local headers = kong.request.get_headers()
--
-- headers.host -- "foo.com"
-- headers.x_custom_header -- "bla"
-- headers.x_another[1] -- "foo bar"
-- headers["X-Another"][2] -- "baz"
function _REQUEST.get_headers(max_headers)
check_phase(PHASES.request)
if max_headers == nil then
return req.get_headers(MAX_HEADERS_DEFAULT)
end
if type(max_headers) ~= "number" then
error("max_headers must be a number", 2)
elseif max_headers < MIN_HEADERS then
error("max_headers must be >= " .. MIN_HEADERS, 2)
elseif max_headers > MAX_HEADERS then
error("max_headers must be <= " .. MAX_HEADERS, 2)
end
return req.get_headers(max_headers)
end
local before_content = phase_checker.new(PHASES.rewrite,
PHASES.access,
PHASES.response,
PHASES.error,
PHASES.admin_api)
---
-- Returns the plain request body.
--
-- If the body has no size (empty), this function returns an empty string.
--
-- If the size of the body is greater than the Nginx buffer size (set by
-- `client_body_buffer_size`), this function fails and returns an error
-- message explaining this limitation.
--
-- @function kong.request.get_raw_body
-- @phases rewrite, access, response, admin_api
-- @treturn string The plain request body.
-- @usage
-- -- Given a body with payload "Hello, Earth!":
--
-- kong.request.get_raw_body():gsub("Earth", "Mars") -- "Hello, Mars!"
function _REQUEST.get_raw_body()
check_phase(before_content)
req.read_body()
local body = req.get_body_data()
if not body then
if req.get_body_file() then
return nil, "request body did not fit into client body buffer, consider raising 'client_body_buffer_size'"
else
return ""
end
end
return body
end
---
-- Returns the request data as a key/value table.
-- A high-level convenience function.
--
-- The body is parsed with the most appropriate format:
--
-- * If `mimetype` is specified, it decodes the body with the requested
-- content type (if supported). This takes precedence over any content type
-- present in the request.
--
-- The optional argument `mimetype` can be one of the following strings:
-- * `application/x-www-form-urlencoded`
-- * `application/json`
-- * `multipart/form-data`
--
-- Whether `mimetype` is specified or a request content type is otherwise
-- present in the request, each content type behaves as follows:
--
-- * If the request content type is `application/x-www-form-urlencoded`:
-- * Returns the body as form-encoded.
-- * If the request content type is `multipart/form-data`:
-- * Decodes the body as multipart form data
-- (same as `multipart(kong.request.get_raw_body(),
-- kong.request.get_header("Content-Type")):get_all()` ).
-- * If the request content type is `application/json`:
-- * Decodes the body as JSON
-- (same as `json.decode(kong.request.get_raw_body())`).
-- * JSON types are converted to matching Lua types.
-- * If the request contains none of the above and the `mimetype` argument is
-- not set, returns `nil` and an error message indicating the
-- body could not be parsed.
--
-- The optional argument `max_args` can be used to set a limit on the number
-- of form arguments parsed for `application/x-www-form-urlencoded` payloads.
--
-- The third return value is string containing the mimetype used to parsed
-- the body (as per the `mimetype` argument), allowing the caller to identify
-- what MIME type the body was parsed as.
--
-- @function kong.request.get_body
-- @phases rewrite, access, response, admin_api
-- @tparam[opt] string mimetype The MIME type.
-- @tparam[opt] number max_args Sets a limit on the maximum number of parsed
-- arguments.
-- @treturn table|nil A table representation of the body.
-- @treturn string|nil An error message.
-- @treturn string|nil mimetype The MIME type used.
-- @usage
-- local body, err, mimetype = kong.request.get_body()
-- body.name -- "John Doe"
-- body.age -- "42"
function _REQUEST.get_body(mimetype, max_args)
check_phase(before_content)
local content_type = mimetype or _REQUEST.get_header(CONTENT_TYPE)
if not content_type then
return nil, "missing content type"
end
local content_type_lower = lower(content_type)
do
local s = find(content_type_lower, ";", 1, true)
if s then
content_type_lower = sub(content_type_lower, 1, s - 1)
end
end
if find(content_type_lower, CONTENT_TYPE_POST, 1, true) == 1 then
if max_args ~= nil then
if type(max_args) ~= "number" then
error("max_args must be a number", 2)
elseif max_args < MIN_POST_ARGS then
error("max_args must be >= " .. MIN_POST_ARGS, 2)
elseif max_args > MAX_POST_ARGS then
error("max_args must be <= " .. MAX_POST_ARGS, 2)
end
end
-- TODO: should we also compare content_length to client_body_buffer_size here?
req.read_body()
local pargs, err = req.get_post_args(max_args or MAX_POST_ARGS_DEFAULT)
if not pargs then
return nil, err, CONTENT_TYPE_POST
end
return pargs, nil, CONTENT_TYPE_POST
elseif find(content_type_lower, CONTENT_TYPE_JSON, 1, true) == 1 then
local body, err = _REQUEST.get_raw_body()
if not body then
return nil, err, CONTENT_TYPE_JSON
end
local json = cjson.decode(body)
if type(json) ~= "table" then
return nil, "invalid json body", CONTENT_TYPE_JSON
end
return json, nil, CONTENT_TYPE_JSON
elseif find(content_type_lower, CONTENT_TYPE_FORM_DATA, 1, true) == 1 then
local body, err = _REQUEST.get_raw_body()
if not body then
return nil, err, CONTENT_TYPE_FORM_DATA
end
local parts = multipart(body, content_type)
if not parts then
return nil, "unable to decode multipart body", CONTENT_TYPE_FORM_DATA
end
local margs = parts:get_all_with_arrays()
if not margs then
return nil, "unable to read multipart values", CONTENT_TYPE_FORM_DATA
end
return margs, nil, CONTENT_TYPE_FORM_DATA
else
return nil, "unsupported content type '" .. content_type .. "'", content_type_lower
end
end
---
-- Returns the request start time, in Unix epoch milliseconds.
--
-- @function kong.request.get_start_time
-- @phases rewrite, access, header_filter, response, body_filter, log, admin_api
-- @treturn number The timestamp
-- @usage
-- kong.request.get_start_time() -- 1649960273000
function _REQUEST.get_start_time()
check_phase(PHASES.request)
return ngx.ctx.KONG_PROCESSING_START or (req.start_time() * 1000)
end
return _REQUEST
end
return {
new = new,
}