Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Coolio::HttpClient never calls on_request_complete #15

Closed
bluezi opened this Issue Jul 12, 2011 · 1 comment

Comments

Projects
None yet
3 participants

bluezi commented Jul 12, 2011

When a non chunked-encoding response lacks a Content-Length header, Coolio::HttpClient keeps instance variable, state, equal to :body. (See HttpClient#dispatch and HttpClient#process_body) It does so even when there is no more data to process, IE: the state variable never transitions to :finished.

Example:

class MyHttp < Coolio::HttpClient
attr_reader :response_body, :response_header
def on_response_header(header)
puts "response status: #{header.status}"
end
def on_body_data(data)
@response_body ||= ""
@response_body << data
end
def on_request_complete
puts "HTTP FINISHED"
end
def on_error(reason)
puts "error: #{reason}"
end
end

l = Coolio::Loop.default
http = MyHttp.connect("www.google.com", 80).attach(l)
http.request("GET", '/')
l.run

outputs:
response status: 200

note:

http.response_body.size # => 9922
http.response_header.keys.include? "CONTENT_LENGTH" # => false

Contributor

dnwade commented Jul 17, 2011

I can confirm this error. Here are three examples using your subclass:

l = Coolio::Loop.default
msn = MyHttp.connect("www.msn.com").attach(l)
msn.request("GET", '/')
l.run

This prints "HTTP FINISHED". The response_header contains a "content-length" header (and no "transfer-encoding: chunked" header).

l = Coolio::Loop.default
ip = MyHttp.connect("jsonip.com).attach(l)
ip.request("GET", '/')
l.run

This too prints "HTTP FINISHED". There is a "transfer-encoding: chunked" header present (but no "content-length" header).

Finally, trying your "www.google.com" example does not print "HTTP FINISHED", i.e.: on_request_complete is not called. And both those headers are not defined.

I think this problem can be traced to the following source from Coolio::HttpClient#process_body (cool.io/http_client.rb):

  if @bytes_remaining.nil?
    on_body_data @data.read
    return false
  end

This code is evaluated if and only if the server has not set both the "Transfer-Encoding: chunked" header and the "Content-Length" header since Coolio::HttpClient sets @bytes_remaining to nil. Hence, @State is never changed from :body to :finished and on_request_complete never gets called.

One work around would be to set a callback that calls on_request_complete whenever the server closes the TCP connection and those two HTTP headers are unset. I'm not entirely sure about the correct way to do this with the Coolio API though.

Would you define HttpClient#on_close? If so, how?

@tarcieri tarcieri closed this in 29a1f68 Aug 10, 2011

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment