How to get the Host or :authority header in Cro when using HTTP/2
Asked Answered
S

1

8

When using Cro with HTTP1.1 I can access the requested Host via both the host method request.uri.host in Cro::Uri as well as the Host or :authority header sent by the browser via the request.header method in Cro::HTTP::Request.

However, when I use HTTP/2, none of these work. The Uri object only contains the schema and the path.

I'm using an official certificate with a wildcard for subdomains and running this locally by adding these subdomains to my hosts file. Chrome DevTools says it has sent the :authority request header under HTTP/2 and Firefox Developer Tools says it has sent the Host request header under HTTP/2. However if I write the headers to a log like below, I see several headers, but not the Host or :authority header.

sub routes() is export {
  route {
    get -> {
      my $log = "/data/myapp/logs/cro.log";
      my $fh = open $log, :w;
      my $host = request.uri.host;
      $fh.say( "Host with host method: " ~ $host );
      $host = request.header('Host');
      $fh.say( "Host: " ~ $host );
      $host = request.header(':authority');
      $fh.say(":authority: " ~ $host );
      $fh.say( "Request headers:" );
      for request.headers {
        $fh.say( "{.name}: {.value}" );
      }
      $fh.close;
      content 'text/html', "<h1> MyApp </h1><p>Running";
    }
  }
}

I'm aware that HTTP/2 uses Server Name Indication and that the host name is sent as part of the TLS negotiation. On the other hand this is also part of the Cro modules (Cro::TLS) and the headers are sent by the browser nonetheless.

So how to get the host under HTTP/2?

Sporophyll answered 8/6, 2020 at 1:18 Comment(0)
M
8

This appears to be a plain bug (unrelated to ones named by Raiph).

I wrote a patch and sent a PR (https://github.com/croservices/cro-http/pull/104), with it merged you can update your Cro::HTTP distribution and both ways you specified (request.uri construction or asking for header('Host')) will work.

Microphotograph answered 10/6, 2020 at 18:47 Comment(4)
Hi @Takao. It's great to see Cro steadily mature as it passes thru the beta 0.8... series on its way to an eventual 1.0 (in a year or two at a guess). I'm curious what debugging approach you took (insert some say statements?) and if you essentially guessed the problem because you know the relevant protocols and the Cro source code? Is there a good single link that gives an overview of debugging Cro issues in general, and http ones in particular? (And if not, any quick comments you might have would be great.)Endo
My way was: 1)run http2.t test with note $request.uri added to the / route block with both HTTP versions; 2)It differs. Run with CRO_TRACE=1 as env var; 3)In CRO_TRACE output the request has the header, but when it is parsed by the server, not anymore; 4)Go to part of the HTTP/2 parser which sets headers; 5)There are 5 pseudo-headers in HTTP/2, but we only handled 3 of them; 6)Add a missing one; 7)Fixed, add a test, PR. There is no debugging manual, but setting CRO_TRACE and running helps a lot to understand what module has a problem and go there.Microphotograph
Cro is very modular and it helps debugging, but HTTP by itself is tricky, so the code in some places is hard to get. There are some concurrency problems known, as well as related to error reporting in various cases. But when it is about protocol data processing parts (like this one), those bugs are usually good to debug.Microphotograph
@Takoa Thank you diagnosing and fixing. More on githubSporophyll

© 2022 - 2024 — McMap. All rights reserved.