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

NoMethodError: undefined method `each' for nil:NilClass #1

Closed
imanel opened this issue Sep 12, 2010 · 9 comments
Closed

NoMethodError: undefined method `each' for nil:NilClass #1

imanel opened this issue Sep 12, 2010 · 9 comments

Comments

@imanel
Copy link

imanel commented Sep 12, 2010

I created simple class for rack:

class MyClass
  def self.call(data)
    puts data.inspect
  end
end

now when in irb I call

Rack::Handler::WEBrick.run(Palmade::SocketIoRack::Middleware.new(MyApp.new, :resources => {'/' => "Palmade::SocketIoRack::EchoResource"}), :Port => 8080)

and try to connect with WebSocket client it throws error:

{"HTTP_HOST"=>"127.0.0.1:8080", "SERVER_NAME"=>"127.0.0.1", "REQUEST_PATH"=>"/", "rack.url_scheme"=>"http", "REMOTE_HOST"=>"imanel.local", "rack.errors"=>#<IO:0x100183b88>, "SERVER_PROTOCOL"=>"HTTP/1.1", "rack.version"=>[1, 1], "rack.run_once"=>false, "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.8.7/2009-06-12)", "REMOTE_ADDR"=>"127.0.0.1", "PATH_INFO"=>"/", "HTTP_SEC_WEBSOCKET_KEY1"=>"]+ *1 91 D4 2 32959", "SCRIPT_NAME"=>"", "HTTP_VERSION"=>"HTTP/1.1", "rack.multithread"=>true, "HTTP_SEC_WEBSOCKET_KEY2"=>"S2%0O 80FL4 9 949", "rack.multiprocess"=>false, "REQUEST_URI"=>"http://127.0.0.1:8080/?client_id=", "SERVER_PORT"=>"8080", "REQUEST_METHOD"=>"GET", "HTTP_UPGRADE"=>"WebSocket", "HTTP_ORIGIN"=>"http://localhost:3000", "rack.input"=>#<StringIO:0x1023f4c58>, "HTTP_CONNECTION"=>"Upgrade", "QUERY_STRING"=>"client_id=", "GATEWAY_INTERFACE"=>"CGI/1.1"}
[2010-09-12 10:08:13] ERROR NoMethodError: undefined method `each' for nil:NilClass
    /opt/local/lib/ruby/gems/1.8/gems/rack-1.1.0/lib/rack/utils.rb:273:in `initialize'
    /opt/local/lib/ruby/gems/1.8/gems/rack-1.1.0/lib/rack/utils.rb:267:in `new'
    /opt/local/lib/ruby/gems/1.8/gems/rack-1.1.0/lib/rack/utils.rb:267:in `new'
    /opt/local/lib/ruby/gems/1.8/gems/rack-1.1.0/lib/rack/content_length.rb:14:in `call'
    /opt/local/lib/ruby/gems/1.8/gems/rack-1.1.0/lib/rack/handler/webrick.rb:48:in `service'
    /opt/local/lib/ruby/1.8/webrick/httpserver.rb:104:in `service'
    /opt/local/lib/ruby/1.8/webrick/httpserver.rb:65:in `run'
    /opt/local/lib/ruby/1.8/webrick/server.rb:173:in `start_thread'
    /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start'
    /opt/local/lib/ruby/1.8/webrick/server.rb:162:in `start_thread'
    /opt/local/lib/ruby/1.8/webrick/server.rb:95:in `start'
    /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `each'
    /opt/local/lib/ruby/1.8/webrick/server.rb:92:in `start'
    /opt/local/lib/ruby/1.8/webrick/server.rb:23:in `start'
    /opt/local/lib/ruby/1.8/webrick/server.rb:82:in `start'
    /opt/local/lib/ruby/gems/1.8/gems/rack-1.1.0/lib/rack/handler/webrick.rb:14:in `run'
    (irb):18:in `irb_binding'
    /opt/local/lib/ruby/1.8/irb/workspace.rb:52:in `irb_binding'
    /opt/local/lib/ruby/1.8/irb/workspace.rb:52
imanel.local - - [12/Sep/2010:10:08:13 CEST] "GET /?client_id= HTTP/1.1" 500 320
- -> /?client_id=

I used WEBrick because it gives more info(thin fails at the same point). Do you know what's the problem? System: OS X 10.6.4, ruby 1.8.7.174(i686)

@markjeee
Copy link
Owner

I think it is related to the Webrick server, including the Content Length middleware, that's part of the rack gem. When a WebSocket connection is created from a browser, i assume you're using Chrome, it doesn't include the Content-Length in the header -- and it looks like Webrick is expecting it.

Also, i think (i'm not sure), WebSocket type of connections don't work with any of the web servers now available in Ruby. The protocol upgrade handshake has to be explicitly supported by the web server, that the succeeding data after the handshake should be treated as raw data, instead of another HTTP request, as is in a persistent HTTP connection. I used a custom thin backend to handle the handshake properly, just like this one:

http://github.com/palmade/puppet_master/blob/development/lib/palmade/puppet_master/thin_websocket_connection.rb

@markjeee
Copy link
Owner

I'll port that code tonight and include it in this package, so you can do something like, somewhere in your code:

Thin.send(:include, Palmade::SocketIoRack::ThinExtentions)

@imanel
Copy link
Author

imanel commented Sep 12, 2010

About support of WebSocket server in ruby - we have couple of them like http://github.com/igrigorik/em-websocket or http://github.com/gimite/web-socket-ruby - both can handle draft 75 and draft 76, but they are standalone instead of thin extensions. Another solution is http://github.com/lifo/cramp that have support for WebSocket, but I don't know how it is working...

And about last line you wrote - why we need to send Thin this include line? Should whole plugin work out of the box? Or I just used it incorrect? My point is to create standalone app using socket.io, but not based on rails - so what is best way to implement that?

@markjeee
Copy link
Owner

Yo, i just pushed the thin extensions i mentioned in my previous message, and also added an example, in the examples directory. To run it,

 ruby examples/rack_app

You'll need the redis gem and a running redis server, since it uses it for session (in between reconnects and other message queuing support).

Yep, it can't run out of the box at the moment. For all the Rack supported web servers, i'm not sure any of them supports web sockets. And for the other websocket implementations, most of them are standalone, and i'd like to have something that comes together with my web app. Though i can imagine some might want to run it independently since it's possible to use a lot of persistent connections.

Also having it on a different process instance and on a different language (as is the case for Socket.IO-node) is a bit hard if most of my codes are running within Rails and/or on Ruby.

My idea here is to have a Rack middleware that i can use to plugin to an existing Rack-compatible web app. This can be Rails, Sinatra, or Camping. I have narrowed it down to the most minimum you'll need to do. For example:

 # load the code
 require 'palmade/socket_io_rack'
 Thin.send(:include, Palmade::SocketIoRack::Mixins::Thin)

 class Firehose < Palmade::SocketIoRack::Base
   def on_connect
     EM.add_timer(30) do
       reply "This message should show-up 30 secs later"
     end

     EM.add_timer(60) do
       reply "This message should show-up 60 secs later"
     end
   end

   def on_message(msg)
     reply "Hello #{msg}"
   end
 end

 # then later in the code, you register the middleware
 use(Palmade::SocketIoRack::Middleware,
       :resources =>  {
         '/firehose' => 'Firehose'
       })

@markjeee
Copy link
Owner

By the way, you'll only need the Thin extensions if using the WebSocket transport. For xhr-polling and xhr-multipart transports, they're not needed.

@imanel
Copy link
Author

imanel commented Sep 12, 2010

I will test that tonight, but looking at your commit I discovered that you only implemented Draft 76, when Safari is still #75. Is this for some reason or just the thing to implement? If so I can try to handle that tomorrow.

@markjeee
Copy link
Owner

Yep, no support for #75 yet. I am developing this on an Ubuntu machine. I'll go find a browser that supports #75 so i can add and test it.

@imanel
Copy link
Author

imanel commented Sep 12, 2010

You could always try older Chrome/Chromium builds - version 4 or 5 had draft 75 support

@imanel
Copy link
Author

imanel commented Sep 13, 2010

Closing this ticket as it is resolved and created #4 connected to lack of draft 75 support.

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

No branches or pull requests

2 participants