Skip to content

Commit

Permalink
Merge pull request #438 from janko-m/make-request-body-source-accessible
Browse files Browse the repository at this point in the history
Add Request::Body#source
  • Loading branch information
ixti authored Nov 13, 2017
2 parents 4acadb5 + 9a28682 commit 70658da
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 36 deletions.
24 changes: 10 additions & 14 deletions lib/http/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ def initialize(opts)
raise(UnsupportedSchemeError, "unknown scheme: #{scheme}") unless SCHEMES.include?(@scheme)

@proxy = opts[:proxy] || {}
@body = request_body(opts[:body], opts)
@body = Request::Body.new(opts[:body])
@deflate = opts[:auto_deflate]
@version = opts[:version] || "1.1"
@headers = HTTP::Headers.coerce(opts[:headers] || {})

Expand All @@ -100,18 +101,20 @@ def redirect(uri, verb = @verb)
headers.delete(Headers::HOST)

self.class.new(
:verb => verb,
:uri => @uri.join(uri),
:headers => headers,
:proxy => proxy,
:body => body,
:version => version
:verb => verb,
:uri => @uri.join(uri),
:headers => headers,
:proxy => proxy,
:body => body.source,
:auto_deflate => @deflate,
:version => version
)
end

# Stream the request to a socket
def stream(socket)
include_proxy_headers if using_proxy? && !@uri.https?
body = @deflate ? @deflate.deflated_body(self.body) : self.body
Request::Writer.new(socket, body, headers, headline).stream
end

Expand Down Expand Up @@ -186,13 +189,6 @@ def socket_port

private

# Transforms body to an object suitable for streaming.
def request_body(body, opts)
body = Request::Body.new(body) unless body.is_a?(Request::Body)
body = opts[:auto_deflate].deflated_body(body) if opts[:auto_deflate]
body
end

# @!attribute [r] host
# @return [String]
def_delegator :@uri, :host
Expand Down
51 changes: 29 additions & 22 deletions lib/http/request/body.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,57 @@
module HTTP
class Request
class Body
def initialize(body)
@body = body
attr_reader :source

validate_body_type!
def initialize(source)
@source = source

validate_source_type!
end

# Returns size which should be used for the "Content-Length" header.
#
# @return [Integer]
def size
if @body.is_a?(String)
@body.bytesize
elsif @body.respond_to?(:read)
raise RequestError, "IO object must respond to #size" unless @body.respond_to?(:size)
@body.size
elsif @body.nil?
if @source.is_a?(String)
@source.bytesize
elsif @source.respond_to?(:read)
raise RequestError, "IO object must respond to #size" unless @source.respond_to?(:size)
@source.size
elsif @source.nil?
0
else
raise RequestError, "cannot determine size of body: #{@body.inspect}"
raise RequestError, "cannot determine size of body: #{@source.inspect}"
end
end

# Yields chunks of content to be streamed to the request body.
#
# @yieldparam [String]
def each(&block)
if @body.is_a?(String)
yield @body
elsif @body.respond_to?(:read)
IO.copy_stream(@body, ProcIO.new(block))
elsif @body.is_a?(Enumerable)
@body.each(&block)
if @source.is_a?(String)
yield @source
elsif @source.respond_to?(:read)
IO.copy_stream(@source, ProcIO.new(block))
elsif @source.is_a?(Enumerable)
@source.each(&block)
end
end

# Request bodies are equivalent when they have the same source.
def ==(other)
self.class == other.class && self.source == other.source # rubocop:disable Style/RedundantSelf
end

private

def validate_body_type!
return if @body.is_a?(String)
return if @body.respond_to?(:read)
return if @body.is_a?(Enumerable)
return if @body.nil?
def validate_source_type!
return if @source.is_a?(String)
return if @source.respond_to?(:read)
return if @source.is_a?(Enumerable)
return if @source.nil?

raise RequestError, "body of wrong type: #{@body.class}"
raise RequestError, "body of wrong type: #{@source.class}"
end

# This class provides a "writable IO" wrapper around a proc object, with
Expand Down
35 changes: 35 additions & 0 deletions spec/lib/http/request/body_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@
end
end

describe "#source" do
it "returns the original object" do
expect(subject.source).to eq ""
end
end

describe "#size" do
context "when body is nil" do
let(:body) { nil }
Expand Down Expand Up @@ -135,4 +141,33 @@
end
end
end

describe "#==" do
context "when sources are equivalent" do
let(:body1) { HTTP::Request::Body.new("content") }
let(:body2) { HTTP::Request::Body.new("content") }

it "returns true" do
expect(body1).to eq body2
end
end

context "when sources are not equivalent" do
let(:body1) { HTTP::Request::Body.new("content") }
let(:body2) { HTTP::Request::Body.new(nil) }

it "returns false" do
expect(body1).not_to eq body2
end
end

context "when objects are not of the same class" do
let(:body1) { HTTP::Request::Body.new("content") }
let(:body2) { "content" }

it "returns false" do
expect(body1).not_to eq body2
end
end
end
end

0 comments on commit 70658da

Please sign in to comment.