-
-
Notifications
You must be signed in to change notification settings - Fork 82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Get curl command line for a request #80
Open
daurnimator
wants to merge
19
commits into
master
Choose a base branch
from
http.request.tocurl
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
21360f1
http.request: Add :to_curl method that returns the equivalent request…
daurnimator bf2e5ca
http.request: :to_curl: fix command line escaping
daurnimator e66c5f3
http.request: :to_curl better comments
daurnimator 588e655
http/request: Fix NYI. curl gained a flag for setting the expect timeout
daurnimator 5a7ae9d
Merge branch 'master' into http.request.tocurl
daurnimator 60e039d
http.request: Reorder checks in to_curl
daurnimator 40d81ca
http.request: :to_curl: add support for post301 and post302 options
daurnimator f264b44
http.request: :to_curl: Don't return --post303
daurnimator 6b147be
http.request: :to_curl: add support for (maps to --location-trusted)
daurnimator 54c0d9d
http/request: `:to_curl`: if URL contains a curl-globbable character,…
daurnimator 84bb632
http/request: `:to_curl`: Validate path is okay for curl
daurnimator 2926c01
http/request: `:to_curl`: handle `.version` field
daurnimator c4df6a4
http/request: `:to_curl`: Add `-e ;auto` to command lines reflect tha…
daurnimator c0da486
http/request: `:to_curl`: Don't bother setting redirect related optio…
daurnimator 7166c1c
Merge branch 'master' into http.request.tocurl
daurnimator d09cd72
spec/request_spec: Add tests for :to_curl()
daurnimator 9deed93
http/request: Fix incorrect assert for validating referer
daurnimator 7844940
spec/request_spec: Add more tests for :to_curl()
daurnimator 953c1cc
http/request: Have :to_curl() pay attention to proxies
daurnimator File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -167,6 +167,146 @@ function request_methods:to_uri(with_userinfo) | |
return scheme .. "://" .. authority .. path | ||
end | ||
|
||
function request_methods:to_curl() | ||
local cmd = { | ||
"curl"; | ||
} | ||
local n = 1 | ||
|
||
if self.version then | ||
if self.version == 1 then | ||
cmd[n+1] = "-0" | ||
elseif self.version == 1.1 then | ||
cmd[n+1] = "--http1.1" | ||
elseif self.version == 2 then | ||
cmd[n+1] = "--http2" | ||
else | ||
error("invalid version") | ||
end | ||
n = n + 1 | ||
end | ||
|
||
if self.proxy then | ||
if type(self.proxy) ~= "string" then | ||
error("NYI") | ||
end | ||
cmd[n+1] = "--proxy" | ||
cmd[n+2] = self.proxy | ||
n = n + 2 | ||
elseif not self.proxies then | ||
cmd[n+1] = "--noproxy" | ||
cmd[n+2] = "*" | ||
n = n + 2 | ||
elseif self.proxies ~= default_proxies then | ||
assert(getmetatable(self.proxies) == http_proxies.mt, "proxies property should be a http.proxies object") | ||
error("NYI") | ||
end | ||
|
||
if self.expect_100_timeout ~= 1 then | ||
cmd[n+1] = "--expect100-timeout" | ||
cmd[n+2] = string.format("%d", self.expect_100_timeout) | ||
n = n + 2 | ||
end | ||
|
||
if self.follow_redirects then | ||
cmd[n+1] = "--location-trusted" | ||
cmd[n+2] = "-e" | ||
cmd[n+3] = ";auto" | ||
n = n + 3 | ||
|
||
if self.max_redirects ~= 50 then -- curl default is 50 | ||
cmd[n+1] = "--max-redirs" | ||
cmd[n+2] = string.format("%d", self.max_redirects or -1) | ||
n = n + 2 | ||
end | ||
|
||
if self.post301 then | ||
cmd[n+1] = "--post301" | ||
n = n + 1 | ||
end | ||
|
||
if self.post302 then | ||
cmd[n+1] = "--post302" | ||
n = n + 1 | ||
end | ||
end | ||
|
||
if self.tls and self.tls ~= true then | ||
error("NYI") | ||
end | ||
|
||
local scheme = self.headers:get(":scheme") | ||
-- Unlike the ':to_uri' method, curl needs the authority in the URI to be the actual host/port | ||
local authority = http_util.to_authority(self.host, self.port, scheme) | ||
local path = self.headers:get(":path") | ||
assert(path == "" or path:sub(1,1) == "/" or path:sub(1,1) == "?", "invalid path for cURL") | ||
local url = scheme .. "://" .. authority .. path | ||
if url:match("[%[%]%{%}]") then | ||
-- Turn off curl URL globbing | ||
cmd[n+1] = "-g" | ||
n = n + 1 | ||
end | ||
cmd[n+1] = url | ||
n = n + 1 | ||
|
||
for name, value in self.headers:each() do | ||
if name:sub(1,1) == ":" then | ||
if name == ":authority" then | ||
if value ~= authority then | ||
cmd[n+1] = "-H" | ||
cmd[n+2] = "host: " .. value | ||
n = n + 2 | ||
end | ||
elseif name == ":method" then | ||
if value == "HEAD" then | ||
cmd[n+1] = "-I" | ||
n = n + 1 | ||
elseif (value ~= "GET" or self.body ~= nil) and (value ~= "POST" or self.body == nil) then | ||
cmd[n+1] = "-X" | ||
cmd[n+2] = value | ||
n = n + 2 | ||
end | ||
end | ||
elseif name == "user-agent" then | ||
cmd[n+1] = "-A" | ||
cmd[n+2] = value | ||
n = n + 2 | ||
elseif name == "referer" then | ||
cmd[n+1] = "-e" | ||
assert(not value:match(";"), "cannot render referer") | ||
if self.follow_redirects then | ||
cmd[n+2] = value .. ";auto" | ||
else | ||
cmd[n+2] = value | ||
end | ||
n = n + 2 | ||
else | ||
cmd[n+1] = "-H" | ||
cmd[n+2] = name .. ": " .. value | ||
n = n + 2 | ||
end | ||
end | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to tell curl to not send |
||
if self.body then | ||
if type(self.body) == "string" then | ||
cmd[n+1] = "--data-raw" | ||
cmd[n+2] = self.body | ||
n = n + 2 | ||
else | ||
error("NYI") | ||
end | ||
end | ||
|
||
-- escape ready for a command line | ||
for i=1, n do | ||
local arg = cmd[i] | ||
if arg:match("[^%w%_%:%/%@%^%.%-]") then | ||
cmd[i] = "'" .. arg:gsub("'", "'\\''") .. "'" | ||
end | ||
end | ||
return table.concat(cmd, " ", 1, n) | ||
end | ||
|
||
function request_methods:handle_redirect(orig_headers) | ||
local max_redirects = self.max_redirects | ||
if max_redirects <= 0 then | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -157,6 +157,131 @@ describe("http.request module", function() | |
test("https://foo:[email protected]:1234") | ||
assert.has.errors(function() test("https://example.com/path") end) | ||
end) | ||
describe(":to_curl() #curl", function() | ||
it("lua-http defaults", function() | ||
local req = request.new_from_uri("http://example.com/") | ||
req.headers:delete "user-agent" -- take variability out of tests | ||
assert.same("curl --location-trusted -e ';auto' --max-redirs 5 http://example.com/", req:to_curl()) | ||
end) | ||
local req_template = request.new_from_uri("http://example.com/") | ||
req_template.headers:delete "user-agent" -- take variability out of tests | ||
req_template.follow_redirects = false -- closer to curl defaults | ||
req_template.max_redirects = 50 | ||
it("curl defaults", function() | ||
local req = req_template:clone() | ||
assert.same("curl http://example.com/", req:to_curl()) | ||
end) | ||
it("http version 1.0", function() | ||
local req = req_template:clone() | ||
req.version = 1 | ||
assert.same("curl -0 http://example.com/", req:to_curl()) | ||
end) | ||
it("http version 1.1", function() | ||
local req = req_template:clone() | ||
req.version = 1.1 | ||
assert.same("curl --http1.1 http://example.com/", req:to_curl()) | ||
end) | ||
it("http version 2", function() | ||
local req = req_template:clone() | ||
req.version = 2 | ||
assert.same("curl --http2 http://example.com/", req:to_curl()) | ||
end) | ||
it("expect_100_timeout flag", function() | ||
local req = req_template:clone() | ||
req.expect_100_timeout = 2 | ||
assert.same("curl --expect100-timeout 2 http://example.com/", req:to_curl()) | ||
end) | ||
it("post301 flag", function() | ||
local req = req_template:clone() | ||
req.follow_redirects = nil | ||
req.post301 = true | ||
assert.same("curl --location-trusted -e ';auto' --post301 http://example.com/", req:to_curl()) | ||
end) | ||
it("post302 flag", function() | ||
local req = req_template:clone() | ||
req.follow_redirects = nil | ||
req.post302 = true | ||
assert.same("curl --location-trusted -e ';auto' --post302 http://example.com/", req:to_curl()) | ||
end) | ||
it("path component", function() | ||
local req = req_template:clone() | ||
req.headers:upsert(":path", "/[complex]&path{component}") | ||
assert.same("curl -g 'http://example.com/[complex]&path{component}'", req:to_curl()) | ||
end) | ||
it("query component", function() | ||
local req = req_template:clone() | ||
req.headers:upsert(":path", "/path?query") | ||
assert.same("curl 'http://example.com/path?query'", req:to_curl()) | ||
end) | ||
it("scheme change", function() | ||
local req = req_template:clone() | ||
req.headers:upsert(":scheme", "https") | ||
assert.same("curl https://example.com:80/ -H 'host: example.com'", req:to_curl()) | ||
end) | ||
it("scheme and port change", function() | ||
local req = req_template:clone() | ||
req.headers:upsert(":scheme", "https") | ||
req.port = 443 | ||
assert.same("curl https://example.com/", req:to_curl()) | ||
end) | ||
it("port change", function() | ||
local req = req_template:clone() | ||
req.port = 443 | ||
assert.same("curl http://example.com:443/ -H 'host: example.com'", req:to_curl()) | ||
end) | ||
it("host change", function() | ||
local req = req_template:clone() | ||
req.headers:upsert(":authority", "foo.com") | ||
assert.same("curl http://example.com/ -H 'host: foo.com'", req:to_curl()) | ||
end) | ||
it("proxy", function() | ||
local req = req_template:clone() | ||
req.proxy = "http://foo.com" | ||
assert.same("curl --proxy http://foo.com http://example.com/", req:to_curl()) | ||
end) | ||
it("proxies", function() | ||
local req = req_template:clone() | ||
req.proxies = false | ||
assert.same("curl --noproxy '*' http://example.com/", req:to_curl()) | ||
end) | ||
it("head method", function() | ||
local req = req_template:clone() | ||
req.headers:upsert(":method", "HEAD") | ||
assert.same("curl http://example.com/ -I", req:to_curl()) | ||
end) | ||
it("post method with body", function() | ||
local req = req_template:clone() | ||
req.headers:upsert(":method", "POST") | ||
req.body = "foo" | ||
assert.same("curl http://example.com/ --data-raw foo", req:to_curl()) | ||
end) | ||
it("post method without body", function() | ||
local req = req_template:clone() | ||
req.headers:upsert(":method", "POST") | ||
assert.same("curl http://example.com/ -X POST", req:to_curl()) | ||
end) | ||
it("referer header", function() | ||
local req = req_template:clone() | ||
req.headers:upsert("user-agent", "myuseragent") | ||
assert.same("curl http://example.com/ -A myuseragent", req:to_curl()) | ||
end) | ||
it("referer header", function() | ||
local req = req_template:clone() | ||
req.headers:upsert("referer", "foo.com") | ||
assert.same("curl http://example.com/ -e foo.com", req:to_curl()) | ||
end) | ||
it("referer header when follow_redirects is on", function() | ||
local req = req_template:clone() | ||
req.headers:upsert("referer", "foo.com") | ||
req.follow_redirects = nil | ||
assert.same("curl --location-trusted -e ';auto' http://example.com/ -e 'foo.com;auto'", req:to_curl()) | ||
end) | ||
it("custom headers", function() | ||
local req = req_template:clone() | ||
req.headers:append("foo", "bar") | ||
assert.same("curl http://example.com/ -H 'foo: bar'", req:to_curl()) | ||
end) | ||
end) | ||
it(":set_body sets content-length for string arguments", function() | ||
local req = request.new_from_uri("http://example.com") | ||
assert.falsy(req.headers:has("content-length")) | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If user agent not set then need to tell curl not to send one.
-H "User-Agent;"