Summary
PalPal's Single Item Purchase links are not technically valid - the query
portion of the URL doesn't start with a question mark. This confuses
ASP.NET 2.0's Response.Redirect(url) call, which causes the return URL to be
malformed. Rather than spend dozens of hours upgrading to the newest version of
the store software, I spent 15 minutes with Reflector, WinMerge, and a hex
editor to modify the .NET assembly.
The Obligatory Human Interest Back Story
I'd been working on setting up an e-commerce site for my wife for a long
time. The first version ran on ZenCart, a fork of the popular osCommerce PHP /
MySql system. The PayPal integration never really worked, and I decided to spend
a few bucks and switch to what I know - ASP.NET.
The
second version of the site is built on DotNetNuke with the CATALooK
store module. We went with DNN for the admin and editing features, so
once it's up and running she can run it by herself. We looked at several store
modules, including the official
DotNetNuke Store Module, and found that CATALook is way ahead of all the
other stores and very reasonably priced (The CATALooK support alone has
been worth the price).
We put a huge amount of effort into a new skin that uses clean (table
free) HTML, although the DNN modules spew so many tables it feels pointless
at times. The hardest part was removing the formatting from the
CATALooK modules, since many of them used the XML skins approach. Finally
it was done, and we placed a test order...
It went through, but the return link from PayPal to our site was broken.
The querystring parameters were incorrect, and the URL began with
http:/ rather than http://. Problems with PayPal integration - deja
vu, huh? This time, though, I had a support contact. They immediately got back
to me and told me it had to do with ASP.NET 2.0's handling of the PayPal link;
the new version of CATALook (just released) would fix it. The new version
did indeed fix the problem with PayPal.
Unfortunately, this version was the time that the CATALooK folks decided to
convert the skinning model from XML based skins to ASCX based skins. While I
vastly prefer ASCX based skins, the this wasn't a convenient time for me to
spend a lot of time converting my skins. I gave it a shot, but the conversion
process didn't go smoothly. My wife and I were lamenting the fact that we had to
put off launching her 99% complete site to complete a difficult upgrade when all
we really needed was a tiny part of the new version - the fix to the PayPal
redirect. "We're going to have to do all this work just to change a few
characters," I said.
Hey, that gives me an idea...
Technical Background on the Problem
The problem is both PayPal and .NET's fault. PayPal's Single Item Purchase /
Buy Now [pdf] links
are not (as I read RFC
3986) valid URL's. Here's an example; note that the query portion of
the URL (starting with business=store@test.com...) isn't
prefixed with a question mark (?), it's prefixed with a forward slash
(/):
https://www.paypal.com/xclick/business=store@test.com&item_name=Baseball+Hat&item_number=123&amount=5.95&return=http%3A//www.test.com/thankyou.htm
It looks like there's a bug in the System.Uri.CombineUri()
function which is called by Response.Redirect(). It looks for a substring of ?
to figure out where the query portion of the url starts, doesn't find it, and
processes the entire URL as if it had no query. I understand that it's being
broken by a malformed URL, but I'd still like it to fail a little more
gracefully.
Anyhow, the solution is to use an alternate Buy Now link format which
replaces that last slash with a quesion mark:
https://www.paypal.com/xclick?business=store@test.com&item_name=Baseball+Hat&item_number=123&amount=5.95&return=http%3A//www.test.com/thankyou.htm
Armed with that knowledge, I was able to find that exact bug fix in the
store system's via Reflector very quickly.
Could it really work?
I assumed that I'd need to disassemble
and recompile the assembly, but luckily the entire URL was set as a string
constant. On the off-chance it might work, I opened the assembly in a hex
editor. I used the hex editor which is built into Notepad++, which
totally rocks. First I searched for "xclick", but I didn't find it. I was pretty
sure it was there, since Reflector had shown it, so I converted it to
UTF-16:
- Bring up the find dialog
- Enter "xclick" (of course, any search string could be sustituted here)
- Changed the datatype from "String" to "Hex Pattern"
- Inserted 00 values after every hex pair, so "78636c69636b" became
"780063006c00690063006b00"
- Tried the search again
Sure enough, that got it. I changed the following character from a forward
slash to a question mark, saved, and tested. That got it - I was able to stay on
my current release of the software, but I had my one character bug fix.
Disclaimers
Of course, if the DLL had been signed I'd have been out of luck, but
fortunately it wasn't and all was good. Yes, I should upgrade to the new
version of the store software as soon as possible, but I was happy to be able to
decouple PayPal bugfix from the skin system change.