Last Update: 2023-01-25 08:07:21 +0000



Response::Body#to_s does not clear the internal buffer

It’s well documented that the response body should be treated as a file, and that calling .to_s on a response should be done only once, and the user should not expect the same call to return the same response body again, while suggesting that the first call should be cached in a variable in case it’s needed:

response = HTTPX.get("https://google.com")
body = response.body.to_s #=> "<html ...."
response.body.to_s #=> ""

# thankfully,it's cached in the body var there.

The justification for this behaviour probably had to do with avoiding keeping huge payloads around, but it got a bit lost in git history. It became a feature, not a bug.

However, I got an issue report that made me change my mind about this behaviour (tl;dr: it broke pattern matching when matching against response bodies more than once).

So now, you can call .to_s how many times you want!

response = HTTPX.get("https://google.com")
body = response.body.to_s #=> "<html ...."
response.body.to_s #=> "<html ....", still here!

Some optimizations were done around how the body is carried forward, and bodies buffered in files will now get properly garbage collected and not leak descriptors behind when users forget to call .close.

grpc plugin improvements

build fully-enabled stub from grpc service

The :grpc plugin can now build fully-loaded stubs from existing GRPC generic services.

GRPC stubs could be a bit tedious to write when compared to what the grpc gem offers, which is, auto-generation from ruby service stubs from protobuf definitions:

# service generated from the command:
# > grpc_tools_ruby_protoc -I ../../protos --ruby_out=../lib --grpc_out=../lib ../../protos/route_guide.proto
require "route_guide_services_pb.rb"

# with httpx, before 0.16
stub = HTTPX.plugin(:grpc).build_stub("localhost:#{server_port}", service: "RouteGuide")
                          .rpc(:GetFeature, Point, Feature)
                          .rpc(:ListFeatures, # ... and so on, all hand stitched

stub.get_feature(# ...

# with httpx 0.16
stub = HTTPX.plugin(:grpc).build_stub("localhost:#{server_port}", service: RouteGuide)
# that's it!
stub.get_feature(# ...

no google/protobuf direct dependency

"google/protobuf" is no longer assumed when using the plugin, i.e. you can use other protobuf serializers, such as github.com/ruby-protobuf/protobuf , which supports jruby (unlike the former).

OptionsMethods for plugins


You can now define an OptionsMethods module under your custom plugin to define your own methods. The tl;dr is, that, given the following module below, a new :bar option will be available (and the method will be used to set it):

module CustomPlugin
  module OptionsMethods
    def option_bar(x) ; x; end

HTTPX.plugin(CustomPlugin).with(bar: 2)

cookies plugin: improved jar management

The behaviour of the cookies jar from the :cookies plugin was a bit unpredictable in certain conditions, for instance if a “Cookie” header would be passed directly via .with(headers: {"Cookie" => "a=1"}) and there’d be a value for it already (in same cases, it’d be fully ignored). This would even get worse, if the session had a jar, and a specific set of cookies would be passed to a request(i.e.: session_with_cookies.get("http://url.get", headers: {"Cookies" => "..."}).

The behaviour was fixed, and is now specced under gitlab.com/os85/httpx/-/blob/master/test/support/requests/plugins/cookies.rb .


  • Cookies sorting in the :cookies plugin jar was fixed for truffleruby;


  • errors when setting options nnow raise TypeError instead of HTTPX::Error.

  • options are now internally frozen by default, which should protect the internals against accidentally updating them;

  • Fixed optimization around options initialization, to prevent needless allocations;