diff --git a/lib/rollbar/request_data_extractor.rb b/lib/rollbar/request_data_extractor.rb index 24e755d9..356637bd 100644 --- a/lib/rollbar/request_data_extractor.rb +++ b/lib/rollbar/request_data_extractor.rb @@ -214,7 +214,7 @@ def rollbar_raw_body_params(rack_req) return {} unless correct_method return {} unless json_request?(rack_req) - raw_body = rack_req.body.read + raw_body = read_raw_body(rack_req.body) begin Rollbar::JSON.load(raw_body) rescue StandardError @@ -222,8 +222,15 @@ def rollbar_raw_body_params(rack_req) end rescue StandardError {} - ensure - rack_req.body.rewind + end + + def read_raw_body(body) + return {} unless body.respond_to?(:rewind) + + body.rewind + raw_body = body.read + body.rewind + raw_body end def json_request?(rack_req) diff --git a/spec/rollbar/request_data_extractor_spec.rb b/spec/rollbar/request_data_extractor_spec.rb index c080d31b..0e9fc458 100644 --- a/spec/rollbar/request_data_extractor_spec.rb +++ b/spec/rollbar/request_data_extractor_spec.rb @@ -354,6 +354,47 @@ class ExtractorDummy end end + context 'with non-rewindable input' do + let(:params) { { 'key' => 'value' } } + let(:body) { params.to_json } + let(:env) do + Rack::MockRequest.env_for('/?foo=bar', + 'CONTENT_TYPE' => 'application/json', + :method => 'POST') + end + + # According to Rack 3.0 "The input stream must respond to gets, each, and read" + # https://github.com/rack/rack/blob/3.0.0/SPEC.rdoc#the-input-stream- + let(:non_rewindable_input) do + Class.new do + def initialize(body) + @body = body + end + + def gets + @body + end + + def read + @body + end + + def each + yield(@body) + end + end + end + + before do + env['rack.input'] = non_rewindable_input.new(body) + end + + it 'skips extracting the body' do + result = subject.extract_request_data_from_rack(env) + expect(result[:body]).to be_eql('{}') + end + end + context 'with POST params' do let(:params) { { 'key' => 'value' } } let(:env) do