Skip to content
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

Invalid or incomplete multibyte or wide character #225

Open
les-citrons opened this issue Aug 7, 2024 · 6 comments
Open

Invalid or incomplete multibyte or wide character #225

les-citrons opened this issue Aug 7, 2024 · 6 comments

Comments

@les-citrons
Copy link

les-citrons commented Aug 7, 2024

if you connect to a lua-http server and send it unix newlines (which I'm aware is invalid), it will throw with a somewhat cryptic error, rather than returning an error value or tolerating it.

reproduction:

local http_server = require "http.server"

local server = assert(http_server.listen {
	host = "127.0.0.1",
	port = 8080,
	onstream = function(server, stream)
		local headers = stream:get_headers()
		if headers then
			stream:write_body_from_string("hello, world!")
		end
	end,
})
assert(server:loop())
printf 'GET / HTTP/1.1\n\n' | nc localhost 8080
lua: repro.lua:13: /usr/local/share/lua/5.4/http/server.lua:182: get_next_incoming_stream: fill: Invalid or incomplete multibyte or wide character
stack traceback:
	[C]: in function 'assert'
	repro.lua:13: in main chunk
	[C]: in ?
@daurnimator
Copy link
Owner

Invalid or incomplete multibyte or wide character

This is your operating system's standard error message when a function returns EILSEQ. Probably from

self.socket:seterror("r", ce.EILSEQ)

lua-http generally doesn't return any error messages for such calls, only errno values (see https://en.wikipedia.org/wiki/Errno.h, EILSEQ seemed the most appropriate to me for the scenario of expecting one byte sequence but receiving another.

@les-citrons
Copy link
Author

sure, I suppose \r\n is a "multibyte sequence" strictly speaking, but the error made me thought I was sending invalid UTF-8 somehow or something. maybe EPROTO would be more appropriate. but I don't feel particularly strongly about that. this isn't the actual bug.

it does return an errno as expected. but then somewhere along the line after I return from onstream, it throws an error.

onstream = function(server, stream)
	local headers, err = stream:get_headers()
	if headers then
		stream:write_body_from_string("hello, world!")
	else
		print("oh no, an error occurred. allow me to handle it properly.")
		print("I surely don't need to crash.")
	end
end
oh no, an error occurred. allow me to handle it properly.
I surely don't need to crash.
lua: repro.lua:16: /usr/local/share/lua/5.4/http/server.lua:182: get_next_incoming_stream: fill: Invalid or incomplete multibyte or wide character
stack traceback:
	[C]: in function 'assert'
	repro.lua:16: in main chunk
	[C]: in ?

@daurnimator
Copy link
Owner

daurnimator commented Aug 7, 2024

but then somewhere along the line after I return from onstream, it throws an error.

Add an onerror: https://daurnimator.github.io/lua-http/0.4/#http.server:onerror

@@ -1,14 +1,17 @@
 local http_server = require "http.server"
 
 local server = assert(http_server.listen {
        host = "127.0.0.1",
        port = 8080,
        onstream = function(server, stream)
                local headers = stream:get_headers()
                if headers then
                        stream:write_body_from_string("hello, world!")
                end
        end,
+       onerror = function(server, context, op, err, errno)
+               io.stderr:write(string.format("ERROR! [%s:%d]: %s\n", op, errno, err))
+       end,
 })
 assert(server:loop())

@les-citrons
Copy link
Author

while I appreciate that this does technically solve the problem, I intentionally do not use this feature because I think it is an antipattern. there's a difference between illegal characters in an HTTP request and dividing by zero. it's like on error resume next or setting a handler for SIGSEGV, though admittedly a bit less problematic. I want the program to stop when it faults, but not when it is in a situation that is expected to arise in the use of the program.

I was under the impression that I could handle error conditions in this library by checking the return values and that it would not raise errors in the case of e.g. invalid input.

@daurnimator
Copy link
Owner

daurnimator commented Aug 8, 2024

That's what the context argument in onerror is for: in the case of this error, it's a connection level error, so the context is the connection object.
You get to decide what you consider fatal vs ignorable.
Anything that is fatal to the whole sever is returned as an error from :loop()

If you look at the examples you'll see that onerror often just logs the error and continues:

onerror = function(myserver, context, op, err, errno) -- luacheck: ignore 212
local msg = op .. " on " .. tostring(context) .. " failed"
if err then
msg = msg .. ": " .. tostring(err)
end
assert(io.stderr:write(msg, "\n"))
)

@les-citrons
Copy link
Author

les-citrons commented Aug 8, 2024

ok, I see. so, how do I distinguish I/O errors from normal lua errors with the context argument?

edit:

If you look at the examples you'll see that onerror often just logs the error and continues:

this is what I'd like to avoid doing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants