Sometimes it's easier to just hex edit the assembly
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.