paypal ipn returns invalid

When migrating a PayPal IPN script from classic asp to a .net generic handler everything worked fine until the contents of the data posted to the script by PayPal contained a special characters, in this particular instance a pound sign.

The problem lay with the creation of the response sent back to PayPal :

Classic asp:

Dim strResponse
strResponse = Request.Form & "&cmd=_notify-validate"
Dim objHttp
set objHttp = Server.CreateObject("Msxml2.ServerXMLHTTP") "POST", "", false
objHttp.setRequestHeader "Content-type", "application/x-www-form-urlencoded"
objHttp.Send strResponse
Dim responseText : responseText = objHttp.responseText

This works fine

.net generic handler:

Dim strResponse as String
strResponse = context.Request.Form.ToString & "&cmd=_notify-validate"
Dim httpRequest As New Net.WebClient
Dim responseText As String = ""
httpRequest.Headers.Add("Content-Type", "application/x-www-form-urlencoded")
responseText = httpRequest.UploadString("", strResponse)

This works fine, until you try and send a special character

After a bit of investigation it turns out that Request. Form collection is not passed in the the same way for classic asp and .net even though they generally behave in the same way and can both be converted to a single string (as above). The key difference is in the way that unencoded special characters are handled, in the case classic asp they are urlencoded for you, so a £ sign is encoded to %A3, however, .net will replace the £ sign with %ufffd which is a replacement for a character whose value is unknown.

As a result of this difference when we try and send back to PayPal the contents of a form that has special characters in it from a .net page it no longer matches to what we were sent in the first place as the £ signs (in this instance) have been swapped for unknown character symbols, and PayPal return INVALID.

The way around this problem is to use Request.BinaryRead....

Swap this:

strResponse = context.Request.Form.ToString & "&cmd=_notify-validate"

for this:

strResponse = Text.Encoding.ASCII.GetString(context.Request.BinaryRead(context.Request.ContentLength)) & "&cmd=_notify-validate"

By using Request.BinaryRead we have access to the original form data that was posted to us before .net can change the unencoded characters to be the unknown character symbol.

Post a comment