2

If Net::HTTP's open_timeout and read_timeout are not set, will it wait indefinitely?

According to the docs, open_timeout is defined as:

Number of seconds to wait for the connection to open. Any number may be used, including Floats for fractional seconds. If the HTTP object cannot open a connection in this many seconds, it raises a Net::OpenTimeout exception. The default value is nil.

OK so the default value is nil. What happens if the server (say, a malicious server) never responds and the client has not set an open_timeout? Will the client wait indefinitely?

I ask because I am trying to debug a scenario in which all of my processes are hung, indefinitely, with an SSL connection request at the top of the stack:

#0  0x00007f33a07acb13 in ppoll () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x00007f33a1962558 in rb_wait_for_single_fd (fd=<optimized out>, events=<optimized out>, tv=0x0) at thread.c:3583
#2  0x00007f33a1966ea2 in rb_thread_wait_fd_rw (read=1, fd=<optimized out>) at thread.c:3422
#3  rb_thread_wait_fd (fd=<optimized out>) at thread.c:3433
#4  0x00007f33a1854ebf in rb_io_wait_readable (f=40) at io.c:1081
#5  0x00007f339ed72184 in ossl_start_ssl (self=139859849103720, func=0x7f339eb1ab20 <SSL_connect>, funcname=0x7f339ed82d89 "SSL_connect", nonblock=<optimized out>) at ossl_ssl.c:1278

Which was apparently triggered by this call:

from /usr/local/lib/ruby/gems/2.0.0/gems/httparty-0.11.0/lib/httparty.rb:497:in `post'
from /usr/local/lib/ruby/gems/2.0.0/gems/httparty-0.11.0/lib/httparty.rb:414:in `post'
from /usr/local/lib/ruby/gems/2.0.0/gems/httparty-0.11.0/lib/httparty.rb:461:in `perform_request'
from /usr/local/lib/ruby/gems/2.0.0/gems/httparty-0.11.0/lib/httparty/request.rb:92:in `perform'
from /usr/local/lib/ruby/2.0.0/net/http.rb:1367:in `request'
from /usr/local/lib/ruby/2.0.0/net/http.rb:851:in `start'
from /usr/local/lib/ruby/2.0.0/net/http.rb:862:in `do_start'
from /usr/local/lib/ruby/2.0.0/net/http.rb:918:in `connect'
from /usr/local/lib/ruby/2.0.0/timeout.rb:52:in `timeout'
from /usr/local/lib/ruby/2.0.0/net/http.rb:918:in `block in connect'
from /usr/local/lib/ruby/2.0.0/net/http.rb:918:in `connect'
esilver
  • 27,713
  • 23
  • 122
  • 168
  • This actually means that server exists and acccepts the request, but doesn’t return data, still keeping a connection open. Yes, in a case of such a malicious server the client will hang up. – Aleksei Matiushkin Dec 08 '13 at 05:47
  • Are there any Net::HTTP configurations in which the client would never hang up / timeout? – esilver Dec 08 '13 at 05:52
  • Uhmm… Setting `open_timeout` is looking like a solution. You may also monkey-patch the original code to set `open_timeout` to non-nil value. But out of the box `Net:HTTP` is a library; it has no config file and it provides mechanisms for waiting undefinitely (e. g. for long server-side processing.) – Aleksei Matiushkin Dec 08 '13 at 05:55
  • It’s interesting… I digged a bit into and I’d suggest it’s not a `Net::HTTP` problem. Matz has already had [problems](http://bogomips.org/ruby.git/commit/?h=ssl-memory&id=4a9883e92f856bf7db773e0ddc72f17a8662b75a) with `rb_wait_for_single_fd` calls. It actually looks like deadlock inside ruby thread synching, not like a server hangup. – Aleksei Matiushkin Dec 08 '13 at 06:03
  • @mudasobwa ok something bad like deadlock makes more sense to me...it seems kind of crazy that any networking library would allow a client to perform a network operation without using some kind of default timeout (I feel like it's usually 60 seconds...) – esilver Dec 08 '13 at 06:06
  • A server is malicious because it doesn't respond? I'd say it's down or you've found a bug in that case, not malicious. – the Tin Man Dec 08 '13 at 06:30
  • I think the server in this case is an amazon instance in a security group that doesn't allow incoming connections. – esilver Dec 08 '13 at 06:37
  • @theTinMan If the server is down there will be `Connection refused - connect(2) (Errno::ECONNREFUSED)` raised immediately. – Aleksei Matiushkin Dec 08 '13 at 06:39
  • @esilver No, there is **no** default timeout in `Net::HTTP`. In normal scenario it will receive `HTTPRequestTimeOut` response (which server is on duty of.) If you feel there might be any problem, you set the timeout yourself. But sometimes you really need to wait infinitely (server is processing large amount of data and you know it.) I personally use (internally, of course) some server-side image processing, which may take up to an hour and I use `Net::HTTP` w/out setting any timeout. – Aleksei Matiushkin Dec 08 '13 at 06:40
  • @mudasobwa ok thanks. Interesting, guess that explains the issue I ran into. Please reply to this question and I will accept when I wake up tomorrow. Thanks! – esilver Dec 08 '13 at 07:13

1 Answers1

2

This actually means that server exists and accepts the request, but doesn’t return data, still keeping a connection open. Yes, in a case of such a malicious server the client will hang up.

There is no default timeout in Net::HTTP. In normal scenario it will receive HTTPRequestTimeOut response (which server is on duty of.) If you feel there might be any problem, you set the timeout yourself. But sometimes you really need to wait infinitely (server is processing large amount of data and you know it.)

Actually, I’d suggest it’s not a Net::HTTP problem. Matz has already had problems with rb_wait_for_single_fd calls. It actually looks like deadlock inside ruby thread synching, not like a server hangup.

Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160