Giter Site home page Giter Site logo

prax.cr's Introduction

Prax

Rack proxy server for development

This is an (almost) complete rewrite of Prax in Crystal, a Ruby-inspired language that compiles down to LLVM. This version should avoid problems with version managers, since Prax is now a binary application that don't rely on Ruby anymore (except for Rack and rackup).

Please refer to the wiki for more information:

Install

You can download a Debian / Ubuntu package for 64bits kernel on the releases page. For other systems, you'll have to follow the Manual Install Guide.

How it works

  1. resolves *.test and *.localhost domains to 127.0.0.1 and ::1 (localhost);
  2. redirects the :80 and :443 ports to :20559 and :20558;
  3. receives incoming HTTP requests and extracts the hostname (eg: myapp.test);
  4. serves static files directly if they exist;
  5. otherwise spawns a Rack applications (found at ~/.prax/myapp) if any;
  6. and proxies the request to the Rack aplication or a specified port for port forwarding.

Domain Resolver

systemd

If your distribution uses systemd-resolved, just use the .localhost TLD instead of .test —be prepared to fight against systemd if you want to use another TLD, or consider switching to a systemd free Linux.

.test TLD

Prax proposes 2 solutions to resolve .test and .localhost domains:

  • a dnsmasq configuration, either throught NetworkManager or by installing dnsmasq manually (eg. through your Linux distribution package);
  • an obsolete and deprecated NSSwitch extension, only compatible wih glibc and no longer compatible with Google Chrome/Chromium, and certainly more.

nip.io

Prax supports http://nip.io/ domains, so you can use myapp.129.168.0.1.nip.io for example. This is useful when using an external device like a smartphone, tablet or another computer to test your websites on.

Custom TLD

If .test or .localhost domains are not your cup of tea, no problem! Prax will route requests from any TLD to the applications in your ~/.prax directory, as long as the domain resolves to localhost.

For instance, if you wished to visit myapp.dev instead of myapp.test, you could create dnsmasq configuration to resolve .dev domains to localhost, too:

$ sudo tee /etc/dnsmasq.d/dev <<EOF
local=/dev/
address=/dev/127.0.0.1
address=/dev/::1
EOF
$ sudo service dnsmasq restart

Port Redirections

The port redirections are iptables rules, that are installed and removed using an initd script. The script redirects the port :80 and :443 on 127.0.0.1 and for each wlanX and ethX devices found on your machine, to allow incoming traffic, so you can use http://nip.io to test on external devices, as mentioned above.

You can install or remove the redirections with:

$ prax iptables [start|stop|restart|status]

Distribution packages should configure an init service to always install the iptables rules on machine startup or before starting prax (warning: this requires root privileges).

License

Prax is distributed under the CeCILL 2.1 license. Please see LICENSE for details.

HTML templates for rendering errors are from Pow!!, by Sam Stephenson and Basecamp, and are under the MIT license.

The NSSwitch extension originaly come from Hoof, by pyromaniac, and is under the MIT license.

Credits

Prax wouldn't exist without Pow!! by Sam Stephenson and Basecamp. Prax is nothing more but a reimplementation (in another language) with Linux compatibility in mind.

prax.cr's People

Contributors

bradediger avatar dependabot[bot] avatar devlucas avatar graywh avatar halida avatar jacksonrayhamilton avatar kwstannard avatar scope2229 avatar stephenh avatar tijn avatar urkle avatar ysbaddaden avatar zamith avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

prax.cr's Issues

execvp: No such file or directory

I am seeing this error message when I ran "curl http://myapp.dev'

<body>
  <div class="page">
    <h1 class="err">Error starting application</h1>
<!--h2>Your Rack app raised an exception when Pow tried to run it.</h2-->

<section>
  <pre>execvp: No such file or directory (Errno)
0x451cf8: ??? at /opt/crystal/src/process.cr 381:7
0x44f0ba: ??? at /vagrant/src/prax/application/spawner.cr 52:13
0x41b828: ??? at /opt/crystal/src/fiber.cr 114:3
0x0: ??? at ??
</pre>
</section>

Is it possible to use Prax on a public Linux server?

Hello,

Is it possible to use Prax on a Linux VM that is exposed publicly? I am using nginx with an upstream directive pointing to a unix socket. How might someone link a deployed application via Prax, and map the .dev domain in listen and server_name nginx server blocks? Let me know if I'm crazy.

Thanks!

Tara

Cookies still getting combined into one header

I believe prax is still combining cookie headers. However, I'm confused because it looks like this was supposed to be fixed in #32.

Most of my team uses pow, but I'm using prax, and was having trouble authing against our www.<us>.localhost because my csrf_token cookie was not being set.

When accessing our app directly (w/o prax via the production domain), I get back three set-cookie values when I look in chrome's network tab:

set-cookie: locale=en; domain=www.example.com
set-cookie: csrf_token=...uuid...; domain=.example.com; path=/
set-cookie: auth_token=...jwt...; domain=www.example.com; path=/; secure; HttpOnly

However, when using prax, I get back a single set-cookie cookie header:

set-cookie: locale=en; domain=.example.localhost, csrf_token=...uuid...; domain=.example.localhost; path=/, auth_token=...jwt...; domain=.example.localhost; path=/; HttpOnly

I'm using prax 0.8.1:

$ prax --version
Prax 0.8.1-1 (2018-12-08)

And latest chrome, Version 75.0.3770.100 (Official Build) (64-bit)...

It seems like prax shouldn't be doing this, right? Any ideas?

Compilation failing on Crystal version 20.4

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?

provide alternative start / stop commands

If there would be a config file with ip, start and stop commands (plus the already provided port) it would be possible to support other projects as well.

Like docker containers, VMs etc.

I would love to see this feature although I understand that it might add more complexity as well.

A myapp.yml would be nice like:

start_commands:
  - 'cd ~/myapp'
  - 'docker-compose up'
stop_commands:
  - 'docker-compose stop'
ip: '123.45.67'
port: 3002

ip6tables v1.4.14: unknown option "--to-ports"

I am running Wheezy with Kernel version 3.16.0-0.bpo.4-amd64. I got the following message when I tried to install prax.

ip6tables v1.4.14: unknown option "--to-ports" Try 'ip6tables -h' or 'ip6tables --help' for more information. dpkg: error processing prax (--install): subprocess installed post-installation script returned error exit status 2 Errors were encountered while processing: prax vagra

Ruby version managers

Most of the installation problems Prax users are facing are related to Ruby version managers configuration. Usually, Rack applications won't be started by Prax while running rackup or rails server in the application's directory actually succeeds.

Prax seeks to be version-managers agnostic. Managing which Ruby version to use and where gems are installed is their jobs, and Prax shouldn't have to deal with it; not to mention there are lots of them (RVM, rbenv, chruby, ry, ...). The problem is that this puts the burden on the developers, namely Prax users, which ain't no fun at all for them and may event be a show stopper. Bummer.

The actual question is: should Prax merely provide some documentation on the wiki? should a notice be included in the distributed package, and printed on screen after it's installed? or should Prax actually deal with version managers, checking for their presence in their standard installation places, and automatically configure them? maybe not forcefully, but through a CLI command that would configure ~/.praxconfig?

HTTP 1.0 request might return empty response

If I send an HTTP 1.0 request, according to specification, I can expect the server to automatically close the connection at the end unless both the client and server send Connection: keep-alive.

If my server’s response does not include Transfer-Encoding: chunked and it does not have a Content-Length and it does not include Connection: close, then an HTTP 1.0 request will erroneously be blank due to this line:

# TODO: read until EOF / connection close?

How do we fix this? I’ve tried this:

diff --git a/src/prax/middlewares/proxy_middleware.cr b/src/prax/middlewares/proxy_middleware.cr
index 8274ea8..d18fc44 100644
--- a/src/prax/middlewares/proxy_middleware.cr
+++ b/src/prax/middlewares/proxy_middleware.cr
@@ -31,10 +31,8 @@ module Prax
           stream_chunked_response(server, client)
         elsif (len = response.content_length) > 0
           copy_stream(server, client, len)
-        elsif response.header("Connection") == "close"
-          copy_stream(server, client)
         else
-          # TODO: read until EOF / connection close?
+          copy_stream(server, client)
         end
       end

However, for the very first request I send to a Rack server, it hangs forever even after the server starts. The second request goes through. (???) Any ideas?

How to run in production mode?

I tried to run by setting RACK_ENV="production" in .env but I get the following error:

bundler: failed to load command: rackup (/home/musaffa/.rbenv/versions/2.3.1/bin/rackup)
ActiveRecord::AdapterNotSpecified: '"production"' database is not configured. Available: ["default", "development", "test", "load_test", "production"]

But my production database is already specified and it works well with:

RACK_ENV=production bundle exec rackup -p 3000

Thread Pool vs Evented IO

Instead of firing a pthread on each request, Prax should have a pool of thread, or rely on an event loop.

RPM packages

It would be nice to have RPM packages too, just like we have DEB packages for Debian/Ubuntu.

Ideally we would have a Fedora (or CentOS) Vagrant box (with provisioning) and a rpm make target, so it's easy to create new packages on each release.

Tests are failing and test runner hangs.

My Ruby version is 2.4.1. When I run make test, a bunch of tests fail, and the test runner hangs.

~/projects/prax.cr (master) λ make test
mkdir -p bin
/usr/bin/crystal build /home/jackson/projects/prax.cr/src/prax.cr -o bin/prax-binary
bundle exec rake test
/home/jackson/.rbenv/versions/2.4.1/bin/ruby -I"lib:test" -I"/home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/rake-10.4.2/lib" "/home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/rake-10.4.2/lib/rake/rake_test_loader.rb" "test/failures_test.rb" "test/keepalive_test.rb" "test/port_forwarding_test.rb" "test/praxrc_test.rb" "test/proxy_test.rb" "test/public_file_test.rb" 
Run options: --seed 16225

# Running:

EES.SEEE.E..S....E

Fabulous run in 28.314632s, 0.6357 runs/s, 0.8123 assertions/s.

  1) Error:
PraxrcTest#test_praxrc_loaded:
Timeout::Error: execution expired
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:176:in `wait_readable'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:176:in `rbuf_fill'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:154:in `readuntil'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:164:in `readline'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http/response.rb:40:in `read_status_line'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http/response.rb:29:in `read_new'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1446:in `block in transport_request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1443:in `catch'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1443:in `transport_request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1416:in `request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1317:in `request_get'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:487:in `block in get_response'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:877:in `start'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:608:in `start'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:485:in `get_response'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:462:in `get'
    /home/jackson/projects/prax.cr/test/praxrc_test.rb:5:in `test_praxrc_loaded'


  2) Error:
ProxyTest#test_proxies_to_rack_applications:
Timeout::Error: execution expired
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:176:in `wait_readable'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:176:in `rbuf_fill'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:154:in `readuntil'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:164:in `readline'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http/response.rb:40:in `read_status_line'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http/response.rb:29:in `read_new'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1446:in `block in transport_request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1443:in `catch'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1443:in `transport_request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1416:in `request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1317:in `request_get'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:487:in `block in get_response'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:877:in `start'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:608:in `start'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:485:in `get_response'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:462:in `get'
    /home/jackson/projects/prax.cr/test/proxy_test.rb:6:in `test_proxies_to_rack_applications'


  3) Error:
ProxyTest#test_alters_request_headers_and_sets_proxy_headers:
Timeout::Error: execution expired
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:176:in `wait_readable'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:176:in `rbuf_fill'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:154:in `readuntil'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:164:in `readline'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http/response.rb:40:in `read_status_line'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http/response.rb:29:in `read_new'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1446:in `block in transport_request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1443:in `catch'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1443:in `transport_request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1416:in `request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1317:in `request_get'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:487:in `block in get_response'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:877:in `start'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:608:in `start'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:485:in `get_response'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:462:in `get'
    /home/jackson/projects/prax.cr/test/proxy_test.rb:39:in `test_alters_request_headers_and_sets_proxy_headers'


  4) Error:
ProxyTest#test_supports_xip_io:
Timeout::Error: execution expired
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:176:in `wait_readable'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:176:in `rbuf_fill'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:154:in `readuntil'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:164:in `readline'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http/response.rb:40:in `read_status_line'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http/response.rb:29:in `read_new'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1446:in `block in transport_request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1443:in `catch'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1443:in `transport_request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1416:in `request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1317:in `request_get'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:487:in `block in get_response'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:877:in `start'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:608:in `start'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:485:in `get_response'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:462:in `get'
    /home/jackson/projects/prax.cr/test/proxy_test.rb:22:in `test_supports_xip_io'


  5) Error:
ProxyTest#test_augments_proxy_headers:
Timeout::Error: execution expired
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:176:in `wait_readable'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:176:in `rbuf_fill'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:154:in `readuntil'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:164:in `readline'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http/response.rb:40:in `read_status_line'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http/response.rb:29:in `read_new'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1446:in `block in transport_request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1443:in `catch'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1443:in `transport_request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1416:in `request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1165:in `get'
    /home/jackson/projects/prax.cr/test/proxy_test.rb:53:in `block in test_augments_proxy_headers'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:877:in `start'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:608:in `start'
    /home/jackson/projects/prax.cr/test/proxy_test.rb:52:in `test_augments_proxy_headers'


  6) Error:
ProxyTest#test_returns_multiple_set_cookie_headers:
Timeout::Error: execution expired
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:176:in `wait_readable'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:176:in `rbuf_fill'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:154:in `readuntil'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/protocol.rb:164:in `readline'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http/response.rb:40:in `read_status_line'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http/response.rb:29:in `read_new'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1446:in `block in transport_request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1443:in `catch'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1443:in `transport_request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1416:in `request'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:1317:in `request_get'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:487:in `block in get_response'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:877:in `start'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:608:in `start'
    /home/jackson/.rbenv/versions/2.4.1/lib/ruby/2.4.0/net/http.rb:485:in `get_response'
    /home/jackson/projects/prax.cr/test/proxy_test.rb:30:in `test_returns_multiple_set_cookie_headers'


  7) Error:
FailuresTest#test_host_header_is_missing_but_found_in_uri:
Timeout::Error: execution expired
    /home/jackson/projects/prax.cr/test/failures_test.rb:27:in `gets'
    /home/jackson/projects/prax.cr/test/failures_test.rb:27:in `block in test_host_header_is_missing_but_found_in_uri'
    /home/jackson/projects/prax.cr/test/failures_test.rb:23:in `open'
    /home/jackson/projects/prax.cr/test/failures_test.rb:23:in `test_host_header_is_missing_but_found_in_uri'

18 runs, 23 assertions, 0 failures, 7 errors, 3 skips

You have skipped tests. Run with --verbose for details.
^Crake aborted!
Interrupt: 
/home/jackson/.rbenv/versions/2.4.1/bin/bundle:22:in `load'
/home/jackson/.rbenv/versions/2.4.1/bin/bundle:22:in `<main>'
Tasks: TOP => test
(See full trace by running task with --trace)
/home/jackson/projects/prax.cr/test/test_helper.rb:18:in `wait': Interrupt
	from /home/jackson/projects/prax.cr/test/test_helper.rb:18:in `block in <top (required)>'
	from /home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/minitest-5.5.1/lib/minitest.rb:52:in `reverse_each'
	from /home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/minitest-5.5.1/lib/minitest.rb:52:in `block (2 levels) in autorun'
Makefile:78: recipe for target 'test' failed
make: *** [test] Error 1

But if I go back a few commits, they are succeeding:

~/projects/prax.cr (master) λ git checkout d88141a
~/projects/prax.cr ((v0.7.0)) λ make test
mkdir -p bin
/usr/bin/crystal build /home/jackson/projects/prax.cr/src/prax.cr -o bin/prax-binary
bundle exec rake test
/home/jackson/.rbenv/versions/2.4.1/bin/ruby -w -I"lib:test" -I"/home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib" "/home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/rake-12.0.0/lib/rake/rake_test_loader.rb" "test/failures_test.rb" "test/keepalive_test.rb" "test/port_forwarding_test.rb" "test/praxrc_test.rb" "test/proxy_test.rb" "test/public_file_test.rb" 
Run options: --seed 1715

# Running:

....S..S..S.......

Fabulous run in 2.511875s, 7.1660 runs/s, 17.9149 assertions/s.

18 runs, 45 assertions, 0 failures, 0 errors, 3 skips

You have skipped tests. Run with --verbose for details.

Maybe 4d0929e has broken the tests for newer Rubies?

Memory Leak?

Prax memory usage seem to grow up quickly on each and every query, and memory seems to never be claimed back. There must be some dead references that prevent objects from being collected by libgc?

  • VIRT climbs up very quickly
  • RES grows up slowly
  • SHR is kept small

File Descriptor Leak (can't identify protocol)

Prax is leaking File Descriptors on each request. Here is the result of an lsof after a few requests:

COMMAND     PID   USER   FD   TYPE             DEVICE SIZE/OFF    NODE NAME
prax-bina 27652 julien  cwd    DIR               0,36     4096 8655908 /home/julien/work/github/prax.cr
prax-bina 27652 julien  rtd    DIR                8,9     4096       2 /
prax-bina 27652 julien  txt    REG               0,36  1602014 8784921 /home/julien/work/github/prax.cr/bin/prax-binary
prax-bina 27652 julien  mem    REG                8,9  1840928 2101998 /lib/x86_64-linux-gnu/libc-2.19.so
prax-bina 27652 julien  mem    REG                8,9    90080 2101109 /lib/x86_64-linux-gnu/libgcc_s.so.1
prax-bina 27652 julien  mem    REG                8,9    14664 2101987 /lib/x86_64-linux-gnu/libdl-2.19.so
prax-bina 27652 julien  mem    REG                8,9   141574 2101999 /lib/x86_64-linux-gnu/libpthread-2.19.so
prax-bina 27652 julien  mem    REG                8,9    31792 2102001 /lib/x86_64-linux-gnu/librt-2.19.so
prax-bina 27652 julien  mem    REG                8,9  1930528 2097469 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
prax-bina 27652 julien  mem    REG                8,9   387256 2097470 /lib/x86_64-linux-gnu/libssl.so.1.0.0
prax-bina 27652 julien  mem    REG                8,9   149120 2101995 /lib/x86_64-linux-gnu/ld-2.19.so
prax-bina 27652 julien    0u   CHR             136,12      0t0      15 /dev/pts/12
prax-bina 27652 julien    1u   CHR             136,12      0t0      15 /dev/pts/12
prax-bina 27652 julien    2u   CHR             136,12      0t0      15 /dev/pts/12
prax-bina 27652 julien    3u  0000                0,9        0    7345 anon_inode
prax-bina 27652 julien    4u  unix 0x0000000000000000      0t0 1403824 socket
prax-bina 27652 julien    5u  unix 0x0000000000000000      0t0 1403825 socket
prax-bina 27652 julien    6r  FIFO                0,8      0t0 1403826 pipe
prax-bina 27652 julien    7w  FIFO                0,8      0t0 1403826 pipe
prax-bina 27652 julien    8u  sock                0,7      0t0 1403827 can't identify protocol
prax-bina 27652 julien    9u  IPv6            1403828      0t0     TCP *:20559 (LISTEN)
prax-bina 27652 julien   10u  sock                0,7      0t0 1403829 can't identify protocol
prax-bina 27652 julien   11u  IPv6            1403830      0t0     TCP *:20558 (LISTEN)
prax-bina 27652 julien   13u  sock                0,7      0t0 1406150 can't identify protocol
prax-bina 27652 julien   14u  sock                0,7      0t0 1406152 can't identify protocol
prax-bina 27652 julien   15u  sock                0,7      0t0 1406154 can't identify protocol
prax-bina 27652 julien   16u  sock                0,7      0t0 1406156 can't identify protocol
prax-bina 27652 julien   17u  sock                0,7      0t0 1406158 can't identify protocol
prax-bina 27652 julien   18u  sock                0,7      0t0 1406160 can't identify protocol
prax-bina 27652 julien   19u  sock                0,7      0t0 1406162 can't identify protocol
prax-bina 27652 julien   20u  sock                0,7      0t0 1406164 can't identify protocol
prax-bina 27652 julien   21u  sock                0,7      0t0 1405310 can't identify protocol
prax-bina 27652 julien   22u  sock                0,7      0t0 1405315 can't identify protocol
prax-bina 27652 julien   23u  sock                0,7      0t0 1405319 can't identify protocol
prax-bina 27652 julien   24u  sock                0,7      0t0 1405324 can't identify protocol
prax-bina 27652 julien   25u  sock                0,7      0t0 1405328 can't identify protocol
prax-bina 27652 julien   26u  sock                0,7      0t0 1405332 can't identify protocol
prax-bina 27652 julien   27u  sock                0,7      0t0 1407060 can't identify protocol
prax-bina 27652 julien   28u  sock                0,7      0t0 1405374 can't identify protocol
prax-bina 27652 julien   29u  sock                0,7      0t0 1405378 can't identify protocol
prax-bina 27652 julien   30u  sock                0,7      0t0 1408064 can't identify protocol
prax-bina 27652 julien   31u  sock                0,7      0t0 1404805 can't identify protocol
prax-bina 27652 julien   32u  sock                0,7      0t0 1404808 can't identify protocol

When making curl requests one by one, Prax leaks a sock but debug shows that TCPSocket reuses the same file descriptor (eg: 12), indicating that it may not be Server#handle_client that's leaking.

I see prax-help: not found

I am seeing /usr/bin/prax: line 17: exec: prax-help: not found after rebooted the machine. My os is debian 8.8 jessie

0.6.1-1 deb install does not complete

I am running Ubuntu 16.10 and during the install, it returns an error:

Setting up prax (0.6.1-1) ...
dpkg: error processing package prax (--configure):
 subprocess installed post-installation script returned error exit status 1
Errors were encountered while processing:
 prax
E: Sub-process /usr/bin/dpkg returned an error code (1)

0.6.0-1 installs correctly.

Does not work

It just does not work, I'm on Ubuntu. Maybe there is something I am missing.

vagrant@vagrant-VirtualBox:~$ cd Projects/users/
vagrant@vagrant-VirtualBox:~/Projects/users$ prax link
ln -s '/home/vagrant/Projects/users' '/home/vagrant/.prax/users'
vagrant@vagrant-VirtualBox:~/Projects/users$ prax open
+ xdg-open http://users.test
# does not work
vagrant@vagrant-VirtualBox:~/Projects/users$ prax start
I, [2018-11-09 10:46:24 -06:00 #6462]  INFO -- prax: binding to [::]:20559
# tried does not work  http://users.test
vagrant@vagrant-VirtualBox:~/Projects/users$ prax list
*users  '~/Projects/users'
vagrant@vagrant-VirtualBox:~/Projects/users$ prax restart
touch tmp/restart.txt
vagrant@vagrant-VirtualBox:~/Projects/users$ prax open
+ xdg-open http://users.test
# does not work
vagrant@vagrant-VirtualBox:~/Projects/users$ cat config.ru

require ::File.expand_path('../config/environment',  __FILE__)
run Rails.application

Tried also rails server and then prax start in a different tab, no luck.

First time I tried to run, I had this issue https://stackoverflow.com/questions/50244429/error-while-loading-shared-libraries-libevent-2-0-so-5 but it was resolved with that package install. Is it maybe related?

Thank you for this project, I want to switch from Mac to Linux.

Error in make prax

When I try to make prax I get the following error:

$ make                          
mkdir -p bin
/usr/bin/crystal build /home/richard/code/prax.cr/src/prax.cr -o bin/prax-binary
Error in ./src/event.cr:10: undefined method 'dns_base' for Event::Base

I am not sure how to troubleshoot this.

`make package` fails

When I try to run make package, an error occurs:

~/projects/prax.cr (patches) λ make package
cd ext && make
make[1]: Entering directory '/home/jackson/projects/prax.cr/ext'
gcc -Wall -fPIC -c -o nss_prax.o nss_prax.c -O2
gcc -shared -o libnss_prax.so.2 nss_prax.o -Wl,-soname,libnss_prax.so.2 -O2
make[1]: Leaving directory '/home/jackson/projects/prax.cr/ext'
mkdir -p /home/jackson/projects/prax.cr/dist/opt/prax/bin
/usr/bin/crystal build --release /home/jackson/projects/prax.cr/src/prax.cr -o /home/jackson/projects/prax.cr/dist/opt/prax/bin/prax-binary --no-debug
#strip --strip-uneeded /home/jackson/projects/prax.cr/dist/opt/prax/bin/prax-binary
mkdir -p /home/jackson/projects/prax.cr/dist/lib /home/jackson/projects/prax.cr/dist/opt/prax /home/jackson/projects/prax.cr/dist/usr/bin /home/jackson/projects/prax.cr/dist/opt/prax/bin /home/jackson/projects/prax.cr/dist/opt/prax/doc #
cp bin/prax /home/jackson/projects/prax.cr/dist/opt/prax/bin
cp -r libexec /home/jackson/projects/prax.cr/dist/opt/prax
cp ext/libnss_prax.so.2 /home/jackson/projects/prax.cr/dist/lib
cd /home/jackson/projects/prax.cr/dist/usr/bin && ln -sf ../../opt/prax/bin/prax
cp README.md LICENSE install/prax.desktop /home/jackson/projects/prax.cr/dist/opt/prax/doc
#cp install/prax.desktop 
chmod -R 0755 /home/jackson/projects/prax.cr/dist/opt/prax/bin /home/jackson/projects/prax.cr/dist/opt/prax/libexec /home/jackson/projects/prax.cr/dist/lib/libnss_prax.so.2
mkdir -p /home/jackson/projects/prax.cr/dist/etc/NetworkManager/dnsmasq.d /home/jackson/projects/prax.cr/dist/etc/dnsmasq.d
cp install/dnsmasq /home/jackson/projects/prax.cr/dist/etc/NetworkManager/dnsmasq.d/prax
cp install/dnsmasq /home/jackson/projects/prax.cr/dist/etc/dnsmasq.d/prax
cp bin/prax-rc /home/jackson/projects/prax.cr/dist/opt/prax/bin/prax-rc
cd dist && fpm -s dir -t  \
	--name "prax" \
	--version "`cat ../VERSION`" \
	 \
	--maintainer "[email protected]" \
	--url "https://github.com/ysbaddaden/prax.cr" \
	--description "Rack proxy server for development" \
	--vendor "" \
	--license "CeCILL 2.1 License" \
	--category devel \
	--after-install "/postinst" \
	--before-remove "/prerm" \
	--after-remove "/postrm" \
	etc lib opt usr
All flags should be before the first argument (stray flags found: ["--version", "--maintainer", "--url", "--description", "--vendor", "--license", "--category", "--after-install", "--before-remove", "--after-remove"] {:level=>:warn}
Invalid output package (-t flag) type "--name". Expected one of: apk, cpan, deb, dir, empty, freebsd, gem, npm, osxpkg, p5p, pacman, pear, pkgin, pleaserun, puppet, python, rpm, sh, solaris, tar, virtualenv, zip {:level=>:warn}
Fix the above problems, and you'll be rolling packages in no time! {:level=>:fatal}
Makefile:53: recipe for target 'package' failed
make: *** [package] Error 1

My fpm version is 1.8.1. Is that not supported?

Compilation error in 0.7.0/master with Crystal 0.24.1

Repro: run make

Expected: compilation succeeds
Instead: compilation fails on

macro def self.version_string : String

with following error:

develop7@t-rex ~/s/prax.cr (master)>  make
mkdir -p bin
/home/develop7/.linuxbrew/bin/crystal build /home/develop7/src/prax.cr/src/prax.cr -o bin/prax-binary
Syntax error in src/prax.cr:18: unexpected token: self (parentheses are mandatory for macro arguments)

  macro def self.version_string : String
            ^

make: *** [Makefile:25: all] Error 1

Prax freezes after one of multiple applications is killed by the monitor

First off, it seems like the monitor needs to duplicate Prax.applications when iterating over it, otherwise deleting an element early in the array can cause later elements to not be iterated over.

diff --git a/src/prax/monitor.cr b/src/prax/monitor.cr
index 828b5ba..ea4863f 100644
--- a/src/prax/monitor.cr
+++ b/src/prax/monitor.cr
@@ -6,7 +6,7 @@ module Prax
     def self.clear_stalled_applications
       Prax.logger.debug "clearing stalled applications"
 
-      Prax.applications.each do |app|
+      Prax.applications.dup.each do |app|
         if app.last_accessed_at + TTL < Time.now
           Prax.applications.delete(app)
           app.stop

You can see that by running the following code in crystal play:

a = [1, 2, 3]
b = [] of Int32
a.each do |e|
  b << e
  if e == 2
    a.delete(2)
  end
end
a
b

b will be [1, 2]. If you change a.each to a.dup.each, then b will be [1, 2, 3].

With that out of the way, onto my main issue. I’ve noticed that if I have multiple applications running and one of my applications becomes inactive and the monitor kills it, after the monitor goes to sleep again, Prax will become completely unresponsive. I can’t make any new requests (all new requests just hang), and the monitor does not appear to run again after DELAY seconds.

An additional bit of information: When I quit Prax by typing ^C, I see the following printed to my terminal as Prax attempts to kill the other application (that one that it deemed was suitable to keep alive due to it being “active” earlier):

^CI, [2018-11-26 08:55:02 -08:00 #18881]  INFO -- prax: killing application: app
kill: No such process (Errno)
  from /usr/share/crystal/src/process.cr:42:7 in 'kill'
  from /usr/share/crystal/src/process.cr:340:5 in 'kill'
  from /usr/share/crystal/src/process.cr:339:3 in 'kill'
  from src/prax/application/spawner.cr:104:9 in 'kill'
  from src/prax/application/spawner.cr:74:7 in 'stop'
  from src/prax/application/spawner.cr:68:13 in 'stop'
  from src/prax/application/spawner.cr:38:9 in 'execute'
  from src/prax/application/spawner.cr:16:11 in '->'
  from /usr/share/crystal/src/fiber.cr:255:3 in 'run'
  from /usr/share/crystal/src/fiber.cr:75:34 in '->'
  from ???
FATAL: uncaught exception while processing handler for INT, exiting

Another bit of info: in another scenario, if all of my applications are deemed inactive and killed at the same time, then Prax does not freeze up.

My first guess was that, with the monitor running in its own thread, running delete on a class variable would cause another thread accessing the shared Prax.applications value to explode. However according to the Crystal docs this seems to be okay to do for now: https://crystal-lang.org/docs/guides/concurrency.html#communicating-data

My next guess would be that the act of killing an application process causes one fiber to hang which prevents any other fibers from executing after the monitor goes to sleep. However this seems to be contradicted by the case where when the monitor kills all of the applications simultaneously things still work.

Your expertise would be much appreciated here.

Doesn't seem to work

distro: Debian Jessie
installed via latest .deb package

>> prax start -v
Prax 0.6.1-1 (2016-10-13)
>> ls -la /home/kwstannard/.prax/
total 8
drwxr-xr-x  2 kwstannard kwstannard 4096 Feb  9 10:37 .
drwxr-xr-x 66 kwstannard kwstannard 4096 Feb  9 10:22 ..
lrwxrwxrwx  1 kwstannard kwstannard   28 Feb  9 10:22 casper -> /home/kwstannard/work/Casper
>> cat /home/kwstannard/.prax/casper/config.ru 
# This file is used by Rack-based servers to start the application.

require ::File.expand_path('../config/environment',  __FILE__)

run Rails.application
>> prax start -V
I, [2017-02-09 10:40:09 -0500 #32262]  INFO -- prax: binding to [::]:20559

# in another tab
>> curl http://casper.dev
curl: (7) Failed to connect to casper.dev port 80: Connection refused

Doesn't work in browser either and returns an immediate server not found. rails s works perfectly.

HTTPS server

The Ruby version of Prax supports an additionnal HTTPS server, along the HTTP one. The Crystal version should to. This is sometimes necessary when dealing with external social services like Facebook.

ERROR -- prax: kill: No such process

I'm using 0.7.0-1 (2017-04-07) on Ubuntu 16.04 and get this error with a Rails 3.1 application on Ruby 1.8.7. After touching tmp/restart.txt, Prax has problems killing application processes and even itself.

E, [2017-12-21 11:05:15 -0600 #20821] ERROR -- prax: kill: No such process
  0x46e44d: ??? at /vagrant/src/prax/handler.cr 50:11
  0x41b828: ??? at /opt/crystal/src/fiber.cr 114:3
  0x0: ??? at ??

% ps ux | grep "rackup\|ruby\|prax"
graywh   13664  0.0  0.5 158532 71956 pts/19   Ss+  09:40   0:04 /usr/local/rbenv/versions/1.8.7-p358/bin/ruby script/rails c
graywh   20821  0.0  0.0 142972  8996 pts/21   SNl  10:59   0:00 /opt/prax/bin/prax-binary
graywh   20865  1.2  1.2 238000 153860 pts/21  SN   10:59   0:04 /usr/local/rbenv/versions/1.8.7-p358/bin/rackup
graywh   21485  0.0  0.0  14224  1096 pts/21   R+   11:05   0:00 grep --color=auto --line-number --binary-files=without-match -i rackup\|ruby\|prax

% prax stop
Unhandled exception in spawn:
Closed stream (IO::Error)
0x46c03d: ??? at /opt/crystal/src/socket.cr 192:16                                                                                                  
0x41b828: ??? at /opt/crystal/src/fiber.cr 114:3
0x0: ??? at ??
Unhandled exception in spawn:
Closed stream (IO::Error)
0x46c03d: ??? at /opt/crystal/src/socket.cr 192:16
0x41b828: ??? at /opt/crystal/src/fiber.cr 114:3
0x0: ??? at ??
I, [2017-12-21 11:08:31 -0600 #20821]  INFO -- prax: killing application: [REDACTED]
kill: No such process (Errno)
0x44e9c3: ??? at /vagrant/src/prax/application.cr 93:9
0x44da03: ??? at /vagrant/src/prax.cr 29:25
0x464fe6: ??? at /opt/crystal/src/string/builder.cr 87:5
0x42d474: ??? at /opt/crystal/src/event/signal_handler.cr 48:7
0x41b828: ??? at /opt/crystal/src/fiber.cr 114:3
0x0: ??? at ??
FATAL ERROR: uncaught signal TERM exception, exiting
[1]  + 20821 exit 1     prax start

% ps ux | grep "rackup\|ruby\|prax" 
graywh   13664  0.0  0.5 158532 71956 pts/19   Ss+  09:40   0:04 /usr/local/rbenv/versions/1.8.7-p358/bin/ruby script/rails c
graywh   20865  0.8  1.2 238000 153860 pts/21  SN   10:59   0:04 /usr/local/rbenv/versions/1.8.7-p358/bin/rackup
graywh   21557  0.0  0.0  14224  1016 pts/21   S+   11:08   0:00 grep --color=auto --line-number --binary-files=without-match rackup\|ruby\|pra

% prax start
I, [2017-12-21 11:09:00 -0600 #21569]  INFO -- prax: binding to [::]:20559
bind: Address already in use (Errno)
0x46a491: ??? at /vagrant/src/prax/server.cr 35:7
0x4132d3: ??? at /vagrant/src/prax.cr 113:3
0x42edfb: main at /opt/crystal/src/main.cr 12:15
0x7f0a178a7830: __libc_start_main at ??
0x40edf9: ??? at ??
0x0: ??? at ??

Please create next release.

With “.test” and Debian 9 support added, I would appreciate if an official release were made available so I could simplify my setup scripts. Thanks!

start prax manually

I would like to start and stop Prax service manually, but the only way I found to use the service is adding desktop run to autostart. Is there a way to do this?

Proxy Websockets

It would be nice for Prax to keep forwarding data back and forth after a sucessful websocket upgrade.

Remove mutexes for actors instead

Related to #3

Instead of having a mutex to avoid starting the same application multiple times (race condition) Prax should leverage an actor system.

Prax hangs forever with concurrent requests to an app while it spawns

Having concurrent requests to myapp.dev while the rack application is actually spawning results in Prax hanging forever. I suspect the mutex is no longer working as expected, since we now run a single-threaded event loop: the mutex must lock the thread when the 2nd request comes in, while never releasing it.

Error starting application

I am seeing the following message. The message is exactly messaged when I run bundle exec rails s. Normally, it means the server start successfully but I am still getting 500 internal error. I don't see any other message.

2017-07-07T18:44:33.514Z 3183 TID-grgyrcjko INFO: SidekiqScheduler is disabled
Puma starting in single mode...
* Version 3.4.0 (ruby 2.3.3-p222), codename: Owl Bowl Brawl
* Min threads: 1, max threads: 1
* Environment: development
* Listening on tcp://localhost:41987
Use Ctrl-C to stop

Are TLDs other than .dev possible?

I'd like to use this on a remote vim dev VPS. Currently I just browse to my domain.com:3000. Being able to do something like app.mydomain.com would be amazing.

Probably isn't the right place but I'm having issues setting up Prax

My application IP is resolving to 127.0.53.53 instead of 127.0.0.1. I don't really have any clue where to go with this. I did the couple things listed in the Troubleshooting section but don't know what to do to fix it.

Any help would be greatly appreciated. Below is console output:

127.0.53.53     carbonAPI.dev

xxx@xxx:~/RubymineProjects/CarbonAPI$ sudo /etc/init.d/prax status
Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    REDIRECT   tcp  --  0.0.0.0/0            127.0.0.1            tcp dpt:80 redir ports 20559
2    REDIRECT   tcp  --  0.0.0.0/0            127.0.0.1            tcp dpt:443 redir ports 20558
Chain PREROUTING (policy ACCEPT)
num  target     prot opt source               destination         
1    REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 redir ports 20559
2    REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:443 redir ports 20558
3    REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 redir ports 20559
4    REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:443 redir ports 20558
Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    REDIRECT   tcp      ::/0                 ::1                  tcp dpt:80 redir ports 20559
2    REDIRECT   tcp      ::/0                 ::1                  tcp dpt:443 redir ports 20558
Chain PREROUTING (policy ACCEPT)
num  target     prot opt source               destination         
1    REDIRECT   tcp      ::/0                 ::/0                 tcp dpt:80 redir ports 20559
2    REDIRECT   tcp      ::/0                 ::/0                 tcp dpt:443 redir ports 20558
3    REDIRECT   tcp      ::/0                 ::/0                 tcp dpt:80 redir ports 20559
4    REDIRECT   tcp      ::/0                 ::/0                 tcp dpt:443 redir ports 20558```

Bad request when sending host header

When the requests have a host header (downcased) prax would just raise a bad request since it's looking for Host (camelcased) but it shouldn't it should work with both 'host' and 'Host' as the HTTP spec says headers should be case-insensitive.

This may be the issue

https://github.com/ysbaddaden/prax.cr/blob/master/src/prax/parser/request.cr#L28

EDIT:

I just realized there's a test case for lowercase host header, but It's failing for me 🤔

EDIT:

Just realized the code is there and I'm using an old version of prax, sorry for the spam 😅

Timeout is too short

Prax.logger.error "timeout starting application: #{app.name}"

This basically makes prax useless for anyone with a legacy rails app.

  1. Why is there a timeout? Could it just be deleted?
  2. If not deleted, maybe we could add a flag/env var to alter the timeout?

Document dnsmasq instead/along the NSSwitch extension

The documentation in the wiki details the NSSwitch extension which should (almost) be considered deprecated: it's incompatible with non-glibc systems (like musl-libc) and with Chrome 41+.

The wiki should document the new dnsmasq configuration, which is more compatible.

refs #9 and #10

Set proxy headers

Prax should set the following proxy headers:

  • X-Forwarded-For
  • X-Forwarded-Host
  • X-Forwarded-Proto
  • X-Forwarded-Server

Can installation be made easier on Debian 9?

On Debian 9, if I try to install the latest release, I get an error:

$ wget https://github.com/ysbaddaden/prax.cr/releases/download/v0.7.0/prax_0.7.0-1_amd64.deb
$ sudo gdebi prax_0.7.0-1_amd64.deb
[sudo] password for jackson: 
Reading package lists... Done
Building dependency tree        
Reading state information... Done
Reading state information... Done
This package is uninstallable
Dependency is not satisfiable: libssl1.0.0

There doesn't seem to be a libssl1.0.0 on Debian 9, only libssl1.0.2, according to this answer.

I was able to work around this by installing the Debian 8 version from here:

wget http://security.debian.org/debian-security/pool/updates/main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u7_amd64.deb
sudo gdebi libssl1.0.0_1.0.1t-1+deb8u7_amd64.deb
sudo apt-mark auto libssl1.0.0

It'd be nice if it was possible to install the package on Debian 9 without needing to resort to old packages. Do you have any ideas on how to do that? Perhaps upgrade to the latest libssl, or support both versions somehow?

prax-binary: error while loading shared libraries: libevent-2.0.so.5

After installing Prax.cr im getting this error

/opt/prax/bin/prax-binary: error while loading shared libraries: libevent-2.0.so.5: cannot open shared object file: No such file or directory

I thought it might be something simple to solve with

$ sudo apt install libevent-dev

This failed though and after removing prax and reinstalling its failing again.

anyone experienced this before

XUbuntu 18.04

Improve compatibility with dotenv

In my application, I'm using the dotenv gem to load a ".env" file with the following contents:

PROTOCOL=http:
BASE_DOMAIN=example.dev
AUTH_APP_URL=$PROTOCOL//$BASE_DOMAIN

dotenv supports bash-style variable substitution, so if dotenv were the first code to parse my ".env" file, then ENV["AUTH_APP_URL"] would be http://example.dev.

However, because I'm using Prax to start my application, and Prax also parses ".env" files and sets the environment variable AUTH_APP_URL, but Prax doesn't seem to support variable substitution, and because dotenv internally sets ENV with the Ruby code ENV[k] ||= v (I think because users wanted to override ".env" variables via CLI), I believe that for all these reasons ENV["AUTH_APP_URL"] ends up being $PROTOCOL//$BASE_DOMAIN, which seems to be breaking the code in my application that uses ENV["AUTH_APP_URL"].

Therefore, I'd like to discuss a strategy for improving compatibility with the dotenv gem.

A quick peek at Pow reveals to me that they use ".powrc" and ".powenv", but not ".env". I see that Prax already supports ".praxrc" so as "to configure variables", so is ".env" necessary? To improve parity with Pow, and to avoid racing with dotenv, I'd like to (selfishly) suggest that support for ".env" loading be removed from Prax. I imagine there may be some users who rely on this feature, so maybe to smooth migration, ".env" could be deprecated at first, with a message encouraging users to use ".praxrc" instead.

In combination with deprecation, or simply as a new feature to improve dotenv compatibility, or for backwards compatibility, maybe it could also be possible to configure whether or not Prax loads ".env" files.

Crashes in release mode

I noticed that the prax-binary built in release mode regularly segfaults with a non helpful message like segfault in fun literal~42. I haven't been able to reproduce the problem in non release mode, yet.

There doesn't seem to be a user driven process do reproduce the bug, which just pops up sometimes, either while using Prax or not.

Support alternative DNS resolvers

  • Chrome implements it's own DNS resolver (Asynchronous DNS resolver) which bypasses the glic resolver (getaddrinfo) and thus bypasses NSSwitch configuration.
  • Alternative libc implementations, like musl, don't implement NSSwitch, for simplicity.
  • Mac OS X uses per domain resolvers (cf. Pow).

It may be necessary to have an alternative solution to resolve .dev domains locally. Like depending on dnsmasq in packages and installing a custom configuration to resolve .dev domains. Maybe some other idea?

Deb package: can't resolve .dev domains

When the deb package is installed/removed the NSSwitch hosts configuration isn't modified to add/remove the prax resolver. A default installation is thus incapable to resolve .dev domains.

timeout starting application

Hi!!! i wanted to ask something, i configured and linked my app folder to prax, and when i access it on the URL myapp.dev, prax starts the rackup, but, my app has a very specific configuraction that it makes compilation of assets and it always delays many seconds on the first shot, and as consequence prax sends me a timeout starting application, is there a way i can increase the wait time? my app has a very specific config, cause its trying to compile a second project that is for the frontend. Or, is there a way i can get in charge of making the rackup in a specific port for prax to make the redirection?, for example if i would like to make a foreman start for starting the app.

Thank you!

Starting an application using Thin results in a timeout.

When I try to start up an application using the WEBrick web server, Prax can start it successfully. But if I try to use Thin, I get the following error:

E, [2017-09-26 16:39:58 -0700 #994] ERROR -- prax: timeout starting application: example

I believe that it's possible to open a TCP connection to WEBrick (as prax does), since when I rackup in one terminal:

bundle exec rackup --host localhost --port 1234

And then in another terminal, do:

nc localhost 1234

Then netcat hangs. But if I try to connect in the same way to a Thin server, I immediately get this output:

localhost [127.0.0.1] 1234 (?) : Connection refused

Maybe Prax needs a better / alternative heuristic for detecting that the server has started?

It is possible for me to connect to my Thin server with:

curl -i -X HEAD http://localhost:1234

Maybe firing a HEAD would be more reliable?

$RBENV_VERSION

I use Rbenv and ran into an issue with Prax using the wrong Ruby version for applications because of the $RBENV_VERSION environment variable in the shell where I started Prax.

Should Prax remove/unset that variable before starting up an application?

Many failing tests

Hi, I'm trying to make changes to this library, however a lot of the tests are failing for me on master:

~/projects/prax.cr (master) λ make test
mkdir -p bin
/usr/bin/crystal build /home/jackson/projects/prax.cr/src/prax.cr -o bin/prax-binary
bundle exec rake test --trace --verbose
** Invoke test (first_time)
** Execute test
/home/jackson/.rbenv/versions/2.3.1/bin/ruby -I"lib:test" -I"/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib" "/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/rake_test_loader.rb" "test/failures_test.rb" "test/keepalive_test.rb" "test/port_forwarding_test.rb" "test/praxrc_test.rb" "test/proxy_test.rb" "test/public_file_test.rb" 
Run options: --seed 62911

# Running:

...SF.EE...EESEEEEE

Fabulous run in 25.418010s, 0.7475 runs/s, 0.9049 assertions/s.

  1) Failure:
PortForwardingTest#test_forwards_to_given_port [/home/jackson/projects/prax.cr/test/port_forwarding_test.rb:29]:
--- expected
+++ actual
@@ -1,2 +1,113 @@
-"TCPServer: OK
+"<!DOCTYPE html>
+<html>
+<head>
+  <meta charset=\"utf-8\"/>
+  <title>Proxy Error</title>
+
+  <style type=\"text/css\">
+   body {
+     margin: 0;
+     padding: 0;
+     font: normal normal 16px/1.4 Helvetica, sans-serif;
+     background: #e0e0d8;
+   }
+
+   h1, h2, p, li { font: inherit; }
+   ul { padding: 0; }
+   li { list-style: none; }
+   pre, code { font-family: Menlo, Monaco, monospace; }
+   p code { font-size: 14px; }
+   p, pre { color: #222; }
+   a { color: #776; }
+
+   .page {
+     max-width: 480px;
+     margin: 36px auto;
+     padding: 36px 90px;
+     background: #fff;
+     box-shadow: 0px 2px 7px #999;
+   }
+
+   h1 {
+     margin: 0 0 0 -57px;
+     line-height: 45px;
+     font-size: 36px;
+     font-weight: bold;
+   }
+   h1:before {
+     position: relative;
+     top: 10px;;
+     font-size: 66px;
+     line-height: 42px;
+   }
+   h1.ok {
+     color: #090;
+   }
+   h1.ok:before {
+     content: \"\xE2\x9C\x93\";
+     color: #090;
+   }
+   h1.err {
+     color: #900;
+   }
+   h1.err:before {
+     content: \"\xE2\x9C\x97\";
+     color: #900;
+   }
+
+   //h2 {
+   //  line-height: 27px;
+   //  font-size: 18px;
+   //  font-weight: normal;
+   //  margin: 0;
+   //}
+
+   pre {
+     white-space: pre-wrap;
+     font-size: 14px;
+     background: #2a2a29;
+     color: #eee;
+     padding: 1em;
+   }
+   pre span {
+     color: #aa9;
+   }
+
+   //pre.breakout {
+   //  border-top: 1px solid #ddd;
+   //  border-bottom: 1px solid #ddd;
+   //  background: #fafcf4;
+   //  margin-left: -90px;
+   //  margin-right: -90px;
+   //  padding: 8px 0 8px 90px;
+   //}
+   //pre.small_text {
+   //  font-size: 10px;
+   //}
+   //pre.small_text strong {
+   //  font-size: 13px;
+   //}
+  </style>
+</head>
+
+<body>
+  <div class=\"page\">
+    <h1 class=\"err\">Proxy Error</h1>
+
+<section>
+  <p>Couldn't proxy request to <code>forward.dev:3123</code>.</p>
+
+  <pre>Error connecting to '127.0.0.1:3123': Connection refused</pre>
+</pre>
+</section>
+
+
+    <ul>
+      <li><a href=\"http://github.com/ysbaddaden/prax\">GitHub Page</a></li>
+      <li><a href=\"https://github.com/ysbaddaden/prax/issues\">Issue Tracker</a></li>
+    </ul>
+  </div>
+</body>
+</html>
+
 "



  2) Error:
PraxrcTest#test_praxrc_loaded:
Timeout::Error: execution expired
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:158:in `wait_readable'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:158:in `rbuf_fill'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:136:in `readuntil'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:146:in `readline'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http/response.rb:40:in `read_status_line'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http/response.rb:29:in `read_new'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1437:in `block in transport_request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1434:in `catch'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1434:in `transport_request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1407:in `request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1308:in `request_get'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:481:in `block in get_response'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:853:in `start'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:584:in `start'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:479:in `get_response'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:456:in `get'
    /home/jackson/projects/prax.cr/test/praxrc_test.rb:5:in `test_praxrc_loaded'


  3) Error:
FailuresTest#test_host_header_is_missing_but_found_in_uri:
Timeout::Error: execution expired
    /home/jackson/projects/prax.cr/test/failures_test.rb:25:in `gets'
    /home/jackson/projects/prax.cr/test/failures_test.rb:25:in `block in test_host_header_is_missing_but_found_in_uri'
    /home/jackson/projects/prax.cr/test/failures_test.rb:23:in `open'
    /home/jackson/projects/prax.cr/test/failures_test.rb:23:in `test_host_header_is_missing_but_found_in_uri'


  4) Error:
ProxyTest#test_returns_multiple_set_cookie_headers:
Timeout::Error: execution expired
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:158:in `wait_readable'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:158:in `rbuf_fill'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:136:in `readuntil'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:146:in `readline'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http/response.rb:40:in `read_status_line'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http/response.rb:29:in `read_new'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1437:in `block in transport_request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1434:in `catch'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1434:in `transport_request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1407:in `request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1308:in `request_get'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:481:in `block in get_response'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:853:in `start'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:584:in `start'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:479:in `get_response'
    /home/jackson/projects/prax.cr/test/proxy_test.rb:33:in `test_returns_multiple_set_cookie_headers'


  5) Error:
ProxyTest#test_alters_request_headers_and_sets_proxy_headers:
Timeout::Error: execution expired
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:158:in `wait_readable'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:158:in `rbuf_fill'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:136:in `readuntil'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:146:in `readline'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http/response.rb:40:in `read_status_line'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http/response.rb:29:in `read_new'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1437:in `block in transport_request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1434:in `catch'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1434:in `transport_request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1407:in `request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1308:in `request_get'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:481:in `block in get_response'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:853:in `start'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:584:in `start'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:479:in `get_response'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:456:in `get'
    /home/jackson/projects/prax.cr/test/proxy_test.rb:42:in `test_alters_request_headers_and_sets_proxy_headers'


  6) Error:
ProxyTest#test_proxies_to_rack_applications:
Timeout::Error: execution expired
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:158:in `wait_readable'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:158:in `rbuf_fill'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:136:in `readuntil'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:146:in `readline'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http/response.rb:40:in `read_status_line'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http/response.rb:29:in `read_new'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1437:in `block in transport_request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1434:in `catch'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1434:in `transport_request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1407:in `request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1308:in `request_get'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:481:in `block in get_response'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:853:in `start'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:584:in `start'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:479:in `get_response'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:456:in `get'
    /home/jackson/projects/prax.cr/test/proxy_test.rb:6:in `test_proxies_to_rack_applications'


  7) Error:
ProxyTest#test_supports_xip_io:
Timeout::Error: execution expired
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:158:in `wait_readable'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:158:in `rbuf_fill'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:136:in `readuntil'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:146:in `readline'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http/response.rb:40:in `read_status_line'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http/response.rb:29:in `read_new'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1437:in `block in transport_request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1434:in `catch'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1434:in `transport_request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1407:in `request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1308:in `request_get'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:481:in `block in get_response'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:853:in `start'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:584:in `start'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:479:in `get_response'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:456:in `get'
    /home/jackson/projects/prax.cr/test/proxy_test.rb:25:in `test_supports_xip_io'


  8) Error:
ProxyTest#test_augments_proxy_headers:
Timeout::Error: execution expired
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:158:in `wait_readable'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:158:in `rbuf_fill'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:136:in `readuntil'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:146:in `readline'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http/response.rb:40:in `read_status_line'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http/response.rb:29:in `read_new'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1437:in `block in transport_request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1434:in `catch'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1434:in `transport_request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1407:in `request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1156:in `get'
    /home/jackson/projects/prax.cr/test/proxy_test.rb:56:in `block in test_augments_proxy_headers'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:853:in `start'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:584:in `start'
    /home/jackson/projects/prax.cr/test/proxy_test.rb:55:in `test_augments_proxy_headers'


  9) Error:
ProxyTest#test_empty_header:
Timeout::Error: execution expired
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:158:in `wait_readable'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:158:in `rbuf_fill'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:136:in `readuntil'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:146:in `readline'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http/response.rb:40:in `read_status_line'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http/response.rb:29:in `read_new'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1437:in `block in transport_request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1434:in `catch'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1434:in `transport_request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1407:in `request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1308:in `request_get'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:481:in `block in get_response'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:853:in `start'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:584:in `start'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:479:in `get_response'
    /home/jackson/projects/prax.cr/test/proxy_test.rb:67:in `test_empty_header'


 10) Error:
ProxyTest#test_populates_env_from_env_file:
Timeout::Error: execution expired
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:158:in `wait_readable'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:158:in `rbuf_fill'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:136:in `readuntil'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/protocol.rb:146:in `readline'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http/response.rb:40:in `read_status_line'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http/response.rb:29:in `read_new'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1437:in `block in transport_request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1434:in `catch'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1434:in `transport_request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1407:in `request'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1308:in `request_get'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:481:in `block in get_response'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:853:in `start'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:584:in `start'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:479:in `get_response'
    /home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/net/http.rb:456:in `get'
    /home/jackson/projects/prax.cr/test/proxy_test.rb:17:in `test_populates_env_from_env_file'

19 runs, 23 assertions, 1 failures, 9 errors, 2 skips

You have skipped tests. Run with --verbose for details.
rake aborted!
Command failed with status (1): [ruby -I"lib:test" -I"/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib" "/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/rake_test_loader.rb" "test/failures_test.rb" "test/keepalive_test.rb" "test/port_forwarding_test.rb" "test/praxrc_test.rb" "test/proxy_test.rb" "test/public_file_test.rb" ]
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/testtask.rb:108:in `block (3 levels) in define'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/file_utils.rb:57:in `sh'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/file_utils_ext.rb:37:in `sh'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/file_utils.rb:96:in `ruby'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/file_utils_ext.rb:37:in `ruby'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/testtask.rb:104:in `block (2 levels) in define'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/file_utils_ext.rb:58:in `verbose'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/testtask.rb:100:in `block in define'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/task.rb:240:in `block in execute'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/task.rb:235:in `each'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/task.rb:235:in `execute'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/task.rb:179:in `block in invoke_with_call_chain'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/2.3.0/monitor.rb:214:in `mon_synchronize'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/task.rb:172:in `invoke_with_call_chain'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/task.rb:165:in `invoke'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/application.rb:150:in `invoke_task'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/application.rb:106:in `block (2 levels) in top_level'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/application.rb:106:in `each'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/application.rb:106:in `block in top_level'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/application.rb:115:in `run_with_threads'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/application.rb:100:in `top_level'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/application.rb:78:in `block in run'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/application.rb:176:in `standard_exception_handling'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/lib/rake/application.rb:75:in `run'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rake-10.4.2/bin/rake:33:in `<top (required)>'
/home/jackson/.rbenv/versions/2.3.1/bin/rake:23:in `load'
/home/jackson/.rbenv/versions/2.3.1/bin/rake:23:in `<top (required)>'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/bundler-1.13.6/lib/bundler/cli/exec.rb:74:in `load'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/bundler-1.13.6/lib/bundler/cli/exec.rb:74:in `kernel_load'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/bundler-1.13.6/lib/bundler/cli/exec.rb:27:in `run'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/bundler-1.13.6/lib/bundler/cli.rb:332:in `exec'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/bundler-1.13.6/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/bundler-1.13.6/lib/bundler/vendor/thor/lib/thor/invocation.rb:126:in `invoke_command'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/bundler-1.13.6/lib/bundler/vendor/thor/lib/thor.rb:359:in `dispatch'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/bundler-1.13.6/lib/bundler/cli.rb:20:in `dispatch'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/bundler-1.13.6/lib/bundler/vendor/thor/lib/thor/base.rb:440:in `start'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/bundler-1.13.6/lib/bundler/cli.rb:11:in `start'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/bundler-1.13.6/exe/bundle:34:in `block in <top (required)>'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/bundler-1.13.6/lib/bundler/friendly_errors.rb:100:in `with_friendly_errors'
/home/jackson/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/bundler-1.13.6/exe/bundle:26:in `<top (required)>'
/home/jackson/.rbenv/versions/2.3.1/bin/bundle:23:in `load'
/home/jackson/.rbenv/versions/2.3.1/bin/bundle:23:in `<main>'
Tasks: TOP => test
Makefile:77: recipe for target 'test' failed
make: *** [test] Error 1

Note that, for the above output, I added "--trace --verbose" to "bundle exec rake test --trace --verbose" in the Makefile before running make test.

I was wondering if you are seeing this too. If so, can we work to fix the tests? Or if not, any idea what's wrong on my end?

System is Debian 8 GNU Linux. Ruby is 2.3.1. Crystal is 0.20.5. Rackup is "Rack 1.3 (Release: 2.0.1)". Rake is "rake, version 10.4.2".

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.