ysbaddaden/prax.cr

Compilation failing on Crystal version 20.4

jacksonrayhamilton opened this issue · 3 comments

When I try to compile using Crystal 20.4, I get the following error:

$ make
mkdir -p bin
/usr/bin/crystal build /path/to/prax.cr/src/prax.cr -o bin/prax-binary
Error in src/prax.cr:112: instantiating 'Prax:Module#start()'

  Prax.start
       ^~~~~

in src/prax.cr:24: instantiating 'Prax::Server#run(Int32, Int32)'

    server.run(http_port, https_port)
           ^~~

in src/prax/server.cr:23: instantiating 'Array(TCPServer)#each_with_index()'

      servers.each_with_index do |server, index|
              ^~~~~~~~~~~~~~~

in /opt/crystal/src/enumerable.cr:369: instantiating 'each()'

    each do |elem|
    ^~~~

in /opt/crystal/src/indexable.cr:148: instantiating 'each_index()'

    each_index do |i|
    ^~~~~~~~~~

in /opt/crystal/src/indexable.cr:148: instantiating 'each_index()'

    each_index do |i|
    ^~~~~~~~~~

in /opt/crystal/src/enumerable.cr:369: instantiating 'each()'

    each do |elem|
    ^~~~

in src/prax/server.cr:23: instantiating 'Array(TCPServer)#each_with_index()'

      servers.each_with_index do |server, index|
              ^~~~~~~~~~~~~~~

in src/prax/server.cr:25: instantiating 'loop()'

          loop do
          ^~~~

in src/prax/server.cr:25: instantiating 'loop()'

          loop do
          ^~~~

in src/prax/server.cr:26: expanding macro

            spawn handle_client(server.accept, index == 1)
            ^

in macro 'spawn' /opt/crystal/src/concurrent.cr:94, line 11:

   1.   
   2.     ->(
   3.       
   4.         __arg0 : typeof(server.accept),
   5.       
   6.         __arg1 : typeof(index == 1),
   7.       
   8.       
   9.       ) {
  10.       spawn(name: nil) do
> 11.         handle_client(
  12.           
  13.             __arg0,
  14.           
  15.             __arg1,
  16.           
  17.           
  18.         )
  19.       end
  20.     
  21.       }.call(server.accept, index == 1)
  22.     
  23.   

instantiating 'handle_client(TCPSocket+, Bool)'
in src/prax/server.cr:46: instantiating 'Prax::Handler:Class#new(OpenSSL::SSL::Socket::Server, TCPSocket+)'

        Handler.new(ssl_socket, socket)
                ^~~

in src/prax/handler.cr:31: instantiating 'Prax:Module#run_middlewares(Prax::Handler)'

        Prax.run_middlewares(self)
             ^~~~~~~~~~~~~~~

in src/prax/middleware.cr:35: instantiating 'Prax::Middleware#run(Prax::Handler)'

    @@middlewares.run(handler)
                  ^~~

in src/prax/middleware.cr:20: instantiating 'Array(Prax::Middlewares::Base)#each()'

      middlewares.each do |middleware|
                  ^~~~

in /opt/crystal/src/indexable.cr:148: instantiating 'each_index()'

    each_index do |i|
    ^~~~~~~~~~

in /opt/crystal/src/indexable.cr:148: instantiating 'each_index()'

    each_index do |i|
    ^~~~~~~~~~

in src/prax/middleware.cr:20: instantiating 'Array(Prax::Middlewares::Base)#each()'

      middlewares.each do |middleware|
                  ^~~~

in src/prax/middleware.cr:22: instantiating 'Prax::Middlewares::Base+#call(Prax::Handler)'

        middleware.call(handler) { continue = true }
                   ^~~~

in src/prax/middlewares/proxy_middleware.cr:10: instantiating 'Prax::Application#connect()'

        app.connect { |server| proxy(handler, server) }
            ^~~~~~~

in src/prax/middlewares/proxy_middleware.cr:10: instantiating 'Prax::Application#connect()'

        app.connect { |server| proxy(handler, server) }
            ^~~~~~~

in src/prax/middlewares/proxy_middleware.cr:10: instantiating 'proxy(Prax::Handler, TCPSocket)'

        app.connect { |server| proxy(handler, server) }
                               ^~~~~

in src/prax/middlewares/proxy_middleware.cr:20: instantiating 'proxy_headers(Prax::Parser::Request, TCPSocket+, Bool)'

        server << proxy_headers(request, handler.tcp_socket, handler.ssl?).map(&.to_s).join("\r\n")
                  ^~~~~~~~~~~~~

in src/prax/middlewares/proxy_middleware.cr:44: instantiating 'Prax::Parser::Headers#prepend(String, (String | Nil))'

        request.headers.prepend("X-Forwarded-For", socket.remote_address.address)
                        ^~~~~~~

in src/prax/parser/header.cr:49: instantiating 'Prax::Parser::Header:Class#new(String, (String | Nil))'

          push(Header.new(name, value))
                      ^~~

in src/prax/parser/header.cr:8: instance variable '@values' of Prax::Parser::Header must be Array(String)+, not Array(String | Nil)

        @values = [value]
        ^~~~~~~

Makefile:24: recipe for target 'all' failed
make: *** [all] Error 1

Now I'm not very familiar with Crystal. But I checked the documentation and source for IPAddress#address, and it looks like it will always return a String (unless it raises). Any idea how to fix this?

0.20.3 fails in the same way. 0.20.1 can compile it though.

Argh, the issue lies in the sockets refactor I did a few weeks go, which made IPAddress#address a nilable when it shouldn't. I'll fix this in Crystal. In the meantime it may be fixed in Prax by appending .not_nil! or .to_s to .remote_address.address and .local_address.address in src/prax/middlewares/proxy_middleware.cr.

Compilation no longer fails in Crystal 0.20.5.