From 60004f2ad58e2b820d1893bdc8cefd79d988ee01 Mon Sep 17 00:00:00 2001 From: shlurbee Date: Fri, 6 Jul 2012 14:31:36 -0700 Subject: [PATCH] Fix encoding and do escaping in authorize.net xml - Escapes &, <, and > except in extraOptions tags, which need to allow special characters - Encodes string as UTF-8 before sending it over the wire - Replaces xml entities in responses with the correct chars This change should fix some of the 500 server errors people were getting when they had unusual characters in their payment info. --- r2/r2/lib/authorize/api.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/r2/r2/lib/authorize/api.py b/r2/r2/lib/authorize/api.py index 71e79732e..69319a2c4 100644 --- a/r2/r2/lib/authorize/api.py +++ b/r2/r2/lib/authorize/api.py @@ -37,6 +37,8 @@ from r2.lib.utils import iters, Storage from r2.models import NotFound from r2.models.bidding import CustomerID, PayID, ShippingAddress +from xml.sax.saxutils import escape + # list of the most common errors. Errors = Storage(TESTMODE = "E00009", TRANSACTION_FAIL = "E00027", @@ -49,6 +51,9 @@ class AuthorizeNetException(Exception): pass +# xml tags whose content shouldn't be escaped +_no_escape_list = ["extraOptions"] + class SimpleXMLObject(object): """ All API transactions are done with authorize.net using XML, so @@ -74,6 +79,10 @@ class SimpleXMLObject(object): def process(k, v): if isinstance(v, SimpleXMLObject): v = v.toXML() + elif v is not None: + v = unicode(v) + if k not in _no_escape_list: + v = escape(v) # escape &, <, and > if v is not None: content.append(self.simple_tag(k, v)) @@ -213,7 +222,7 @@ class AuthorizeNetRequest(SimpleXMLObject): u = urlparse(g.authorizenetapi) try: conn = HTTPSConnection(u.hostname, u.port) - conn.request("POST", u.path, self.toXML(), + conn.request("POST", u.path, self.toXML().encode('utf-8'), {"Content-type": "text/xml"}) res = conn.getresponse() res = self.handle_response(res.read()) @@ -237,7 +246,9 @@ class AuthorizeNetRequest(SimpleXMLObject): def handle_response(self, res): res = self._autoclose_re.sub(self._autoclose_handler, res) - res = BeautifulStoneSoup(res, markupMassage=False) + res = BeautifulStoneSoup(res, + markupMassage=False, + convertEntities=BeautifulStoneSoup.XML_ENTITIES) if res.resultcode.contents[0] == u"Ok": return self.process_response(res) else: