function _RESPONSE.error()

in kong/kong/pdk/response.lua [1129:1215]


  function _RESPONSE.error(status, message, headers)
    if self.worker_events and ngx.get_phase() == "content" then
      self.worker_events.poll()
    end

    check_phase(rewrite_access_header)

    if ngx.headers_sent then
      error("headers have already been sent", 2)
    end

    if type(status) ~= "number" then
      error("code must be a number", 2)

    elseif status < MIN_ERR_STATUS_CODE or status > MAX_STATUS_CODE then
      error(fmt("code must be a number between %u and %u", MIN_ERR_STATUS_CODE,
        MAX_STATUS_CODE), 2)
    end

    if message ~= nil then
      if type(message) == "table" then
        local err
        message, err = cjson.encode(message)
        if err then
          error("could not JSON encode the error message: " .. err, 2)
        end
      end

      if type(message) ~= "string" then
        error("message must be a nil, a string or a table", 2)
      end
    end

    if headers ~= nil and type(headers) ~= "table" then
      error("headers must be a nil or table", 2)
    end

    if headers ~= nil then
      validate_headers(headers)
    else
      headers = {}
    end

    local content_type_header = headers[CONTENT_TYPE_NAME]
    local content_type = content_type_header and content_type_header[1]
      or content_type_header

    if content_type_header == nil then
      if is_grpc_request() then
        content_type = CONTENT_TYPE_GRPC
      else
        content_type_header = ngx.req.get_headers()[ACCEPT_NAME]
        if type(content_type_header) == "table" then
          content_type_header = content_type_header[1]
        end
        content_type = get_response_type(content_type_header)
      end
    end

    headers[CONTENT_TYPE_NAME] = content_type

    local body
    if content_type ~= CONTENT_TYPE_GRPC then
      local actual_message = message or
                             HTTP_MESSAGES["s" .. status] or
                             fmt(HTTP_MESSAGES.default, status)
      body = fmt(utils.get_error_template(content_type), actual_message)
    end

    local ctx = ngx.ctx

    ctx.KONG_EXITED = true

    if ctx.delay_response and not ctx.delayed_response then
      ctx.delayed_response = {
        status_code = status,
        content     = body,
        headers     = headers,
      }

      ctx.delayed_response_callback = flush
      coroutine.yield()

    else
      return send(status, body, headers)
    end
  end