IO+ vs IO from a request.body

I have the following code.

        if( request.method == "POST" )
            if body = request.body
                HTTP::Client.post("x.x.x.x:9001" + request.path, body ) do |response_client|
                   IO.copy(response_client.body_io, response)
                end
            end
        end

I expect by assigning the request.body ( IO, Nil ), that body will contain ( IO ). So i can pass body to a other client. But body is now (IO+), what gets rejected by HTTP::Client.post ( expecting IO ).

Is this a bug ( missing IO+ receiver for HTTP::Client.post?) or my misunderstanding?

IO is the same as IO+, it’s just an internal representation of something else that shouldn’t be exposed. Can you post some code that reproduces the bug?

Already solved this issue last night.

Here is the example that will fail:

require "http/server"

server = HTTP::Server.new(
    [ HTTP::ErrorHandler.new, HTTP::LogHandler.new, HTTP::CompressHandler.new, HTTP::StaticFileHandler.new("./files", true, false),]
    ) do |context|
    response = context.response
    request = context.request

    if( request.method == "POST" )
        if body = request.body
            HTTP::Client.post("x.x.x.x:9002" + request.path, body ) do |response_client|
               IO.copy(response_client.body_io, response)
            end
        end
    end
end

server.listen("x.x.x.x", 9001, reuse_port: true)

Results in:

Error in test2.cr:12: no overload matches 'HTTP::Client.post' with types String, IO+
Overloads are:
 - HTTP::Client.post(url : String | URI, headers : HTTP::Headers | ::Nil = nil, body : BodyType = nil, tls = nil)
 - HTTP::Client.post(url : String | URI, headers : HTTP::Headers | ::Nil = nil, body : BodyType = nil, tls = nil, &block)
 - HTTP::Client.post(url, headers : HTTP::Headers | ::Nil = nil, tls = nil, *, form : String | IO | Hash)
 - HTTP::Client.post(url, headers : HTTP::Headers | ::Nil = nil, tls = nil, *, form : String | IO | Hash, &block)

                HTTP::Client.post("192.168.222.129:9001" + request.path, body ) do |response_client|
                             ^~~~

The issue is:

HTTP::Client.post("x.x.x.x:9002" + request.path, body ) 

needs to be:

HTTP::Client.post("x.x.x.x:9002" + request.path, nil, body ) 

Because the second parameter is actually the header. Its unclear in that wall of text ( that is not even that bad, i have before with ( IO/Nil ) when directly pushing the body, maybe 15 different overloads being presented ).

My confusion started with the examples in the documentation:

https://crystal-lang.org/api/0.24.1/HTTP/Client.html

response = HTTP::Client.post "http://www.example.com", form: "foo=bar"

What made it seem that the forms is a second parameter value.

So it was me mistaking the documentation and the actual error code.

I do like to point out, that the documentation is the wrong version ( 0.24.1) as Google search send me to the correct page but the wrong Crystal documentation version ( 0.24.1 ).