0

I get the error NoMethodError: undefined method 'bytesize' when I try to connect to my ruby sinatra server through java.

This is my ruby code, I suspect I need some sort of method, which runs when a client connects but I am not sure:

require 'sinatra'

get '/hello' do
'this page displays hello'
end

get '/' do
'this page is the main page'
end

And here is the code for my java application:

private static Socket connect;
private static OutputStream output;
private static InputStream input;

public static void main(String[] args) throws IOException {
    System.out.println("Connecting...");
    connect = new Socket(InetAddress.getByName("localhost"), 4567);
    System.out.println("Connected to: " + connect.getInetAddress().getHostName());

    output = new ObjectOutputStream(connect.getOutputStream());
    output.flush();

    //input = new ObjectInputStream(connect.getInputStream());
    System.out.println("Streams ready");
}
Cj1m
  • 805
  • 3
  • 11
  • 26
  • Does the Sinatra application work correctly when you access it through a browser? – Alyssa Ross Aug 17 '13 at 12:21
  • @RossPenman Yes, works completely fine – Cj1m Aug 17 '13 at 12:28
  • What do you expect to happen with that Java code? You don’t make any HTTP request. And why are you using an `ObjectOutputStream`? – matt Aug 17 '13 at 14:28
  • @RossPenman I am wanting to send text to the server. – Cj1m Aug 17 '13 at 14:39
  • 1
    You can’t just open a socket and start sending data like that, you need to create a proper HTTP request. With this code you just get server errors relating to invalid requests. – matt Aug 17 '13 at 15:02

1 Answers1

0

I would guess this is happening because of a theory error in Rack in the following code, paired with a theory error in your Java client invocation of the Ruby server:

# Return the bytesize of String; uses String#size under Ruby 1.8 and
# String#bytesize under 1.9.
if ''.respond_to?(:bytesize)
  def bytesize(string)
    string.bytesize
  end
else
  def bytesize(string)
    string.size
  end
end
module_function :bytesize

That is in the file <rack>lib/rack/utils.rb ... which Sinatra uses, here:

headers["Content-Length"] = body.inject(0) { |l, p| l + Rack::Utils.bytesize(p) }.to_s

That is in the file <sinatra>lib/sinatra/base.rb in the #finish method, in inside a check which tests calculate_content_length?

...anyway, there is no test for if string is Nil, in the #bytesize method... it's just doing a test to see whether the Ruby engine itself supports #bytesize.

In other words, I would guess your body is Nil, or an incompatible kind of Object, which does not have the #bytesize method, since Rack does not test, it just assumes the data coming into that method is good, and passes the method call onto that object, based purely on the underlying engine... not based on the user_agent. That's Rack's theory error.

Troubleshooting further, I would guess that there is either something which is user_agent specific in your Java code, not your Ruby code. And not even truly user_agent, because you don't seem to instantiate a 'browser' but just open a socket connection. I'd guess that you need to actually invoke the server through HTTP commands in a formal request, RFC compliant protocol, etc... so you need to send a syntactically correct header and body.

I've seen this sort of thing happen with strange clients, such as obscure crawlers which do not send correct headers, or send no body and only headers. I'd further further further guess that opening a Socket connection is not enough. You need to send headers and a body to the server. I'd finally guess that you could likely use a Java library which is like a curl or a wget and not just manipulating a raw socket. That would do the proper protocol chatter for you, and just give you back what you're looking for from your Ruby/Sinatra endpoints. Looking around on here a bit, I found:

cURL equivalent in JAVA

Community
  • 1
  • 1
digitalextremist
  • 5,952
  • 3
  • 43
  • 62
  • Yeah. Upon returning to your question, I can best put it this way: Where is there an endpoint called? Even "/" is an endpoint that is explicitly called in the PATH_INFO header field. `Sinatra` and `Rack` underneath that are getting nothing to create a response out of. Technically, this ought to fail more elegantly, but it is still solvable by using an actual text-browser library such as at the link I added. I see Matt also mentioned this after reading the comments to your original question more closely. – digitalextremist Aug 17 '13 at 19:34