Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions lib/resty/http.lua
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,23 @@ local EXPECTING_BODY = {
}


-- ngx.var is only readable in request-bearing phases. Reading it from a
-- request-less phase (init, init_worker, timer, etc.) raises an error, so we
-- gate any ngx.var access on being in one of these phases.
local NGX_VAR_PHASES = {
set = true,
rewrite = true,
server_rewrite = true,
access = true,
content = true,
preread = true,
header_filter = true,
body_filter = true,
log = true,
balancer = true,

@sriemer sriemer Jun 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Phases reviewed. Those look mostly good. Thanks.
But what about adding "precontent" as seen in t/089-phase.t#L227?
I'd like to drop balancer and preread, because balancer has no full API support and preread is unlikely to be triggered.

}


-- Reimplemented coroutine.wrap, returning "nil, err" if the coroutine cannot
-- be resumed. This protects user code from infinite loops when doing things like
-- repeat
Expand Down Expand Up @@ -739,8 +756,11 @@ function _M.send_request(self, params)
if params.version == 1.0 and not headers["Connection"] then
headers["Connection"] = "Keep-Alive"
end
-- W3C trace context support with NGINX tracer
if not headers["traceparent"] and ngx.var.http_traceparent then
-- W3C trace context support with NGINX tracer.
-- Only read ngx.var in request-bearing phases; doing so during
-- init/init_worker/timer (config preload, background jobs) raises an error.
if NGX_VAR_PHASES[ngx.get_phase()]
and not headers["traceparent"] and ngx.var.http_traceparent then
Comment thread
sriemer marked this conversation as resolved.
headers["traceparent"] = ngx.var.http_traceparent
end

Expand Down
61 changes: 61 additions & 0 deletions t/21-traceparent-header.t
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,46 @@ our $HttpConfig = qq{
}
};

# Same as $HttpConfig, but fires a request from a request-less phase
# (an init_worker timer) where ngx.var is disabled.
our $HttpConfigInitWorker = qq{
lua_package_path "$pwd/lib/?.lua;/usr/local/share/lua/5.1/?.lua;;";
error_log logs/error.log debug;
resolver 8.8.8.8 ipv6=off;

init_by_lua_block {
if $ENV{TEST_COVERAGE} == 1 then
jit.off()
require("luacov.runner").init()
end

require("resty.http").debug(true)
}

init_worker_by_lua_block {
local function make_request(premature)
if premature then
return
end

local http = require "resty.http"
local httpc = http.new()
local res, err = httpc:request_uri("http://www.google.com")
if err then
ngx.log(ngx.ERR, "init_worker request failed: ", err)
end
ngx.log(ngx.INFO, "init_worker request completed")
end

-- cosockets are unavailable directly in init_worker, so defer to a
-- timer. The timer phase is also request-less (ngx.var disabled).
local ok, err = ngx.timer.at(0, make_request)
if not ok then
ngx.log(ngx.ERR, "failed to create timer: ", err)
end
}
};

no_long_string();
#no_diff();

Expand Down Expand Up @@ -90,3 +130,24 @@ GET /lua
traceparent: 00-000000000000000019f4e02c82857913-11488c6e00d1d248-01
--- error_log
traceparent: 00-00000000000000006633c2d00527dd33-1af98f7e6ecd16ff-01


=== TEST 4: A request from a request-less phase does not error reading ngx.var
--- http_config eval: $::HttpConfigInitWorker
--- config
location /lua {
content_by_lua_block {
-- give the init_worker timer time to fire and finish
ngx.sleep(0.5)
ngx.say("ok")
}
}
--- request
GET /lua
--- response_body
ok
--- no_error_log
[error]
API disabled in the context of ngx.timer
--- error_log
init_worker request completed
Loading