New issue

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

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebMock does not support matching body for multipart/form-data #623

Open
bootstraponline opened this Issue May 27, 2016 · 14 comments

Comments

Projects
None yet
7 participants
@bootstraponline

bootstraponline commented May 27, 2016

ArgumentError: WebMock does not support matching body for multipart/form-data requests yet :(

:(

Is there an open issue for this?

@bblimke

This comment has been minimized.

Owner

bblimke commented May 30, 2016

No there isn't.

It's not easy to fix (that's why it hasn't been fixed yet :). Direct body matching won't work as body parts boundaries change on each requested. The only way to handle that would be to split parts and match each of them.

If someone has any idea how to deal with it, a pull request is always welcome.

@chadcf

This comment has been minimized.

chadcf commented Jun 10, 2016

Out of curiosity, what used to happen, did it just ignore the body? I ask as we had a bunch of passing tests and after updating to webmock 2.x I started getting this error and the tests started failing, so I'm curious what the proper way to emulate the previous behavior is (I'm guessing just removing the body match).

@bblimke

This comment has been minimized.

Owner

bblimke commented Jun 10, 2016

@chadcf matching multipart body was never supported and never worked.

The error messages were unclear so the assertion has been added to 2.x recently,
which raises an error on an attempt to match multipart body.

I'm surprised that it used to work for you before. How have you been matching the body?

@chadcf

This comment has been minimized.

chadcf commented Jun 10, 2016

yes I was pretty surprised too!

I just updated the app from 1.18 to 2.1.0 and these stubs which used to work started throwing the error:

  stub_request(:post, url)
  .with(headers: { "Content-Type" => %r[multipart/form-data] })
  .with(body: %r[#{Regexp.escape attachment_data.read}])
@bblimke

This comment has been minimized.

Owner

bblimke commented Jun 10, 2016

I see. Yes, regexp would have worked before as it doesn't care about boundaries.

Perhaps the error should be raised only if trying to match body against hash.

@sshaw

This comment has been minimized.

sshaw commented Jan 3, 2017

You can use the block form:

stub_request(:post, "http://example.com").
      with(:headers => { "Content-Type" => %r|\Amultipart/form-data| }) { |request| request.body =~ /some-part-of-body/ }

Works for me under 2.3.2.

@bblimke

This comment has been minimized.

Owner

bblimke commented Jan 3, 2017

@sshaw it works only because most likely your http client creates part boundary strings which are the same for every request, therefore the generated body is always the same.
This can't be guaranteed though as various clients will generate different boundary strings and these strings can be different across requests.

@sshaw

This comment has been minimized.

sshaw commented Jan 3, 2017

It only works because I'm using a regex and not trying to match an entire part, just contents. Boundary string is not relevant . (Maybe regex can be update to indicate this better?)

@bblimke

This comment has been minimized.

Owner

bblimke commented Jan 3, 2017

@sshaw

This comment has been minimized.

sshaw commented Jan 3, 2017

You can use regexp to match body without a block. Webmock supports body to
be declared as regexp.

Not for multipart/for-data (hence this issue). It results in: ArgumentError: WebMock does not support matching body for multipart/form-data requests yet

Using 2.3.2.

😿

@russell

This comment has been minimized.

russell commented Jun 12, 2017

With 3.0.1 and 2.3.2 I notice that when trying to follow one of the examples above if I try test with

    stub_request(:post, 'http://mockserver.com/api/v2/')
      .with(body: %r[.*],
            headers: default_headers('Authorization' => 'Basic ZblahC5jb236cGFzcblah=',
                                     'Content-Length' => '258',
                                     'Content-Type' => 'multipart/form-data; boundary=-----------RubyMultipartPost')) do |request|
      boundry = Regexp.quote(request.headers['Content-Type'][/ boundary=(.+)/, 1])
      request.body == %r{
      start
      -------------#{boundary}\r\nContent-Disposition: form-data; name=\"file\"; filename=\"test_file\"\r\nContent-Length: 38\r\nContent-Type: image/jpeg\r\nContent-Transfer-Encoding: binary\r\n\r\nPellentesque dapibus suscipit ligula.\n\r\n-------------#{boundary}--\r\n\r\n
      end
      }x
    end.to_return(status: 200, body: '', headers: {})

I get

     ArgumentError:
       WebMock does not support matching body for multipart/form-data requests yet :(
     # /Users/rsim/.gem/ruby/2.2.3/gems/webmock-2.3.2/lib/webmock/request_pattern.rb:263:in `assert_non_multipart_body'
     # /Users/rsim/.gem/ruby/2.2.3/gems/webmock-2.3.2/lib/webmock/request_pattern.rb:231:in `matches?'
     # /Users/rsim/.gem/ruby/2.2.3/gems/webmock-2.3.2/lib/webmock/request_pattern.rb:34:in `matches?'
     # /Users/rsim/.gem/ruby/2.2.3/gems/webmock-2.3.2/lib/webmock/stub_registry.rb:58:in `block in request_stub_for'
     # /Users/rsim/.gem/ruby/2.2.3/gems/webmock-2.3.2/lib/webmock/stub_registry.rb:57:in `each'
     # /Users/rsim/.gem/ruby/2.2.3/gems/webmock-2.3.2/lib/webmock/stub_registry.rb:57:in `detect'
     # /Users/rsim/.gem/ruby/2.2.3/gems/webmock-2.3.2/lib/webmock/stub_registry.rb:57:in `request_stub_for'
     # /Users/rsim/.gem/ruby/2.2.3/gems/webmock-2.3.2/lib/webmock/stub_registry.rb:50:in `response_for_request'
     # /Users/rsim/.gem/ruby/2.2.3/gems/webmock-2.3.2/lib/webmock/http_lib_adapters/net_http.rb:79:in `request'

And if i omit the body section from the with call, then i get WebMock::NetConnectNotAllowedError where it shows that there is a mock endpoint is registered but it dosen't match the multipart one. The only difference I can see is the body doesn't exist for the stub.

@bblimke

This comment has been minimized.

Owner

bblimke commented Jun 17, 2017

@russell it's because of this part .with(body: %r[.*], please remove body: %r[.*] completely.
It's not necessary since you are matching body inside the block anyway.

@cbliard

This comment has been minimized.

cbliard commented Jul 19, 2017

I also upgraded to 3.0.1 recently, and tests began to fail with this error too. My test was to ensure that two files were sent, like so:

expect(a_request(:post, "https://domain.com/").
  with(:body => (a_string_matching(/Content-Disposition: form-data;.+ filename="result1.tap"/).
             and a_string_matching(/Content-Disposition: form-data;.+ filename="result2.tap"/)),
       :headers => {'Content-Type' => 'multipart/form-data; boundary=-----------RubyMultipartPost'})
  ).to have_been_made

I had to rewrite it like this to prevent raising the exception

expect(a_request(:post, "https://domain.com/").
  with { |req|
    expect(req.body).to match(/Content-Disposition: form-data;.+ filename="result1.tap"/).
                    and match(/Content-Disposition: form-data;.+ filename="result2.tap"/)
    expect(req.headers).to include('Content-Type' => 'multipart/form-data; boundary=-----------RubyMultipartPost')
  }).to have_been_made
@ukd1

This comment has been minimized.

ukd1 commented Aug 10, 2017

also getting this when upgrading to ruby and upgrading this lib.

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