As it often happens a 5 minute job turned into one that was a lot, lot longer.
@ futzle - thanks for the info. I had a look at overriding the function without much success, so I modified the underlying http.lua file instead. It’s probably possible to perform the override but I haven’t figured it out. If any one else can demonstrate how the two routines below can be overridden please let us know.
I modified http.lua and have now succeeded in logging into my target device. Turns out that the target required the header to be just so: “Content-Type”. http.lua sent it as “content-type”, resulting in a failed login. Clearly the target web server needs a bit of rework, especially as a lower case “content-length” was of no concern to it.
The basic functionality of the modified http.lua is the same (in theory!) as before. However any user supplied headers now maintain the alpha case as set by the user, instead of being forced to lower case by the code.
Here’s an example showing “any case” headers:
local r, c, h = http.request {
url = 'http://some-ip-address/xyz/login.php',
method = 'POST',
headers = {
["CoNtEnT-TyPe"] = "application/x-www-form-urlencoded",
["cONTENT-lengtH"] = string.len(request_body)
},
source = ltn12.source.string(request_body),
sink = ltn12.sink.table(response_body)
}
Only these two functions, as reproduced below, were changed:
metat.__index:sendbody
adjustheaders
[code]function metat.__index:sendbody(headers, source, step)
source = source or ltn12.source.empty()
step = step or ltn12.pump.step
– if we don’t know the size in advance, send chunked and hope for the best
local mode = “http-chunked”
if headers then
for i,v in base.pairs(headers) do
if (string.lower(i) == “content-length”) then mode = “keep-open” end
end
end
return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step))
end
local function adjustheaders(reqt)
– duplicate and also lower case the user’s headers
local newHeaders = {}
local lcHeaders = {}
– a simple request with no body, ie a url only, does not use headers
if reqt.headers then
for i,v in base.pairs(reqt.headers) do
newHeaders[i] = v
lcHeaders[string.lower(i)] = v
end
end
– insert the default headers if they are not being provided by the user
if not lcHeaders[“user-agent”] then newHeaders[“user-agent”] = USERAGENT end
if not lcHeaders[“host”] then newHeaders[“host”] = reqt.host end
if not lcHeaders[“connection”] then newHeaders[“connection”] = “close, TE” end
if not lcHeaders[“te”] then newHeaders[“te”] = “trailers” end
– If “authorization” exists the user has supplied it. The header can be in any
– alpha case the user prefers eg: upper, lower, title case, etc but they must
– supply the header value themselves. We just pass on the header untouched.
if not lcHeaders[“authorization”]
then – header was not supplied by the user. If authorization is specified
– only as part of the supplied url, we complete the header here
if reqt.user and reqt.password then
newHeaders[“authorization”] = "Basic " … (mime.b64(reqt.user … “:” … reqt.password))
end
end
return newHeaders
end[/code]
So it looks like the code can be modified without too much drama and give the user more flexibility at the same time.
EDIT: have attached the modified http.lua file to replace /usr/lib/lua/socket/http.lua