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

request host, port, and scheme all missing when running localhost #83

Open
alanvoss opened this issue May 1, 2020 · 8 comments
Open

Comments

@alanvoss
Copy link

alanvoss commented May 1, 2020

when implementing my handle function on localhost, I was hoping to be able to utilize scheme, host, and port. I keep getting undefined. I admittedly am not super slick with erlang, but the rest of the application works correctly (when getting raw_path, for example, everything is as expected).

%% @doc Return the `scheme'.
scheme(#req{scheme = Scheme}) -> Scheme.
%% @doc Return the `host'.
host(#req{host = Host}) -> Host.
%% @doc Return the `port'.
port(#req{port = Port}) -> Port.

All are undefined when this runs inside my server (though method properly returns).

 handle(Req, [Secrets, VendorConfigs, AvroEncoders]) ->
+    io:fwrite("~1p is the method~n",  [Req#req.method]),
+    io:fwrite("~1p is the host~n",    [Req#req.host]),
+    io:fwrite("~1p is the scheme~n",  [Req#req.scheme]),
+    io:fwrite("~1p is the port~n",    [Req#req.port]),

result:

'POST' is the method
undefined is the host
undefined is the scheme
undefined is the port

calling using curl:

curl -H -v http://localhost:3000/v2/my/path -d '{"data":"1113"}'

System specs:

MacOS Catalina, 10.15.4

Erlang installed using https://github.com/asdf-vm/asdf :

$ cat plugins/erlang/kerl-home/.kerlrc
KERL_CONFIGURE_OPTIONS="--without-javac --with-ssl=/usr/local/opt/openssl@1.1 --enable-wx --with-wx-config=/usr/local/bin/wx-config"
$ erl --version
Erlang/OTP 22 [erts-10.4.4] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe]
$ uname -a
Darwin alanvoss 19.4.0 Darwin Kernel Version 19.4.0: Wed Mar  4 22:28:40 PST 2020; root:xnu-6153.101.6~15/RELEASE_X86_64 x86_64
@tsloughter
Copy link
Member

Thanks, Alan!

I asked him to open this here even though I think the underlying problem is likely in Erlang's packet parser since Elli just does:

parse_path({abs_path, FullPath}) ->
    Parsed = case binary:split(FullPath, [<<"?">>]) of
                 [URL]       -> {FullPath, split_path(URL), []};
                 [URL, Args] -> {FullPath, split_path(URL), split_args(Args)}
             end,
    {ok, {undefined, undefined, undefined}, Parsed};
parse_path({absoluteURI, Scheme, Host, Port, Path}) ->
    setelement(2, parse_path({abs_path, Path}), {Scheme, Host, Port});
parse_path(_) ->
    {error, unsupported_uri}.

So if Erlang packet parser is incorrectly returning {abs_path, Path} instead of absoluteURI this would happen and I think looks to be the only way it would happen.

But will need to verify this and could still be an Elli issue.

@yurrriq
Copy link
Member

yurrriq commented May 11, 2020

Thanks! I can have a look sometime this week.

@yurrriq
Copy link
Member

yurrriq commented May 19, 2020

Wishful thinking, it seems. Will try for this week. Feel free to beat me to it.

@jeffgrunewald
Copy link
Contributor

jeffgrunewald commented Apr 19, 2021

For what it's worth, this appears to be related to the contents of the packet being passed back from the prim_inet module not containing the scheme, host, or port information. I've tested this locally on MacOS running Big Sur as well as in a container (either Ubuntu or Debian) and a POST request to a local endpoint "http://localhost:4000/create" in a test app results in a packet starting with <<"POST /create HTTP/1.1...">> which decodes to:

{ok, {http_request, 'POST', {abs_path, "/create"}, {1, 1}...}}

if i manually modify the same packet to pre-pend the missing info to the path: <<"POST http://localhost:4000/create HTTP/1.1...">> it decodes as I would expect to:

{ok, {http_request, 'POST', {absoluteURI, http, "localhost", 4000, "/create"}, {1, 1}...}}

I tried to trace this back to the source but best I can tell, it appears to be coming from the C message responses generated in the erts/emulator/drivers/common/inet_drv.c but that's above my pay grade.

@tsloughter
Copy link
Member

Oh weird, thanks @jeffgrunewald

I wonder if we are supposed to just infer "localhost" if nothing else is there.

I was going to say the port could be taken from the socket itself but it should probably be the port in the URL and not the port being listened on, since those could technically be different.

@jeffgrunewald
Copy link
Contributor

Where should we get the URL from if it's not able to be parsed from the packet? The host entry in the headers list? Is that something we could reliably count on to be present in a request from any given client?

@jeffgrunewald
Copy link
Contributor

FWIW, it looks like Cowboy attempts to get around this issue by primarily pulling the host from the clients’ host header value and raising an exception if it’s not set, referring to the value being required by RFC7230 5.4: https://github.com/ninenines/cowboy/blob/2a082504996afccf78185182cd168123800bd4f0/src/cowboy_http.erl#L717

@tsloughter
Copy link
Member

Thanks @jeffgrunewald

I opened a PR to have scheme get set. I guess we can go with host header for how to set the port and host.

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

No branches or pull requests

4 participants