Skip to content
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

RawPostDataException when trying to test IPN #79

Closed
dantium opened this issue Feb 12, 2015 · 7 comments · Fixed by #152
Closed

RawPostDataException when trying to test IPN #79

dantium opened this issue Feb 12, 2015 · 7 comments · Fixed by #152

Comments

@dantium
Copy link

dantium commented Feb 12, 2015

I am using the chrome plugin Postman to try and test the IPN callback on my localhost. When posting to the callback URL I am getting a RawPostDataException error "You cannot access body after reading from request's data stream"

Am I doing something wrong here or is there a better why to test the IPN callback locally? Thanks

@spookylukey
Copy link
Owner

spookylukey commented Feb 12, 2015

You'll need to paste the complete traceback. Thanks!

I suspect you have something (e.g. middleware or custom view logic) that is reading the request data, instead of letting the ipn view do that.

You can use the PayPal sandbox and something like ngrok to test locally.

@spookylukey
Copy link
Owner

I can't do anything without a traceback, so closing. Please reopen if you can provide more information.

@asfaltboy
Copy link
Contributor

asfaltboy commented Jun 22, 2016

I just encountered the same issue and would like to share my insights and the workaround.

tl;dr django.test.Client requests default to the Content-Type=multipart/form-data, this prevents the ipn view from accessing request.body after it accesses request.POST. To work around it, pass a non-multipart content_type:

client = django.test.Client()
client.post(reverse('paypal-ipn'), data=ipn_data, content_type='application/x-www-form-urlencoded')

I found the issue encode/django-rest-framework#2774 extremely useful when debugging.

It is mentioned by Preston Holmes in a comment that Django prevents reading a body of a request with the multipart/form-data content type because "we don't want to repeat the expensive operation of parsing the multipart data".

While I'm fairly happy with the workaround, I'd hate to waste other users' time. So I would suggest we either:

  1. Catch the RawPostDataException in the view (add try/except ~ L45 and present a sane error which states we expect the POST to have Content-Type: application/x-www-form-urlencoded, and it is something else).
  2. Copy the request.POST/body before the first call and use the copy thereafter.

@spookylukey please let me know if you'd like to see a PR for either.

On a side note, it would be very helpful if Django docs mention the above behavior. I could not find mention of this anywhere besides this related middleware warning. Though the docstring added in this commit is very informative; I would go ahead and copy paste this directly to a warning in HttpRequest docs. I've expressed my last paragraph in this Django ticket.

@spookylukey
Copy link
Owner

Given that the PayPal docs explicitly show x-www-form-urlencoded (see https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNIntro/#a-sample-ipn-message-and-response ) I think the best option here is to first check that the Content-Type matches that, and raise an exception otherwise. This avoids using internals like RawPostDataException

@spookylukey spookylukey reopened this Jun 23, 2016
@asfaltboy
Copy link
Contributor

asfaltboy commented Jun 23, 2016

@spookylukey thanks for the quick response. I honestly couldn't find any mention (in quoted docs or any others) of the headers paypal sends. Right now however, the value of Content-Type is clearly x-www-form-urlencoded as can be seen by issuing a IPN Simulator request. And raising an exception if the behavior changes is a good way as any to handle this.

@jTiKey
Copy link
Contributor

jTiKey commented Jan 1, 2018

Is there a possibility this was changes recently? The server is getting many errors on the live server:
AssertionError: Invalid Content-Type - PayPal is only expected to use application/x-www-form-urlencoded. If using django's test Client, set content_type explicitly

@spookylukey
Copy link
Owner

@jTiKey If PayPal changed the data to no longer match what their docs show - https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNIntro/#a-sample-ipn-message-and-response - then you should take it up with them. I don't know if they have changed anything recently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants