Project

General

Profile

Actions

Feature #13396

closed

Net::HTTP has no write timeout

Added by byroot (Jean Boussier) about 5 years ago. Updated about 1 year ago.

Status:
Closed
Priority:
Normal
Target version:
-
[ruby-core:80542]

Description

When sending a large request to an unresponsive server, Net::HTTP can hang pretty much forever.

# server.rb
require 'socket'

server = TCPServer.new('localhost', 2345)
loop do
  socket = server.accept
end

# client.rb
require 'net/http'

connection = Net::HTTP.new('localhost', 2345)
connection.open_timeout = 1
connection.read_timeout = 3
connection.start

post = Net::HTTP::Post.new('/')
body = (('a' * 1023) + "\n") * 5_000
post.body = body

puts "Sending #{body.bytesize} bytes"
connection.request(post)

The above code will hang forever on all system I tested it on (OSX / Linux 3.19).

The issue only trigger once the request body is above a certain threshold. That threshold depends on the system, I assume it's due to the system's TCP settings, but a request over 4MB will trigger the issue consistently.

I assume it happens when the request is bigger than the socket buffer.

It's stuck on the following path:

/net/protocol.rb:211:in `write': Interrupt
/net/protocol.rb:211:in `write0'
/net/protocol.rb:185:in `block in write'
/net/protocol.rb:202:in `writing'
/net/protocol.rb:184:in `write'
/net/http/generic_request.rb:188:in `send_request_with_body'
/net/http/generic_request.rb:121:in `exec'
/net/http.rb:1435:in `block in transport_request'
/net/http.rb:1434:in `catch'
/net/http.rb:1434:in `transport_request'
/net/http.rb:1407:in `request'

I tried setting setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, ...) on the client socket, but without success. However adding a Timeout.timeout call around req.exec did work.

Actions

Also available in: Atom PDF